From 11c1519a12cdae1ce05d31a6e389a103259c6c93 Mon Sep 17 00:00:00 2001 From: manuel Date: Mon, 26 Mar 2012 20:18:23 +0200 Subject: first timer alarm implementation --- pintos-progos/devices/timer.c | 45 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'pintos-progos/devices/timer.c') diff --git a/pintos-progos/devices/timer.c b/pintos-progos/devices/timer.c index befaaae..bf78351 100644 --- a/pintos-progos/devices/timer.c +++ b/pintos-progos/devices/timer.c @@ -30,11 +30,16 @@ static void busy_wait (int64_t loops); static void real_time_sleep (int64_t num, int32_t denom); static void real_time_delay (int64_t num, int32_t denom); +/* list of processes waiting for an alarm event + * and currently put to sleep */ +static struct list alarm_list; + /* Sets up the timer to interrupt TIMER_FREQ times per second, and registers the corresponding interrupt. */ void timer_init (void) { + list_init (&alarm_list); pit_configure_channel (0, 2, TIMER_FREQ); intr_register_ext (0x20, timer_interrupt, "8254 Timer"); } @@ -89,11 +94,26 @@ timer_elapsed (int64_t then) void timer_sleep (int64_t ticks) { - int64_t start = timer_ticks (); + struct thread *t = thread_current (); + enum intr_level old_level; - ASSERT (intr_get_level () == INTR_ON); - while (timer_elapsed (start) < ticks) - thread_yield (); + /* nothing to sleep here */ + if (ticks <= 0) + return; + + t->alarm_tick = timer_ticks () + ticks; + + /* add thread to alarm list + * disable interrupts as this is critical */ + old_level = intr_disable (); + ASSERT (t->status == THREAD_RUNNING); + list_push_back (&alarm_list, &t->elem); + + /* block the thread */ + thread_block(); + + /* restore interrupt */ + intr_set_level (old_level); } /* Sleeps for approximately MS milliseconds. Interrupts must be @@ -170,8 +190,25 @@ timer_print_stats (void) static void timer_interrupt (struct intr_frame *args UNUSED) { + struct list_elem *el, *next; + ticks++; thread_tick (); + + /* check for threads waiting for an alarm event */ + for (el = list_begin (&alarm_list); el != list_end (&alarm_list); el = next) + { + struct thread *t = list_entry (el, struct thread, elem); + if (t->alarm_tick == timer_ticks ()) + { + next = list_remove (el); + /* unblock must be called AFTER removing, + * as thread_unblock() will reuse thread.elem */ + thread_unblock (t); + } + else + next = list_next (el); + } } /* Returns true if LOOPS iterations waits for more than one timer -- cgit v1.2.3