00001 #include "devices/intq.h" 00002 //3111214039 00003 #include <debug.h> 00004 #include "threads/thread.h" 00005 00006 static int next (int pos); 00007 static void wait (struct intq *q, struct thread **waiter); 00008 static void signal (struct intq *q, struct thread **waiter); 00009 00010 /* Initializes interrupt queue Q. */ 00011 void 00012 intq_init (struct intq *q) 00013 { 00014 lock_init (&q->lock); 00015 q->not_full = q->not_empty = NULL; 00016 q->head = q->tail = 0; 00017 } 00018 00019 /* Returns true if Q is empty, false otherwise. */ 00020 bool 00021 intq_empty (const struct intq *q) 00022 { 00023 ASSERT (intr_get_level () == INTR_OFF); 00024 return q->head == q->tail; 00025 } 00026 00027 /* Returns true if Q is full, false otherwise. */ 00028 bool 00029 intq_full (const struct intq *q) 00030 { 00031 ASSERT (intr_get_level () == INTR_OFF); 00032 return next (q->head) == q->tail; 00033 } 00034 00035 /* Removes a byte from Q and returns it. 00036 If Q is empty, sleeps until a byte is added. 00037 When called from an interrupt handler, Q must not be empty. */ 00038 uint8_t 00039 intq_getc (struct intq *q) 00040 { 00041 uint8_t byte; 00042 00043 ASSERT (intr_get_level () == INTR_OFF); 00044 while (intq_empty (q)) 00045 { 00046 ASSERT (!intr_context ()); 00047 lock_acquire (&q->lock); 00048 wait (q, &q->not_empty); 00049 lock_release (&q->lock); 00050 } 00051 00052 byte = q->buf[q->tail]; 00053 q->tail = next (q->tail); 00054 signal (q, &q->not_full); 00055 return byte; 00056 } 00057 00058 /* Adds BYTE to the end of Q. 00059 If Q is full, sleeps until a byte is removed. 00060 When called from an interrupt handler, Q must not be full. */ 00061 void 00062 intq_putc (struct intq *q, uint8_t byte) 00063 { 00064 ASSERT (intr_get_level () == INTR_OFF); 00065 while (intq_full (q)) 00066 { 00067 ASSERT (!intr_context ()); 00068 lock_acquire (&q->lock); 00069 wait (q, &q->not_full); 00070 lock_release (&q->lock); 00071 } 00072 00073 q->buf[q->head] = byte; 00074 q->head = next (q->head); 00075 signal (q, &q->not_empty); 00076 } 00077 00078 /* Returns the position after POS within an intq. */ 00079 static int 00080 next (int pos) 00081 { 00082 return (pos + 1) % INTQ_BUFSIZE; 00083 } 00084 00085 /* WAITER must be the address of Q's not_empty or not_full 00086 member. Waits until the given condition is true. */ 00087 static void 00088 wait (struct intq *q UNUSED, struct thread **waiter) 00089 { 00090 ASSERT (!intr_context ()); 00091 ASSERT (intr_get_level () == INTR_OFF); 00092 ASSERT ((waiter == &q->not_empty && intq_empty (q)) 00093 || (waiter == &q->not_full && intq_full (q))); 00094 00095 *waiter = thread_current (); 00096 thread_block (); 00097 } 00098 00099 /* WAITER must be the address of Q's not_empty or not_full 00100 member, and the associated condition must be true. If a 00101 thread is waiting for the condition, wakes it up and resets 00102 the waiting thread. */ 00103 static void 00104 signal (struct intq *q UNUSED, struct thread **waiter) 00105 { 00106 ASSERT (intr_get_level () == INTR_OFF); 00107 ASSERT ((waiter == &q->not_empty && !intq_empty (q)) 00108 || (waiter == &q->not_full && !intq_full (q))); 00109 00110 if (*waiter != NULL) 00111 { 00112 thread_unblock (*waiter); 00113 *waiter = NULL; 00114 } 00115 }