/* An "interrupt queue", a circular buffer shared between
kernel threads and external interrupt handlers.
- A kernel thread that touches an interrupt queue must bracket
- its accesses with calls to intq_lock() and intq_unlock().
- These functions take a lock associated with the queue (which
- locks out other kernel threads) and disable interrupts (which
- locks out interrupt handlers).
-
- An external interrupt handler that touches an interrupt queue
- need not take any special precautions. Interrupts are
- disabled in an external interrupt handler, so other code will
- not interfere. The interrupt cannot occur during an update to
- the interrupt queue by a kernel thread because kernel threads
- disable interrupts while touching interrupt queues.
+ These functions can be called from kernel threads or from
+ external interrupt handlers. Except for intq_init(),
+ interrupts must be off in either case.
Incidentally, this has the structure of a "monitor". Normally
we'd use locks and condition variables from threads/synch.h to
- implement a monitor. Unfortunately, those are intended only
- to protect kernel threads from one another, not from interrupt
+ implement a monitor, but those are intended only to protect
+ kernel threads from one another, not from interrupt
handlers. */
/* Queue buffer size, in bytes. */
/* A circular queue of bytes. */
struct intq
{
- /* Mutual exclusion. */
- enum intr_level old_level; /* Excludes interrupt handlers. */
- struct lock lock; /* Excludes kernel threads. */
-
/* Waiting threads. */
+ struct lock lock; /* Only one thread may wait at once. */
struct thread *not_full; /* Thread waiting for not-full condition. */
struct thread *not_empty; /* Thread waiting for not-empty condition. */
int tail; /* Old data is read here. */
};
-void intq_init (struct intq *, const char *);
-void intq_lock (struct intq *);
-void intq_unlock (struct intq *);
+void intq_init (struct intq *);
bool intq_empty (const struct intq *);
bool intq_full (const struct intq *);
uint8_t intq_getc (struct intq *);