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