aboutsummaryrefslogtreecommitdiffstats
path: root/src/devices/intq.c
diff options
context:
space:
mode:
authorklaar36 <klas.arvidsson@liu.se>2015-03-20 17:30:24 +0100
committerklaar36 <klas.arvidsson@liu.se>2015-03-20 17:30:24 +0100
commite7bc50ca8ffcaa6ed68ebd2315f78b0f5a7d10ad (patch)
tree4de97af7207676b69cb6a9aba8cb443cc134855d /src/devices/intq.c
parentb0418a24e709f0632d2ede5b0f327c422931939b (diff)
downloadpintos-rs-e7bc50ca8ffcaa6ed68ebd2315f78b0f5a7d10ad.tar.gz
Initial Pintos
Diffstat (limited to 'src/devices/intq.c')
-rw-r--r--src/devices/intq.c116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/devices/intq.c b/src/devices/intq.c
new file mode 100644
index 0000000..028dca4
--- /dev/null
+++ b/src/devices/intq.c
@@ -0,0 +1,116 @@
+#include "devices/intq.h"
+#include <debug.h>
+#include "threads/thread.h"
+
+static int next (int pos);
+static void wait (struct intq *q, struct thread **waiter);
+static void signal (struct intq *q, struct thread **waiter);
+
+/* Initializes interrupt queue Q. */
+void
+intq_init (struct intq *q)
+{
+ lock_init (&q->lock);
+ q->not_full = q->not_empty = NULL;
+ q->head = q->tail = 0;
+}
+
+/* Returns true if Q is empty, false otherwise. */
+bool
+intq_empty (const struct intq *q)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ return q->head == q->tail;
+}
+
+/* Returns true if Q is full, false otherwise. */
+bool
+intq_full (const struct intq *q)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ return next (q->head) == q->tail;
+}
+
+/* Removes a byte from Q and returns it.
+ Q must not be empty if called from an interrupt handler.
+ Otherwise, if Q is empty, first sleeps until a byte is
+ added. */
+uint8_t
+intq_getc (struct intq *q)
+{
+ uint8_t byte;
+
+ ASSERT (intr_get_level () == INTR_OFF);
+ while (intq_empty (q))
+ {
+ ASSERT (!intr_context ());
+ lock_acquire (&q->lock);
+ wait (q, &q->not_empty);
+ lock_release (&q->lock);
+ }
+
+ byte = q->buf[q->tail];
+ q->tail = next (q->tail);
+ signal (q, &q->not_full);
+ return byte;
+}
+
+/* Adds BYTE to the end of Q.
+ Q must not be full if called from an interrupt handler.
+ Otherwise, if Q is full, first sleeps until a byte is
+ removed. */
+void
+intq_putc (struct intq *q, uint8_t byte)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ while (intq_full (q))
+ {
+ ASSERT (!intr_context ());
+ lock_acquire (&q->lock);
+ wait (q, &q->not_full);
+ lock_release (&q->lock);
+ }
+
+ q->buf[q->head] = byte;
+ q->head = next (q->head);
+ signal (q, &q->not_empty);
+}
+
+/* Returns the position after POS within an intq. */
+static int
+next (int pos)
+{
+ return (pos + 1) % INTQ_BUFSIZE;
+}
+
+/* WAITER must be the address of Q's not_empty or not_full
+ member. Waits until the given condition is true. */
+static void
+wait (struct intq *q UNUSED, struct thread **waiter)
+{
+ ASSERT (!intr_context ());
+ ASSERT (intr_get_level () == INTR_OFF);
+ ASSERT ((waiter == &q->not_empty && intq_empty (q))
+ || (waiter == &q->not_full && intq_full (q)));
+
+ *waiter = thread_current ();
+ thread_block ();
+}
+
+/* WAITER must be the address of Q's not_empty or not_full
+ member, and the associated condition must be true. If a
+ thread is waiting for the condition, wakes it up and resets
+ the waiting thread. */
+static void
+signal (struct intq *q UNUSED, struct thread **waiter)
+{
+ ASSERT (intr_get_level () == INTR_OFF);
+ ASSERT ((waiter == &q->not_empty && !intq_empty (q))
+ || (waiter == &q->not_full && !intq_full (q)));
+
+ if (*waiter != NULL)
+ {
+ thread_unblock (*waiter);
+ *waiter = NULL;
+ }
+}