summaryrefslogtreecommitdiffstats
path: root/pintos-progos/devices/intq.c
diff options
context:
space:
mode:
Diffstat (limited to 'pintos-progos/devices/intq.c')
-rw-r--r--pintos-progos/devices/intq.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/pintos-progos/devices/intq.c b/pintos-progos/devices/intq.c
new file mode 100644
index 0000000..40b23ae
--- /dev/null
+++ b/pintos-progos/devices/intq.c
@@ -0,0 +1,114 @@
1#include "devices/intq.h"
2#include <debug.h>
3#include "threads/thread.h"
4
5static int next (int pos);
6static void wait (struct intq *q, struct thread **waiter);
7static void signal (struct intq *q, struct thread **waiter);
8
9/* Initializes interrupt queue Q. */
10void
11intq_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. */
19bool
20intq_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. */
27bool
28intq_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 If Q is empty, sleeps until a byte is added.
36 When called from an interrupt handler, Q must not be empty. */
37uint8_t
38intq_getc (struct intq *q)
39{
40 uint8_t byte;
41
42 ASSERT (intr_get_level () == INTR_OFF);
43 while (intq_empty (q))
44 {
45 ASSERT (!intr_context ());
46 lock_acquire (&q->lock);
47 wait (q, &q->not_empty);
48 lock_release (&q->lock);
49 }
50
51 byte = q->buf[q->tail];
52 q->tail = next (q->tail);
53 signal (q, &q->not_full);
54 return byte;
55}
56
57/* Adds BYTE to the end of Q.
58 If Q is full, sleeps until a byte is removed.
59 When called from an interrupt handler, Q must not be full. */
60void
61intq_putc (struct intq *q, uint8_t byte)
62{
63 ASSERT (intr_get_level () == INTR_OFF);
64 while (intq_full (q))
65 {
66 ASSERT (!intr_context ());
67 lock_acquire (&q->lock);
68 wait (q, &q->not_full);
69 lock_release (&q->lock);
70 }
71
72 q->buf[q->head] = byte;
73 q->head = next (q->head);
74 signal (q, &q->not_empty);
75}
76
77/* Returns the position after POS within an intq. */
78static int
79next (int pos)
80{
81 return (pos + 1) % INTQ_BUFSIZE;
82}
83
84/* WAITER must be the address of Q's not_empty or not_full
85 member. Waits until the given condition is true. */
86static void
87wait (struct intq *q UNUSED, struct thread **waiter)
88{
89 ASSERT (!intr_context ());
90 ASSERT (intr_get_level () == INTR_OFF);
91 ASSERT ((waiter == &q->not_empty && intq_empty (q))
92 || (waiter == &q->not_full && intq_full (q)));
93
94 *waiter = thread_current ();
95 thread_block ();
96}
97
98/* WAITER must be the address of Q's not_empty or not_full
99 member, and the associated condition must be true. If a
100 thread is waiting for the condition, wakes it up and resets
101 the waiting thread. */
102static void
103signal (struct intq *q UNUSED, struct thread **waiter)
104{
105 ASSERT (intr_get_level () == INTR_OFF);
106 ASSERT ((waiter == &q->not_empty && !intq_empty (q))
107 || (waiter == &q->not_full && !intq_full (q)));
108
109 if (*waiter != NULL)
110 {
111 thread_unblock (*waiter);
112 *waiter = NULL;
113 }
114}