diff options
Diffstat (limited to 'src/devices/timer.c')
| -rw-r--r-- | src/devices/timer.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/src/devices/timer.c b/src/devices/timer.c index a4521de..aea6aa2 100644 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -1,6 +1,7 @@ #include "devices/timer.h" #include <debug.h> #include <inttypes.h> +#include <list.h> #include <round.h> #include <stdio.h> #include "threads/interrupt.h" @@ -17,6 +18,13 @@ #error TIMER_FREQ <= 1000 recommended #endif +struct waiting_thread + { + struct list_elem elem; + struct semaphore sema; + int64_t tick_target; + }; + /* Number of timer ticks since OS booted. */ static int64_t ticks; @@ -24,6 +32,8 @@ static int64_t ticks; Initialized by timer_calibrate(). */ static unsigned loops_per_tick; +static struct list waiting_threads; + static intr_handler_func timer_interrupt; static bool too_many_loops (unsigned loops); static void busy_wait (int64_t loops); @@ -43,6 +53,8 @@ timer_init (void) outb (0x40, count & 0xff); outb (0x40, count >> 8); + list_init (&waiting_threads); + intr_register_ext (0x20, timer_interrupt, "8254 Timer"); } @@ -98,9 +110,27 @@ timer_sleep (int64_t ticks) { int64_t start = timer_ticks (); - ASSERT (intr_get_level () == INTR_ON); - while (timer_elapsed (start) < ticks) - thread_yield (); + struct waiting_thread new_waiting_thread; + new_waiting_thread.tick_target = start + ticks; + sema_init (&new_waiting_thread.sema, 0); + + // disable interrupts so the timer interrupt handler can't modify the list + enum intr_level old_level = intr_disable (); + + struct list_elem *before = list_begin (&waiting_threads); + while (before != list_end (&waiting_threads)) { + struct list_elem *next = list_next (before); + struct waiting_thread *waiting_thread = list_entry (before, struct waiting_thread, elem); + if (new_waiting_thread.tick_target < waiting_thread->tick_target) { + break; + } + before = next; + } + list_insert (before, &new_waiting_thread.elem); + + intr_set_level (old_level); + + sema_down (&new_waiting_thread.sema); } /* Suspends execution for approximately MS milliseconds. */ @@ -137,6 +167,19 @@ timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); + + struct list_elem *e = list_begin (&waiting_threads); + while (e != list_end (&waiting_threads)) { + struct list_elem *next = list_next (e); + struct waiting_thread *waiting_thread = list_entry (e, struct waiting_thread, elem); + if (ticks >= waiting_thread->tick_target) { + sema_up (&waiting_thread->sema); + list_remove (e); + e = next; + } else { + break; + } + } } /* Returns true if LOOPS iterations waits for more than one timer |
