Really make it safe to call printf() from any context.
[pintos-anon] / src / devices / intq.c
1 #include "devices/intq.h"
2 #include <debug.h>
3 #include "threads/thread.h"
4
5 static int next (int pos);
6 static void wait (struct intq *q, struct thread **waiter);
7 static void signal (struct intq *q, struct thread **waiter);
8
9 /* Initializes interrupt queue Q, naming it NAME (for debugging
10    purposes). */
11 void
12 intq_init (struct intq *q, const char *name) 
13 {
14   lock_init (&q->lock, name);
15   q->not_full = q->not_empty = NULL;
16   q->head = q->tail = 0;
17 }
18
19 /* Returns true if Q is empty, false otherwise. */
20 bool
21 intq_empty (const struct intq *q) 
22 {
23   ASSERT (intr_get_level () == INTR_OFF);
24   return q->head == q->tail;
25 }
26
27 /* Returns true if Q is full, false otherwise. */
28 bool
29 intq_full (const struct intq *q) 
30 {
31   ASSERT (intr_get_level () == INTR_OFF);
32   return next (q->head) == q->tail;
33 }
34
35 /* Removes a byte from Q and returns it.
36    Q must not be empty if called from an interrupt handler.
37    Otherwise, if Q is empty, first sleeps until a byte is
38    added. */
39 uint8_t
40 intq_getc (struct intq *q) 
41 {
42   uint8_t byte;
43   
44   ASSERT (intr_get_level () == INTR_OFF);
45   while (intq_empty (q)) 
46     {
47       ASSERT (!intr_context ());
48       lock_acquire (&q->lock);
49       wait (q, &q->not_empty);
50       lock_release (&q->lock);
51     }
52   
53   byte = q->buf[q->tail];
54   q->tail = next (q->tail);
55   signal (q, &q->not_full);
56   return byte;
57 }
58
59 /* Adds BYTE to the end of Q.
60    Q must not be full if called from an interrupt handler.
61    Otherwise, if Q is full, first sleeps until a byte is
62    removed. */
63 void
64 intq_putc (struct intq *q, uint8_t byte) 
65 {
66   ASSERT (intr_get_level () == INTR_OFF);
67   while (intq_full (q))
68     {
69       ASSERT (!intr_context ());
70       lock_acquire (&q->lock);
71       wait (q, &q->not_full);
72       lock_release (&q->lock);
73     }
74
75   q->buf[q->head] = byte;
76   q->head = next (q->head);
77   signal (q, &q->not_empty);
78 }
79 \f
80 /* Returns the position after POS within an intq. */
81 static int
82 next (int pos) 
83 {
84   return (pos + 1) % INTQ_BUFSIZE;
85 }
86
87 /* WAITER must be the address of Q's not_empty or not_full
88    member.  Waits until the given condition is true. */
89 static void
90 wait (struct intq *q, struct thread **waiter) 
91 {
92   ASSERT (!intr_context ());
93   ASSERT (intr_get_level () == INTR_OFF);
94   ASSERT ((waiter == &q->not_empty && intq_empty (q))
95           || (waiter == &q->not_full && intq_full (q)));
96
97   *waiter = thread_current ();
98   thread_block ();
99 }
100
101 /* WAITER must be the address of Q's not_empty or not_full
102    member, and the associated condition must be true.  If a
103    thread is waiting for the condition, wakes it up and resets
104    the waiting thread. */
105 static void
106 signal (struct intq *q, struct thread **waiter) 
107 {
108   ASSERT (intr_get_level () == INTR_OFF);
109   ASSERT ((waiter == &q->not_empty && !intq_empty (q))
110           || (waiter == &q->not_full && !intq_full (q)));
111
112   if (*waiter != NULL) 
113     {
114       thread_unblock (*waiter);
115       *waiter = NULL;
116     }
117 }