CS318 - Pintos
Pintos source browser for JHU CS318 course
intq.c
Go to the documentation of this file.
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 {
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 {
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. */
37 uint8_t
38 intq_getc (struct intq *q)
39 {
40  uint8_t byte;
41 
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. */
60 void
61 intq_putc (struct intq *q, uint8_t byte)
62 {
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. */
78 static int
79 next (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. */
86 static void
87 wait (struct intq *q UNUSED, struct thread **waiter)
88 {
89  ASSERT (!intr_context ());
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. */
102 static void
103 signal (struct intq *q UNUSED, struct thread **waiter)
104 {
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 }
uint8_t
unsigned char uint8_t
Definition: stdint.h:20
lock_release
void lock_release(struct lock *lock)
Releases LOCK, which must be owned by the current thread.
Definition: synch.c:229
intr_context
bool intr_context(void)
Returns true during processing of an external interrupt and false at all other times.
Definition: interrupt.c:212
NULL
#define NULL
Definition: stddef.h:4
signal
static void signal(struct intq *q, struct thread **waiter)
intq_empty
bool intq_empty(const struct intq *q)
Returns true if Q is empty, false otherwise.
Definition: intq.c:20
lock_init
void lock_init(struct lock *lock)
Initializes LOCK.
Definition: synch.c:176
UNUSED
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
thread
A kernel thread or user process.
Definition: thread.h:83
intq_init
void intq_init(struct intq *q)
Initializes interrupt queue Q.
Definition: intq.c:11
intq::buf
uint8_t buf[INTQ_BUFSIZE]
Buffer.
Definition: intq.h:32
intq_getc
uint8_t intq_getc(struct intq *q)
Removes a byte from Q and returns it.
Definition: intq.c:38
intq.h
thread_current
struct thread * thread_current(void)
Returns the running thread.
Definition: thread.c:256
thread_block
void thread_block(void)
Puts the current thread to sleep.
Definition: thread.c:214
next
static int next(int pos)
Returns the position after POS within an intq.
Definition: intq.c:79
intr_get_level
enum intr_level intr_get_level(void)
Returns the current interrupt status.
Definition: interrupt.c:65
INTQ_BUFSIZE
#define INTQ_BUFSIZE
An "interrupt queue", a circular buffer shared between kernel threads and external interrupt handlers...
Definition: intq.h:21
intq_putc
void intq_putc(struct intq *q, uint8_t byte)
Adds BYTE to the end of Q.
Definition: intq.c:61
intq_full
bool intq_full(const struct intq *q)
Returns true if Q is full, false otherwise.
Definition: intq.c:28
intq::head
int head
New data is written here.
Definition: intq.h:33
ASSERT
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
intq::not_empty
struct thread * not_empty
Thread waiting for not-empty condition.
Definition: intq.h:29
intq::lock
struct lock lock
Only one thread may wait at once.
Definition: intq.h:27
intq::tail
int tail
Old data is read here.
Definition: intq.h:34
intq
A circular queue of bytes.
Definition: intq.h:24
wait
static void wait(struct intq *q, struct thread **waiter)
INTR_OFF
Interrupts disabled.
Definition: interrupt.h:10
thread_unblock
void thread_unblock(struct thread *t)
Transitions a blocked thread T to the ready-to-run state.
Definition: thread.c:232
intq::not_full
struct thread * not_full
Thread waiting for not-full condition.
Definition: intq.h:28
lock_acquire
void lock_acquire(struct lock *lock)
Acquires LOCK, sleeping until it becomes available if necessary.
Definition: synch.c:193
thread.h
debug.h