Project HW #2
This commit is contained in:
parent
7bb6e7cbc0
commit
45efb57647
3 changed files with 124 additions and 64 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
// Author: Claudio Maggioni
|
||||||
|
// Author: Tommaso Rodolfo Masera
|
||||||
|
|
||||||
#include "devices/timer.h"
|
#include "devices/timer.h"
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
@ -7,7 +10,9 @@
|
||||||
#include "threads/interrupt.h"
|
#include "threads/interrupt.h"
|
||||||
#include "threads/synch.h"
|
#include "threads/synch.h"
|
||||||
#include "threads/thread.h"
|
#include "threads/thread.h"
|
||||||
|
#include "threads/malloc.h"
|
||||||
|
#include "../lib/kernel/list.h"
|
||||||
|
|
||||||
/* See [8254] for hardware details of the 8254 timer chip. */
|
/* See [8254] for hardware details of the 8254 timer chip. */
|
||||||
|
|
||||||
#if TIMER_FREQ < 19
|
#if TIMER_FREQ < 19
|
||||||
|
@ -33,7 +38,7 @@ static void real_time_delay (int64_t num, int32_t denom);
|
||||||
/* 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. */
|
||||||
void
|
void
|
||||||
timer_init (void)
|
timer_init (void)
|
||||||
{
|
{
|
||||||
pit_configure_channel (0, 2, TIMER_FREQ);
|
pit_configure_channel (0, 2, TIMER_FREQ);
|
||||||
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
|
intr_register_ext (0x20, timer_interrupt, "8254 Timer");
|
||||||
|
@ -41,7 +46,7 @@ timer_init (void)
|
||||||
|
|
||||||
/* Calibrates loops_per_tick, used to implement brief delays. */
|
/* Calibrates loops_per_tick, used to implement brief delays. */
|
||||||
void
|
void
|
||||||
timer_calibrate (void)
|
timer_calibrate (void)
|
||||||
{
|
{
|
||||||
unsigned high_bit, test_bit;
|
unsigned high_bit, test_bit;
|
||||||
|
|
||||||
|
@ -51,7 +56,7 @@ timer_calibrate (void)
|
||||||
/* Approximate loops_per_tick as the largest power-of-two
|
/* Approximate loops_per_tick as the largest power-of-two
|
||||||
still less than one timer tick. */
|
still less than one timer tick. */
|
||||||
loops_per_tick = 1u << 10;
|
loops_per_tick = 1u << 10;
|
||||||
while (!too_many_loops (loops_per_tick << 1))
|
while (!too_many_loops (loops_per_tick << 1))
|
||||||
{
|
{
|
||||||
loops_per_tick <<= 1;
|
loops_per_tick <<= 1;
|
||||||
ASSERT (loops_per_tick != 0);
|
ASSERT (loops_per_tick != 0);
|
||||||
|
@ -68,7 +73,7 @@ timer_calibrate (void)
|
||||||
|
|
||||||
/* Returns the number of timer ticks since the OS booted. */
|
/* Returns the number of timer ticks since the OS booted. */
|
||||||
int64_t
|
int64_t
|
||||||
timer_ticks (void)
|
timer_ticks (void)
|
||||||
{
|
{
|
||||||
enum intr_level old_level = intr_disable ();
|
enum intr_level old_level = intr_disable ();
|
||||||
int64_t t = ticks;
|
int64_t t = ticks;
|
||||||
|
@ -79,7 +84,7 @@ timer_ticks (void)
|
||||||
/* Returns the number of timer ticks elapsed since THEN, which
|
/* Returns the number of timer ticks elapsed since THEN, which
|
||||||
should be a value once returned by timer_ticks(). */
|
should be a value once returned by timer_ticks(). */
|
||||||
int64_t
|
int64_t
|
||||||
timer_elapsed (int64_t then)
|
timer_elapsed (int64_t then)
|
||||||
{
|
{
|
||||||
return timer_ticks () - then;
|
return timer_ticks () - then;
|
||||||
}
|
}
|
||||||
|
@ -87,19 +92,20 @@ timer_elapsed (int64_t then)
|
||||||
/* Sleeps for approximately TICKS timer ticks. Interrupts must
|
/* Sleeps for approximately TICKS timer ticks. Interrupts must
|
||||||
be turned on. */
|
be turned on. */
|
||||||
void
|
void
|
||||||
timer_sleep (int64_t ticks)
|
timer_sleep (int64_t ticks)
|
||||||
{
|
{
|
||||||
int64_t start = timer_ticks ();
|
if (ticks <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
ASSERT (intr_get_level () == INTR_ON);
|
ASSERT (intr_get_level() == INTR_ON);
|
||||||
while (timer_elapsed (start) < ticks)
|
|
||||||
thread_yield ();
|
thread_sleep(ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sleeps for approximately MS milliseconds. Interrupts must be
|
/* Sleeps for approximately MS milliseconds. Interrupts must be
|
||||||
turned on. */
|
turned on. */
|
||||||
void
|
void
|
||||||
timer_msleep (int64_t ms)
|
timer_msleep (int64_t ms)
|
||||||
{
|
{
|
||||||
real_time_sleep (ms, 1000);
|
real_time_sleep (ms, 1000);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +113,7 @@ timer_msleep (int64_t ms)
|
||||||
/* Sleeps for approximately US microseconds. Interrupts must be
|
/* Sleeps for approximately US microseconds. Interrupts must be
|
||||||
turned on. */
|
turned on. */
|
||||||
void
|
void
|
||||||
timer_usleep (int64_t us)
|
timer_usleep (int64_t us)
|
||||||
{
|
{
|
||||||
real_time_sleep (us, 1000 * 1000);
|
real_time_sleep (us, 1000 * 1000);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +121,7 @@ timer_usleep (int64_t us)
|
||||||
/* Sleeps for approximately NS nanoseconds. Interrupts must be
|
/* Sleeps for approximately NS nanoseconds. Interrupts must be
|
||||||
turned on. */
|
turned on. */
|
||||||
void
|
void
|
||||||
timer_nsleep (int64_t ns)
|
timer_nsleep (int64_t ns)
|
||||||
{
|
{
|
||||||
real_time_sleep (ns, 1000 * 1000 * 1000);
|
real_time_sleep (ns, 1000 * 1000 * 1000);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +134,7 @@ timer_nsleep (int64_t ns)
|
||||||
will cause timer ticks to be lost. Thus, use timer_msleep()
|
will cause timer ticks to be lost. Thus, use timer_msleep()
|
||||||
instead if interrupts are enabled. */
|
instead if interrupts are enabled. */
|
||||||
void
|
void
|
||||||
timer_mdelay (int64_t ms)
|
timer_mdelay (int64_t ms)
|
||||||
{
|
{
|
||||||
real_time_delay (ms, 1000);
|
real_time_delay (ms, 1000);
|
||||||
}
|
}
|
||||||
|
@ -141,7 +147,7 @@ timer_mdelay (int64_t ms)
|
||||||
will cause timer ticks to be lost. Thus, use timer_usleep()
|
will cause timer ticks to be lost. Thus, use timer_usleep()
|
||||||
instead if interrupts are enabled. */
|
instead if interrupts are enabled. */
|
||||||
void
|
void
|
||||||
timer_udelay (int64_t us)
|
timer_udelay (int64_t us)
|
||||||
{
|
{
|
||||||
real_time_delay (us, 1000 * 1000);
|
real_time_delay (us, 1000 * 1000);
|
||||||
}
|
}
|
||||||
|
@ -154,14 +160,14 @@ timer_udelay (int64_t us)
|
||||||
will cause timer ticks to be lost. Thus, use timer_nsleep()
|
will cause timer ticks to be lost. Thus, use timer_nsleep()
|
||||||
instead if interrupts are enabled.*/
|
instead if interrupts are enabled.*/
|
||||||
void
|
void
|
||||||
timer_ndelay (int64_t ns)
|
timer_ndelay (int64_t ns)
|
||||||
{
|
{
|
||||||
real_time_delay (ns, 1000 * 1000 * 1000);
|
real_time_delay (ns, 1000 * 1000 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prints timer statistics. */
|
/* Prints timer statistics. */
|
||||||
void
|
void
|
||||||
timer_print_stats (void)
|
timer_print_stats (void)
|
||||||
{
|
{
|
||||||
printf ("Timer: %"PRId64" ticks\n", timer_ticks ());
|
printf ("Timer: %"PRId64" ticks\n", timer_ticks ());
|
||||||
}
|
}
|
||||||
|
@ -171,13 +177,15 @@ static void
|
||||||
timer_interrupt (struct intr_frame *args UNUSED)
|
timer_interrupt (struct intr_frame *args UNUSED)
|
||||||
{
|
{
|
||||||
ticks++;
|
ticks++;
|
||||||
thread_tick ();
|
|
||||||
|
thread_unsleep();
|
||||||
|
thread_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true if LOOPS iterations waits for more than one timer
|
/* Returns true if LOOPS iterations waits for more than one timer
|
||||||
tick, otherwise false. */
|
tick, otherwise false. */
|
||||||
static bool
|
static bool
|
||||||
too_many_loops (unsigned loops)
|
too_many_loops (unsigned loops)
|
||||||
{
|
{
|
||||||
/* Wait for a timer tick. */
|
/* Wait for a timer tick. */
|
||||||
int64_t start = ticks;
|
int64_t start = ticks;
|
||||||
|
@ -201,7 +209,7 @@ too_many_loops (unsigned loops)
|
||||||
differently in different places the results would be difficult
|
differently in different places the results would be difficult
|
||||||
to predict. */
|
to predict. */
|
||||||
static void NO_INLINE
|
static void NO_INLINE
|
||||||
busy_wait (int64_t loops)
|
busy_wait (int64_t loops)
|
||||||
{
|
{
|
||||||
while (loops-- > 0)
|
while (loops-- > 0)
|
||||||
barrier ();
|
barrier ();
|
||||||
|
@ -209,12 +217,12 @@ busy_wait (int64_t loops)
|
||||||
|
|
||||||
/* Sleep for approximately NUM/DENOM seconds. */
|
/* Sleep for approximately NUM/DENOM seconds. */
|
||||||
static void
|
static void
|
||||||
real_time_sleep (int64_t num, int32_t denom)
|
real_time_sleep (int64_t num, int32_t denom)
|
||||||
{
|
{
|
||||||
/* Convert NUM/DENOM seconds into timer ticks, rounding down.
|
/* Convert NUM/DENOM seconds into timer ticks, rounding down.
|
||||||
|
|
||||||
(NUM / DENOM) s
|
(NUM / DENOM) s
|
||||||
---------------------- = NUM * TIMER_FREQ / DENOM ticks.
|
---------------------- = NUM * TIMER_FREQ / DENOM ticks.
|
||||||
1 s / TIMER_FREQ ticks
|
1 s / TIMER_FREQ ticks
|
||||||
*/
|
*/
|
||||||
int64_t ticks = num * TIMER_FREQ / denom;
|
int64_t ticks = num * TIMER_FREQ / denom;
|
||||||
|
@ -224,14 +232,14 @@ real_time_sleep (int64_t num, int32_t denom)
|
||||||
{
|
{
|
||||||
/* We're waiting for at least one full timer tick. Use
|
/* We're waiting for at least one full timer tick. Use
|
||||||
timer_sleep() because it will yield the CPU to other
|
timer_sleep() because it will yield the CPU to other
|
||||||
processes. */
|
processes. */
|
||||||
timer_sleep (ticks);
|
timer_sleep (ticks);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Otherwise, use a busy-wait loop for more accurate
|
/* Otherwise, use a busy-wait loop for more accurate
|
||||||
sub-tick timing. */
|
sub-tick timing. */
|
||||||
real_time_delay (num, denom);
|
real_time_delay (num, denom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,5 +250,5 @@ real_time_delay (int64_t num, int32_t denom)
|
||||||
/* Scale the numerator and denominator down by 1000 to avoid
|
/* Scale the numerator and denominator down by 1000 to avoid
|
||||||
the possibility of overflow. */
|
the possibility of overflow. */
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Author: Claudio Maggioni
|
||||||
|
// Author: Tommaso Rodolfo Masera
|
||||||
|
|
||||||
#include "threads/thread.h"
|
#include "threads/thread.h"
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -11,6 +14,7 @@
|
||||||
#include "threads/switch.h"
|
#include "threads/switch.h"
|
||||||
#include "threads/synch.h"
|
#include "threads/synch.h"
|
||||||
#include "threads/vaddr.h"
|
#include "threads/vaddr.h"
|
||||||
|
#include "devices/timer.h"
|
||||||
#ifdef USERPROG
|
#ifdef USERPROG
|
||||||
#include "userprog/process.h"
|
#include "userprog/process.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,8 +41,10 @@ static struct thread *initial_thread;
|
||||||
/* Lock used by allocate_tid(). */
|
/* Lock used by allocate_tid(). */
|
||||||
static struct lock tid_lock;
|
static struct lock tid_lock;
|
||||||
|
|
||||||
|
static struct list sleeping;
|
||||||
|
|
||||||
/* Stack frame for kernel_thread(). */
|
/* Stack frame for kernel_thread(). */
|
||||||
struct kernel_thread_frame
|
struct kernel_thread_frame
|
||||||
{
|
{
|
||||||
void *eip; /* Return address. */
|
void *eip; /* Return address. */
|
||||||
thread_func *function; /* Function to call. */
|
thread_func *function; /* Function to call. */
|
||||||
|
@ -85,7 +91,7 @@ static tid_t allocate_tid (void);
|
||||||
It is not safe to call thread_current() until this function
|
It is not safe to call thread_current() until this function
|
||||||
finishes. */
|
finishes. */
|
||||||
void
|
void
|
||||||
thread_init (void)
|
thread_init (void)
|
||||||
{
|
{
|
||||||
ASSERT (intr_get_level () == INTR_OFF);
|
ASSERT (intr_get_level () == INTR_OFF);
|
||||||
|
|
||||||
|
@ -98,12 +104,52 @@ thread_init (void)
|
||||||
init_thread (initial_thread, "main", PRI_DEFAULT);
|
init_thread (initial_thread, "main", PRI_DEFAULT);
|
||||||
initial_thread->status = THREAD_RUNNING;
|
initial_thread->status = THREAD_RUNNING;
|
||||||
initial_thread->tid = allocate_tid ();
|
initial_thread->tid = allocate_tid ();
|
||||||
|
|
||||||
|
list_init(&sleeping);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
earlier_wakeup(const struct list_elem* a, const struct list_elem* b, void* aux UNUSED) {
|
||||||
|
return list_entry(a, struct thread, elem)->wakeup <
|
||||||
|
list_entry(b, struct thread, elem)->wakeup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thread_sleep(uint64_t ticks) {
|
||||||
|
enum intr_level old_level = intr_disable();
|
||||||
|
struct thread* cur = thread_current();
|
||||||
|
cur->wakeup = timer_ticks() + ticks;
|
||||||
|
// printf("sleeping insert %X\n", cur);
|
||||||
|
list_insert_ordered(&sleeping, &(cur->elem), earlier_wakeup, NULL);
|
||||||
|
thread_block();
|
||||||
|
intr_set_level(old_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct thread* thr(struct list_elem* l) {
|
||||||
|
return list_entry(l, struct thread, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
thread_unsleep() {
|
||||||
|
const uint64_t ticks = timer_ticks();
|
||||||
|
enum intr_level old_level = intr_disable();
|
||||||
|
if (!list_empty(&sleeping)) {
|
||||||
|
|
||||||
|
struct list_elem* t = list_begin(&sleeping);
|
||||||
|
while (thr(t)->wakeup <= ticks) {
|
||||||
|
// printf("sleeping remove %X\n", thr(t));
|
||||||
|
struct thread* s = thr(t);
|
||||||
|
t = list_remove(t);
|
||||||
|
thread_unblock(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intr_set_level(old_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Starts preemptive thread scheduling by enabling interrupts.
|
/* Starts preemptive thread scheduling by enabling interrupts.
|
||||||
Also creates the idle thread. */
|
Also creates the idle thread. */
|
||||||
void
|
void
|
||||||
thread_start (void)
|
thread_start (void)
|
||||||
{
|
{
|
||||||
/* Create the idle thread. */
|
/* Create the idle thread. */
|
||||||
struct semaphore idle_started;
|
struct semaphore idle_started;
|
||||||
|
@ -120,7 +166,7 @@ thread_start (void)
|
||||||
/* Called by the timer interrupt handler at each timer tick.
|
/* Called by the timer interrupt handler at each timer tick.
|
||||||
Thus, this function runs in an external interrupt context. */
|
Thus, this function runs in an external interrupt context. */
|
||||||
void
|
void
|
||||||
thread_tick (void)
|
thread_tick (void)
|
||||||
{
|
{
|
||||||
struct thread *t = thread_current ();
|
struct thread *t = thread_current ();
|
||||||
|
|
||||||
|
@ -141,7 +187,7 @@ thread_tick (void)
|
||||||
|
|
||||||
/* Prints thread statistics. */
|
/* Prints thread statistics. */
|
||||||
void
|
void
|
||||||
thread_print_stats (void)
|
thread_print_stats (void)
|
||||||
{
|
{
|
||||||
printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n",
|
printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n",
|
||||||
idle_ticks, kernel_ticks, user_ticks);
|
idle_ticks, kernel_ticks, user_ticks);
|
||||||
|
@ -164,7 +210,7 @@ thread_print_stats (void)
|
||||||
Priority scheduling is the goal of Problem 1-3. */
|
Priority scheduling is the goal of Problem 1-3. */
|
||||||
tid_t
|
tid_t
|
||||||
thread_create (const char *name, int priority,
|
thread_create (const char *name, int priority,
|
||||||
thread_func *function, void *aux)
|
thread_func *function, void *aux)
|
||||||
{
|
{
|
||||||
struct thread *t;
|
struct thread *t;
|
||||||
struct kernel_thread_frame *kf;
|
struct kernel_thread_frame *kf;
|
||||||
|
@ -185,7 +231,7 @@ thread_create (const char *name, int priority,
|
||||||
tid = t->tid = allocate_tid ();
|
tid = t->tid = allocate_tid ();
|
||||||
|
|
||||||
/* Prepare thread for first run by initializing its stack.
|
/* Prepare thread for first run by initializing its stack.
|
||||||
Do this atomically so intermediate values for the 'stack'
|
Do this atomically so intermediate values for the 'stack'
|
||||||
member cannot be observed. */
|
member cannot be observed. */
|
||||||
old_level = intr_disable ();
|
old_level = intr_disable ();
|
||||||
|
|
||||||
|
@ -219,7 +265,7 @@ thread_create (const char *name, int priority,
|
||||||
is usually a better idea to use one of the synchronization
|
is usually a better idea to use one of the synchronization
|
||||||
primitives in synch.h. */
|
primitives in synch.h. */
|
||||||
void
|
void
|
||||||
thread_block (void)
|
thread_block (void)
|
||||||
{
|
{
|
||||||
ASSERT (!intr_context ());
|
ASSERT (!intr_context ());
|
||||||
ASSERT (intr_get_level () == INTR_OFF);
|
ASSERT (intr_get_level () == INTR_OFF);
|
||||||
|
@ -237,7 +283,7 @@ thread_block (void)
|
||||||
it may expect that it can atomically unblock a thread and
|
it may expect that it can atomically unblock a thread and
|
||||||
update other data. */
|
update other data. */
|
||||||
void
|
void
|
||||||
thread_unblock (struct thread *t)
|
thread_unblock (struct thread *t)
|
||||||
{
|
{
|
||||||
enum intr_level old_level;
|
enum intr_level old_level;
|
||||||
|
|
||||||
|
@ -252,7 +298,7 @@ thread_unblock (struct thread *t)
|
||||||
|
|
||||||
/* Returns the name of the running thread. */
|
/* Returns the name of the running thread. */
|
||||||
const char *
|
const char *
|
||||||
thread_name (void)
|
thread_name (void)
|
||||||
{
|
{
|
||||||
return thread_current ()->name;
|
return thread_current ()->name;
|
||||||
}
|
}
|
||||||
|
@ -261,10 +307,10 @@ thread_name (void)
|
||||||
This is running_thread() plus a couple of sanity checks.
|
This is running_thread() plus a couple of sanity checks.
|
||||||
See the big comment at the top of thread.h for details. */
|
See the big comment at the top of thread.h for details. */
|
||||||
struct thread *
|
struct thread *
|
||||||
thread_current (void)
|
thread_current (void)
|
||||||
{
|
{
|
||||||
struct thread *t = running_thread ();
|
struct thread *t = running_thread ();
|
||||||
|
|
||||||
/* Make sure T is really a thread.
|
/* Make sure T is really a thread.
|
||||||
If either of these assertions fire, then your thread may
|
If either of these assertions fire, then your thread may
|
||||||
have overflowed its stack. Each thread has less than 4 kB
|
have overflowed its stack. Each thread has less than 4 kB
|
||||||
|
@ -278,7 +324,7 @@ thread_current (void)
|
||||||
|
|
||||||
/* Returns the running thread's tid. */
|
/* Returns the running thread's tid. */
|
||||||
tid_t
|
tid_t
|
||||||
thread_tid (void)
|
thread_tid (void)
|
||||||
{
|
{
|
||||||
return thread_current ()->tid;
|
return thread_current ()->tid;
|
||||||
}
|
}
|
||||||
|
@ -286,7 +332,7 @@ thread_tid (void)
|
||||||
/* Deschedules the current thread and destroys it. Never
|
/* Deschedules the current thread and destroys it. Never
|
||||||
returns to the caller. */
|
returns to the caller. */
|
||||||
void
|
void
|
||||||
thread_exit (void)
|
thread_exit (void)
|
||||||
{
|
{
|
||||||
ASSERT (!intr_context ());
|
ASSERT (!intr_context ());
|
||||||
|
|
||||||
|
@ -307,15 +353,15 @@ thread_exit (void)
|
||||||
/* Yields the CPU. The current thread is not put to sleep and
|
/* Yields the CPU. The current thread is not put to sleep and
|
||||||
may be scheduled again immediately at the scheduler's whim. */
|
may be scheduled again immediately at the scheduler's whim. */
|
||||||
void
|
void
|
||||||
thread_yield (void)
|
thread_yield (void)
|
||||||
{
|
{
|
||||||
struct thread *cur = thread_current ();
|
struct thread *cur = thread_current ();
|
||||||
enum intr_level old_level;
|
enum intr_level old_level;
|
||||||
|
|
||||||
ASSERT (!intr_context ());
|
ASSERT (!intr_context ());
|
||||||
|
|
||||||
old_level = intr_disable ();
|
old_level = intr_disable ();
|
||||||
if (cur != idle_thread)
|
if (cur != idle_thread)
|
||||||
list_push_back (&ready_list, &cur->elem);
|
list_push_back (&ready_list, &cur->elem);
|
||||||
cur->status = THREAD_READY;
|
cur->status = THREAD_READY;
|
||||||
schedule ();
|
schedule ();
|
||||||
|
@ -341,28 +387,28 @@ thread_foreach (thread_action_func *func, void *aux)
|
||||||
|
|
||||||
/* Sets the current thread's priority to NEW_PRIORITY. */
|
/* Sets the current thread's priority to NEW_PRIORITY. */
|
||||||
void
|
void
|
||||||
thread_set_priority (int new_priority)
|
thread_set_priority (int new_priority)
|
||||||
{
|
{
|
||||||
thread_current ()->priority = new_priority;
|
thread_current ()->priority = new_priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the current thread's priority. */
|
/* Returns the current thread's priority. */
|
||||||
int
|
int
|
||||||
thread_get_priority (void)
|
thread_get_priority (void)
|
||||||
{
|
{
|
||||||
return thread_current ()->priority;
|
return thread_current ()->priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets the current thread's nice value to NICE. */
|
/* Sets the current thread's nice value to NICE. */
|
||||||
void
|
void
|
||||||
thread_set_nice (int nice UNUSED)
|
thread_set_nice (int nice UNUSED)
|
||||||
{
|
{
|
||||||
/* Not yet implemented. */
|
/* Not yet implemented. */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the current thread's nice value. */
|
/* Returns the current thread's nice value. */
|
||||||
int
|
int
|
||||||
thread_get_nice (void)
|
thread_get_nice (void)
|
||||||
{
|
{
|
||||||
/* Not yet implemented. */
|
/* Not yet implemented. */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -370,7 +416,7 @@ thread_get_nice (void)
|
||||||
|
|
||||||
/* Returns 100 times the system load average. */
|
/* Returns 100 times the system load average. */
|
||||||
int
|
int
|
||||||
thread_get_load_avg (void)
|
thread_get_load_avg (void)
|
||||||
{
|
{
|
||||||
/* Not yet implemented. */
|
/* Not yet implemented. */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -378,7 +424,7 @@ thread_get_load_avg (void)
|
||||||
|
|
||||||
/* Returns 100 times the current thread's recent_cpu value. */
|
/* Returns 100 times the current thread's recent_cpu value. */
|
||||||
int
|
int
|
||||||
thread_get_recent_cpu (void)
|
thread_get_recent_cpu (void)
|
||||||
{
|
{
|
||||||
/* Not yet implemented. */
|
/* Not yet implemented. */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -394,13 +440,13 @@ thread_get_recent_cpu (void)
|
||||||
ready list. It is returned by next_thread_to_run() as a
|
ready list. It is returned by next_thread_to_run() as a
|
||||||
special case when the ready list is empty. */
|
special case when the ready list is empty. */
|
||||||
static void
|
static void
|
||||||
idle (void *idle_started_ UNUSED)
|
idle (void *idle_started_ UNUSED)
|
||||||
{
|
{
|
||||||
struct semaphore *idle_started = idle_started_;
|
struct semaphore *idle_started = idle_started_;
|
||||||
idle_thread = thread_current ();
|
idle_thread = thread_current ();
|
||||||
sema_up (idle_started);
|
sema_up (idle_started);
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/* Let someone else run. */
|
/* Let someone else run. */
|
||||||
intr_disable ();
|
intr_disable ();
|
||||||
|
@ -424,7 +470,7 @@ idle (void *idle_started_ UNUSED)
|
||||||
|
|
||||||
/* Function used as the basis for a kernel thread. */
|
/* Function used as the basis for a kernel thread. */
|
||||||
static void
|
static void
|
||||||
kernel_thread (thread_func *function, void *aux)
|
kernel_thread (thread_func *function, void *aux)
|
||||||
{
|
{
|
||||||
ASSERT (function != NULL);
|
ASSERT (function != NULL);
|
||||||
|
|
||||||
|
@ -435,7 +481,7 @@ kernel_thread (thread_func *function, void *aux)
|
||||||
|
|
||||||
/* Returns the running thread. */
|
/* Returns the running thread. */
|
||||||
struct thread *
|
struct thread *
|
||||||
running_thread (void)
|
running_thread (void)
|
||||||
{
|
{
|
||||||
uint32_t *esp;
|
uint32_t *esp;
|
||||||
|
|
||||||
|
@ -475,7 +521,7 @@ init_thread (struct thread *t, const char *name, int priority)
|
||||||
/* Allocates a SIZE-byte frame at the top of thread T's stack and
|
/* Allocates a SIZE-byte frame at the top of thread T's stack and
|
||||||
returns a pointer to the frame's base. */
|
returns a pointer to the frame's base. */
|
||||||
static void *
|
static void *
|
||||||
alloc_frame (struct thread *t, size_t size)
|
alloc_frame (struct thread *t, size_t size)
|
||||||
{
|
{
|
||||||
/* Stack data is always allocated in word-size units. */
|
/* Stack data is always allocated in word-size units. */
|
||||||
ASSERT (is_thread (t));
|
ASSERT (is_thread (t));
|
||||||
|
@ -491,7 +537,7 @@ alloc_frame (struct thread *t, size_t size)
|
||||||
will be in the run queue.) If the run queue is empty, return
|
will be in the run queue.) If the run queue is empty, return
|
||||||
idle_thread. */
|
idle_thread. */
|
||||||
static struct thread *
|
static struct thread *
|
||||||
next_thread_to_run (void)
|
next_thread_to_run (void)
|
||||||
{
|
{
|
||||||
if (list_empty (&ready_list))
|
if (list_empty (&ready_list))
|
||||||
return idle_thread;
|
return idle_thread;
|
||||||
|
@ -519,7 +565,7 @@ void
|
||||||
thread_schedule_tail (struct thread *prev)
|
thread_schedule_tail (struct thread *prev)
|
||||||
{
|
{
|
||||||
struct thread *cur = running_thread ();
|
struct thread *cur = running_thread ();
|
||||||
|
|
||||||
ASSERT (intr_get_level () == INTR_OFF);
|
ASSERT (intr_get_level () == INTR_OFF);
|
||||||
|
|
||||||
/* Mark us as running. */
|
/* Mark us as running. */
|
||||||
|
@ -538,7 +584,7 @@ thread_schedule_tail (struct thread *prev)
|
||||||
pull out the rug under itself. (We don't free
|
pull out the rug under itself. (We don't free
|
||||||
initial_thread because its memory was not obtained via
|
initial_thread because its memory was not obtained via
|
||||||
palloc().) */
|
palloc().) */
|
||||||
if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread)
|
if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread)
|
||||||
{
|
{
|
||||||
ASSERT (prev != cur);
|
ASSERT (prev != cur);
|
||||||
palloc_free_page (prev);
|
palloc_free_page (prev);
|
||||||
|
@ -553,7 +599,7 @@ thread_schedule_tail (struct thread *prev)
|
||||||
It's not safe to call printf() until thread_schedule_tail()
|
It's not safe to call printf() until thread_schedule_tail()
|
||||||
has completed. */
|
has completed. */
|
||||||
static void
|
static void
|
||||||
schedule (void)
|
schedule (void)
|
||||||
{
|
{
|
||||||
struct thread *cur = running_thread ();
|
struct thread *cur = running_thread ();
|
||||||
struct thread *next = next_thread_to_run ();
|
struct thread *next = next_thread_to_run ();
|
||||||
|
@ -570,7 +616,7 @@ schedule (void)
|
||||||
|
|
||||||
/* Returns a tid to use for a new thread. */
|
/* Returns a tid to use for a new thread. */
|
||||||
static tid_t
|
static tid_t
|
||||||
allocate_tid (void)
|
allocate_tid (void)
|
||||||
{
|
{
|
||||||
static tid_t next_tid = 1;
|
static tid_t next_tid = 1;
|
||||||
tid_t tid;
|
tid_t tid;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Author: Claudio Maggioni
|
||||||
|
// Author: Tommaso Rodolfo Masera
|
||||||
|
|
||||||
#ifndef THREADS_THREAD_H
|
#ifndef THREADS_THREAD_H
|
||||||
#define THREADS_THREAD_H
|
#define THREADS_THREAD_H
|
||||||
|
|
||||||
|
@ -89,7 +92,7 @@ struct thread
|
||||||
uint8_t *stack; /* Saved stack pointer. */
|
uint8_t *stack; /* Saved stack pointer. */
|
||||||
int priority; /* Priority. */
|
int priority; /* Priority. */
|
||||||
struct list_elem allelem; /* List element for all threads list. */
|
struct list_elem allelem; /* List element for all threads list. */
|
||||||
|
uint64_t wakeup;
|
||||||
/* Shared between thread.c and synch.c. */
|
/* Shared between thread.c and synch.c. */
|
||||||
struct list_elem elem; /* List element. */
|
struct list_elem elem; /* List element. */
|
||||||
|
|
||||||
|
@ -126,6 +129,9 @@ const char *thread_name (void);
|
||||||
void thread_exit (void) NO_RETURN;
|
void thread_exit (void) NO_RETURN;
|
||||||
void thread_yield (void);
|
void thread_yield (void);
|
||||||
|
|
||||||
|
void thread_sleep(uint64_t ticks);
|
||||||
|
void thread_unsleep(void);
|
||||||
|
|
||||||
/* Performs some operation on thread t, given auxiliary data AUX. */
|
/* Performs some operation on thread t, given auxiliary data AUX. */
|
||||||
typedef void thread_action_func (struct thread *t, void *aux);
|
typedef void thread_action_func (struct thread *t, void *aux);
|
||||||
void thread_foreach (thread_action_func *, void *);
|
void thread_foreach (thread_action_func *, void *);
|
||||||
|
|
Reference in a new issue