Implement non-busy timer_sleep (task 0)
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <round.h>
|
#include <round.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <list.h>
|
||||||
#include "devices/pit.h"
|
#include "devices/pit.h"
|
||||||
#include "threads/interrupt.h"
|
#include "threads/interrupt.h"
|
||||||
#include "threads/synch.h"
|
#include "threads/synch.h"
|
||||||
@@ -17,6 +18,15 @@
|
|||||||
#error TIMER_FREQ <= 1000 recommended
|
#error TIMER_FREQ <= 1000 recommended
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct asleep_thread
|
||||||
|
{
|
||||||
|
int64_t end_at; /* Number of timer ticks to stop sleeping at. */
|
||||||
|
struct semaphore semaphore; /* Semaphore used to block the thread. */
|
||||||
|
struct list_elem elem; /* List element. */
|
||||||
|
};
|
||||||
|
/* List of threads that are sleeping. */
|
||||||
|
static struct list sleeping_threads;
|
||||||
|
|
||||||
/* Number of timer ticks since OS booted. */
|
/* Number of timer ticks since OS booted. */
|
||||||
static int64_t ticks;
|
static int64_t ticks;
|
||||||
|
|
||||||
@@ -29,6 +39,9 @@ static bool too_many_loops (unsigned loops);
|
|||||||
static void busy_wait (int64_t loops);
|
static void busy_wait (int64_t loops);
|
||||||
static void real_time_sleep (int64_t num, int32_t denom);
|
static void real_time_sleep (int64_t num, int32_t denom);
|
||||||
static void real_time_delay (int64_t num, int32_t denom);
|
static void real_time_delay (int64_t num, int32_t denom);
|
||||||
|
static bool sleeping_threads_less (const struct list_elem *a,
|
||||||
|
const struct list_elem *b,
|
||||||
|
void *aux UNUSED);
|
||||||
|
|
||||||
/* Sets up the timer to interrupt TIMER_FREQ times per second,
|
/* Sets up the timer to interrupt TIMER_FREQ times per second,
|
||||||
and registers the corresponding interrupt. */
|
and registers the corresponding interrupt. */
|
||||||
@@ -36,6 +49,7 @@ void
|
|||||||
timer_init (void)
|
timer_init (void)
|
||||||
{
|
{
|
||||||
pit_configure_channel (0, 2, TIMER_FREQ);
|
pit_configure_channel (0, 2, TIMER_FREQ);
|
||||||
|
list_init (&sleeping_threads);
|
||||||
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
|
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +103,25 @@ timer_elapsed (int64_t then)
|
|||||||
void
|
void
|
||||||
timer_sleep (int64_t ticks)
|
timer_sleep (int64_t ticks)
|
||||||
{
|
{
|
||||||
|
enum intr_level old_level;
|
||||||
int64_t start = timer_ticks ();
|
int64_t start = timer_ticks ();
|
||||||
|
|
||||||
ASSERT (intr_get_level () == INTR_ON);
|
ASSERT (intr_get_level () == INTR_ON);
|
||||||
while (timer_elapsed (start) < ticks)
|
if (ticks < 0)
|
||||||
thread_yield ();
|
return;
|
||||||
|
|
||||||
|
struct asleep_thread st;
|
||||||
|
st.end_at = start + ticks;
|
||||||
|
sema_init (&st.semaphore, 0);
|
||||||
|
|
||||||
|
old_level = intr_disable ();
|
||||||
|
list_insert_ordered (&sleeping_threads, &st.elem, &sleeping_threads_less,
|
||||||
|
NULL);
|
||||||
|
intr_set_level (old_level);
|
||||||
|
sema_down (&st.semaphore);
|
||||||
|
old_level = intr_disable ();
|
||||||
|
list_remove (&st.elem);
|
||||||
|
intr_set_level (old_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sleeps for approximately MS milliseconds. Interrupts must be
|
/* Sleeps for approximately MS milliseconds. Interrupts must be
|
||||||
@@ -171,6 +199,15 @@ static void
|
|||||||
timer_interrupt (struct intr_frame *args UNUSED)
|
timer_interrupt (struct intr_frame *args UNUSED)
|
||||||
{
|
{
|
||||||
ticks++;
|
ticks++;
|
||||||
|
for (struct list_elem *e = list_begin (&sleeping_threads);
|
||||||
|
e != list_end (&sleeping_threads); e = list_next (e))
|
||||||
|
{
|
||||||
|
struct asleep_thread *st = list_entry (e, struct asleep_thread, elem);
|
||||||
|
if (ticks >= st->end_at)
|
||||||
|
sema_up (&st->semaphore);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
thread_tick ();
|
thread_tick ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,3 +281,13 @@ real_time_delay (int64_t num, int32_t denom)
|
|||||||
ASSERT (denom % 1000 == 0);
|
ASSERT (denom % 1000 == 0);
|
||||||
busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000));
|
busy_wait (loops_per_tick * num / 1000 * TIMER_FREQ / (denom / 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* list_less_func for sleeping_threads list */
|
||||||
|
bool
|
||||||
|
sleeping_threads_less (const struct list_elem *a, const struct list_elem *b,
|
||||||
|
void *aux UNUSED)
|
||||||
|
{
|
||||||
|
struct asleep_thread *sta = list_entry (a, struct asleep_thread, elem);
|
||||||
|
struct asleep_thread *stb = list_entry (b, struct asleep_thread, elem);
|
||||||
|
return sta->end_at < stb->end_at;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user