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 | |
| 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
| -rw-r--r-- | pintos-progos/devices/timer.c | 40 | ||||
| -rw-r--r-- | pintos-progos/threads/thread.h | 10 | ||||
| -rw-r--r-- | proj0.txt | 11 |
3 files changed, 40 insertions, 21 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 | ||
diff --git a/pintos-progos/threads/thread.h b/pintos-progos/threads/thread.h index 9cc5ef7..4ba5ef2 100644 --- a/pintos-progos/threads/thread.h +++ b/pintos-progos/threads/thread.h | |||
| @@ -77,12 +77,12 @@ typedef int tid_t; | |||
| 77 | value, triggering the assertion. */ | 77 | value, triggering the assertion. */ |
| 78 | /* The `elem' member has a dual purpose. It can be an element in | 78 | /* The `elem' member has a dual purpose. It can be an element in |
| 79 | the run queue (thread.c), it can be an element in a semaphore | 79 | the run queue (thread.c), it can be an element in a semaphore |
| 80 | wait list (synch.c), or it can be an element in the alarm sleep | 80 | wait list (synch.c), or it can be an element in the timer/alarm sleep |
| 81 | list (timer.c). It can be used these two ways only because they | 81 | list (timer.c). It can be used these three ways only because they |
| 82 | are mutually exclusive: only a thread in the ready state is on | 82 | are mutually exclusive: only a thread in the ready state is on |
| 83 | the run queue, only a thread in the blocked state is on a semaphore | 83 | the run queue, only a thread in the blocked state is on a semaphore |
| 84 | wait list, whereas only a thread waiting for an alarm event is on | 84 | wait list, whereas only a thread waiting for an timer/alarm event is on |
| 85 | the alarm sleep list. */ | 85 | the timer/alarm sleep list. */ |
| 86 | struct thread | 86 | struct thread |
| 87 | { | 87 | { |
| 88 | /* Owned by thread.c. */ | 88 | /* Owned by thread.c. */ |
| @@ -106,7 +106,7 @@ struct thread | |||
| 106 | /* Owned by thread.c. */ | 106 | /* Owned by thread.c. */ |
| 107 | unsigned magic; /* Detects stack overflow. */ | 107 | unsigned magic; /* Detects stack overflow. */ |
| 108 | 108 | ||
| 109 | int64_t alarm_tick; /* absolute tick when to trigger an alarm event */ | 109 | int64_t wakeup_tick; /* absolute tick when to wake up the thread */ |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | /* If false (default), use round-robin scheduler. | 112 | /* If false (default), use round-robin scheduler. |
| @@ -32,19 +32,24 @@ TODO | |||
| 32 | >> enumeration. Identify the purpose of each in 25 words or less. | 32 | >> enumeration. Identify the purpose of each in 25 words or less. |
| 33 | 33 | ||
| 34 | struct thread: | 34 | struct thread: |
| 35 | int64_t alarm_tick ...absolute tick when to trigger an alarm event | 35 | int64_t wakeup_tick ...absolute tick when to wake up the thread |
| 36 | 36 | ||
| 37 | ---- ALGORITHMS ---- | 37 | ---- ALGORITHMS ---- |
| 38 | 38 | ||
| 39 | >> A2: Briefly describe what happens in a call to timer_sleep(), | 39 | >> A2: Briefly describe what happens in a call to timer_sleep(), |
| 40 | >> including the effects of the timer interrupt handler. | 40 | >> including the effects of the timer interrupt handler. |
| 41 | 41 | ||
| 42 | TODO | 42 | In case of a positive tick value we calculate the tick when to awake the |
| 43 | current thread and store that inside the per thread structure. Afterwards | ||
| 44 | we disable interrupts and insert the thread into our wakup list which is | ||
| 45 | sorted by wakeup-tick in ascending order. Finally we block the thread | ||
| 46 | and restore the interrupt value. | ||
| 43 | 47 | ||
| 44 | >> A3: What steps are taken to minimize the amount of time spent in | 48 | >> A3: What steps are taken to minimize the amount of time spent in |
| 45 | >> the timer interrupt handler? | 49 | >> the timer interrupt handler? |
| 46 | 50 | ||
| 47 | TODO | 51 | We sort our alarm/wake-up list by wakeup-tick value in ascending order. |
| 52 | Thus we can return as soon as the first thread doesn't need to get unblocked. | ||
| 48 | 53 | ||
| 49 | ---- SYNCHRONIZATION ---- | 54 | ---- SYNCHRONIZATION ---- |
| 50 | 55 | ||
