This repository has been archived on 2021-05-26. You can view files and clone it, but cannot push or open issues or pull requests.
OS/pintos-env/pintos/devices/intq.c

115 lines
2.7 KiB
C
Raw Normal View History

#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.
If Q is empty, sleeps until a byte is added.
When called from an interrupt handler, Q must not be empty. */
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.
If Q is full, sleeps until a byte is removed.
When called from an interrupt handler, Q must not be full. */
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;
}
}