Implement non-busy timer_sleep (task 0)

This commit is contained in:
2024-10-10 11:28:35 +01:00
parent 1a669267d0
commit f5d130f832

View File

@@ -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;
}