1 #include "devices/intq.h"
3 #include "threads/thread.h"
5 static int next (int pos);
6 static bool owned_by_current_thread (const struct intq *);
7 static void wait (struct intq *q, struct thread **waiter);
8 static void signal (struct intq *q, struct thread **waiter);
10 /* Initializes interrupt queue Q, naming it NAME (for debugging
13 intq_init (struct intq *q, const char *name)
15 lock_init (&q->lock, name);
16 q->not_full = q->not_empty = NULL;
17 q->head = q->tail = 0;
20 /* Locks out other threads from Q (with Q's lock) and interrupt
21 handlers (by disabling interrupts). */
23 intq_lock (struct intq *q)
25 ASSERT (!intr_context ());
26 ASSERT (!owned_by_current_thread (q));
28 lock_acquire (&q->lock);
29 q->old_level = intr_disable ();
34 intq_unlock (struct intq *q)
36 ASSERT (!intr_context ());
37 ASSERT (owned_by_current_thread (q));
39 lock_release (&q->lock);
40 intr_set_level (q->old_level);
43 /* Returns true if Q is empty, false otherwise. */
45 intq_empty (const struct intq *q)
47 ASSERT (intr_get_level () == INTR_OFF);
48 return q->head == q->tail;
51 /* Returns true if Q is full, false otherwise. */
53 intq_full (const struct intq *q)
55 ASSERT (intr_get_level () == INTR_OFF);
56 return next (q->head) == q->tail;
59 /* Removes a byte from Q and returns it.
60 Q must not be empty if called from an interrupt handler.
61 Otherwise, if Q is empty, first waits until a byte is added.
62 Either Q must be locked or we must be in an interrupt
65 intq_getc (struct intq *q)
69 ASSERT (owned_by_current_thread (q));
70 while (intq_empty (q))
71 wait (q, &q->not_empty);
73 byte = q->buf[q->tail];
74 q->tail = next (q->tail);
75 signal (q, &q->not_full);
79 /* Adds BYTE to the end of Q.
80 Q must not be full if called from an interrupt handler.
81 Otherwise, if Q is full, first waits until a byte is removed.
82 Either Q must be locked or we must be in an interrupt
85 intq_putc (struct intq *q, uint8_t byte)
87 ASSERT (owned_by_current_thread (q));
89 wait (q, &q->not_full);
91 q->buf[q->head] = byte;
92 q->head = next (q->head);
93 signal (q, &q->not_empty);
96 /* Returns the position after POS within an intq. */
100 return (pos + 1) % INTQ_BUFSIZE;
103 /* Returns true if Q is "owned by" the current thread; that is,
104 if Q is locked by the current thread or if we're in an
105 external interrupt handler. */
107 owned_by_current_thread (const struct intq *q)
109 return (intr_context ()
110 || (lock_held_by_current_thread (&q->lock)
111 && intr_get_level () == INTR_OFF));
114 /* WAITER must be the address of Q's not_empty or not_full
115 member. Waits until the given condition is true. */
117 wait (struct intq *q, struct thread **waiter)
119 ASSERT (!intr_context ());
120 ASSERT (owned_by_current_thread (q));
121 ASSERT ((waiter == &q->not_empty && intq_empty (q))
122 || (waiter == &q->not_full && intq_full (q)));
124 *waiter = thread_current ();
128 /* WAITER must be the address of Q's not_empty or not_full
129 member, and the associated condition must be true. If a
130 thread is waiting for the condition, wakes it up and resets
131 the waiting thread. */
133 signal (struct intq *q, struct thread **waiter)
135 ASSERT (owned_by_current_thread (q));
136 ASSERT ((waiter == &q->not_empty && !intq_empty (q))
137 || (waiter == &q->not_full && !intq_full (q)));
141 thread_unblock (*waiter);