summaryrefslogtreecommitdiffstats
path: root/pintos-progos/devices/timer.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-03-26 22:05:09 +0200
committermanuel <manuel@mausz.at>2012-03-26 22:05:09 +0200
commit1a39d0619947a0a3cda8322e5856975ba46c602d (patch)
tree411c8ee27fd75756dd73e52ff1c622dd2c5c9356 /pintos-progos/devices/timer.c
parent11c1519a12cdae1ce05d31a6e389a103259c6c93 (diff)
downloadprogos-1a39d0619947a0a3cda8322e5856975ba46c602d.tar.gz
progos-1a39d0619947a0a3cda8322e5856975ba46c602d.tar.bz2
progos-1a39d0619947a0a3cda8322e5856975ba46c602d.zip
- rename alarm list/tick to wakeup list/tick
- order wakeup list by wakeup tick in ascending order which allows to bail out early inside timer_interrupt
Diffstat (limited to 'pintos-progos/devices/timer.c')
-rw-r--r--pintos-progos/devices/timer.c40
1 files changed, 27 insertions, 13 deletions
diff --git a/pintos-progos/devices/timer.c b/pintos-progos/devices/timer.c
index bf78351..3533fe7 100644
--- a/pintos-progos/devices/timer.c
+++ b/pintos-progos/devices/timer.c
@@ -30,16 +30,16 @@ static void busy_wait (int64_t loops);
30static void real_time_sleep (int64_t num, int32_t denom); 30static void real_time_sleep (int64_t num, int32_t denom);
31static void real_time_delay (int64_t num, int32_t denom); 31static void real_time_delay (int64_t num, int32_t denom);
32 32
33/* list of processes waiting for an alarm event 33/* list of processes waiting for an wakeup event
34 * and currently put to sleep */ 34 * and currently put to sleep */
35static struct list alarm_list; 35static struct list wakeup_list;
36 36
37/* Sets up the timer to interrupt TIMER_FREQ times per second, 37/* Sets up the timer to interrupt TIMER_FREQ times per second,
38 and registers the corresponding interrupt. */ 38 and registers the corresponding interrupt. */
39void 39void
40timer_init (void) 40timer_init (void)
41{ 41{
42 list_init (&alarm_list); 42 list_init (&wakeup_list);
43 pit_configure_channel (0, 2, TIMER_FREQ); 43 pit_configure_channel (0, 2, TIMER_FREQ);
44 intr_register_ext (0x20, timer_interrupt, "8254 Timer"); 44 intr_register_ext (0x20, timer_interrupt, "8254 Timer");
45} 45}
@@ -89,6 +89,16 @@ timer_elapsed (int64_t then)
89 return timer_ticks () - then; 89 return timer_ticks () - then;
90} 90}
91 91
92/* Comparison function for our ascending ordered wakeup list. */
93static bool
94wakeup_list_cmp_less(const struct list_elem *a, const struct list_elem *b,
95 void *AUX UNUSED)
96{
97 struct thread *t1 = list_entry (a, struct thread, elem);
98 struct thread *t2 = list_entry (b, struct thread, elem);
99 return (t1->wakeup_tick < t2->wakeup_tick);
100}
101
92/* Sleeps for approximately TICKS timer ticks. Interrupts must 102/* Sleeps for approximately TICKS timer ticks. Interrupts must
93 be turned on. */ 103 be turned on. */
94void 104void
@@ -97,20 +107,22 @@ timer_sleep (int64_t ticks)
97 struct thread *t = thread_current (); 107 struct thread *t = thread_current ();
98 enum intr_level old_level; 108 enum intr_level old_level;
99 109
110 ASSERT (intr_get_level () == INTR_ON);
111
100 /* nothing to sleep here */ 112 /* nothing to sleep here */
101 if (ticks <= 0) 113 if (ticks <= 0)
102 return; 114 return;
103 115
104 t->alarm_tick = timer_ticks () + ticks; 116 t->wakeup_tick = timer_ticks () + ticks;
105 117
106 /* add thread to alarm list 118 /* add thread to sorted wakeup list
107 * disable interrupts as this is critical */ 119 * disable interrupts as this is critical */
108 old_level = intr_disable (); 120 old_level = intr_disable ();
109 ASSERT (t->status == THREAD_RUNNING); 121 ASSERT (t->status == THREAD_RUNNING);
110 list_push_back (&alarm_list, &t->elem); 122 list_insert_ordered (&wakeup_list, &t->elem, &wakeup_list_cmp_less, NULL);
111 123
112 /* block the thread */ 124 /* block the thread */
113 thread_block(); 125 thread_block ();
114 126
115 /* restore interrupt */ 127 /* restore interrupt */
116 intr_set_level (old_level); 128 intr_set_level (old_level);
@@ -195,19 +207,21 @@ timer_interrupt (struct intr_frame *args UNUSED)
195 ticks++; 207 ticks++;
196 thread_tick (); 208 thread_tick ();
197 209
198 /* check for threads waiting for an alarm event */ 210 /* Check threads waiting to get woken up/unblocked.
199 for (el = list_begin (&alarm_list); el != list_end (&alarm_list); el = next) 211 * Since this is an ordered list we can bail out as soon
212 * as the first element doesn't need to get unblocked. */
213 for (el = list_begin (&wakeup_list); el != list_end (&wakeup_list); el = next)
200 { 214 {
201 struct thread *t = list_entry (el, struct thread, elem); 215 struct thread *t = list_entry (el, struct thread, elem);
202 if (t->alarm_tick == timer_ticks ()) 216 if (t->wakeup_tick == timer_ticks ())
203 { 217 {
204 next = list_remove (el); 218 next = list_remove (el);
205 /* unblock must be called AFTER removing, 219 /* unblock must be called AFTER removing,
206 * as thread_unblock() will reuse thread.elem */ 220 * as thread_unblock() will reuse t.elem */
207 thread_unblock (t); 221 thread_unblock (t);
222 continue;
208 } 223 }
209 else 224 break;
210 next = list_next (el);
211 } 225 }
212} 226}
213 227