diff options
| author | manuel <manuel@mausz.at> | 2012-03-26 22:05:09 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2012-03-26 22:05:09 +0200 |
| commit | 1a39d0619947a0a3cda8322e5856975ba46c602d (patch) | |
| tree | 411c8ee27fd75756dd73e52ff1c622dd2c5c9356 /pintos-progos/devices/timer.c | |
| parent | 11c1519a12cdae1ce05d31a6e389a103259c6c93 (diff) | |
| download | progos-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.c | 40 |
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); | |||
| 30 | static void real_time_sleep (int64_t num, int32_t denom); | 30 | static void real_time_sleep (int64_t num, int32_t denom); |
| 31 | static void real_time_delay (int64_t num, int32_t denom); | 31 | static 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 */ |
| 35 | static struct list alarm_list; | 35 | static 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. */ |
| 39 | void | 39 | void |
| 40 | timer_init (void) | 40 | timer_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. */ | ||
| 93 | static bool | ||
| 94 | wakeup_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. */ |
| 94 | void | 104 | void |
| @@ -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 | ||
