From: Jack Lange Date: Mon, 29 Sep 2008 16:07:55 +0000 (-0500) Subject: added support for timing out Cond_Wait's X-Git-Tag: 1.0~3^2~11^2~4^2 X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=ac9621026b54c3b5e9bae3d7153736c65ab03652;p=palacios.git added support for timing out Cond_Wait's also added support for waking up specific threads by pid --- diff --git a/palacios/include/geekos/kthread.h b/palacios/include/geekos/kthread.h index f0ef23c..48ade1c 100644 --- a/palacios/include/geekos/kthread.h +++ b/palacios/include/geekos/kthread.h @@ -123,6 +123,7 @@ void Switch_To_Thread(struct Kernel_Thread*); void Wait(struct Thread_Queue* waitQueue); void Wake_Up(struct Thread_Queue* waitQueue); void Wake_Up_One(struct Thread_Queue* waitQueue); +void Wake_Up_Thread(struct Thread_Queue* waitQueue, int pid); /* * Pointer to currently executing thread. diff --git a/palacios/include/geekos/synch.h b/palacios/include/geekos/synch.h index 5cb95ef..b1ad875 100644 --- a/palacios/include/geekos/synch.h +++ b/palacios/include/geekos/synch.h @@ -18,9 +18,9 @@ enum { MUTEX_UNLOCKED, MUTEX_LOCKED }; struct Mutex { - int state; - struct Kernel_Thread* owner; - struct Thread_Queue waitQueue; + int state; + struct Kernel_Thread* owner; + struct Thread_Queue waitQueue; }; #define MUTEX_INITIALIZER { MUTEX_UNLOCKED, 0, THREAD_QUEUE_INITIALIZER } @@ -35,6 +35,7 @@ void Mutex_Unlock(struct Mutex* mutex); void Cond_Init(struct Condition* cond); void Cond_Wait(struct Condition* cond, struct Mutex* mutex); +int Cond_Wait_Timeout(struct Condition * cond, struct Mutex * mutex, uint_t ms); void Cond_Signal(struct Condition* cond); void Cond_Broadcast(struct Condition* cond); diff --git a/palacios/src/geekos/kthread.c b/palacios/src/geekos/kthread.c index 0cba546..6ecb30f 100644 --- a/palacios/src/geekos/kthread.c +++ b/palacios/src/geekos/kthread.c @@ -748,6 +748,30 @@ void Wake_Up_One(struct Thread_Queue* waitQueue) } } + + +/* + * Wake up a single thread waiting on given wait queue + * (if there are any threads waiting). Chooses the highest priority thread. + * Interrupts must be disabled! + */ +void Wake_Up_Thread(struct Thread_Queue* waitQueue, int pid) +{ + struct Kernel_Thread* thread = Lookup_Thread(pid);; + + KASSERT(!Interrupts_Enabled()); + + + if (thread != 0) { + Remove_Thread(waitQueue, thread); + Make_Runnable(thread); + /*Print("Wake_Up_One: waking up %x from %x\n", best, g_currentThread); */ + } +} + + + + /* * Allocate a key for accessing thread-local data. */ diff --git a/palacios/src/geekos/synch.c b/palacios/src/geekos/synch.c index 86e7191..fdc1f34 100644 --- a/palacios/src/geekos/synch.c +++ b/palacios/src/geekos/synch.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * NOTES: @@ -181,6 +182,82 @@ void Cond_Wait(struct Condition* cond, struct Mutex* mutex) g_preemptionDisabled = false; } + + +struct timeout_data { + int pid; + int timed_out; + struct Thread_Queue * waitQueue; +}; + + +static void timeout_cb(int id, void * arg) { + struct timeout_data * to_state = (struct timeout_data *)arg; + + to_state->timed_out = 1; + Wake_Up_Thread(to_state->waitQueue, to_state->pid); + +} + + +/* + * Wait on given condition (protected by given mutex). + */ +int Cond_Wait_Timeout(struct Condition* cond, struct Mutex* mutex, uint_t ms) +{ + struct timeout_data to_state; + struct Kernel_Thread * self = Get_Current(); + + to_state.pid = self->pid; + to_state.timed_out = 0; + to_state.waitQueue = &cond->waitQueue; + + KASSERT(Interrupts_Enabled()); + + /* Ensure mutex is held. */ + KASSERT(IS_HELD(mutex)); + + /* Turn off scheduling. */ + g_preemptionDisabled = true; + + + + /* + * Release the mutex, but leave preemption disabled. + * No other threads will be able to run before this thread + * is able to wait. Therefore, this thread will not + * miss the eventual notification on the condition. + */ + Mutex_Unlock_Imp(mutex); + + + Start_Timer_MSecs(ms, timeout_cb, &to_state); + + /* + * Atomically reenable preemption and wait in the condition wait queue. + * Other threads can run while this thread is waiting, + * and eventually one of them will call Cond_Signal() or Cond_Broadcast() + * to wake up this thread. + * On wakeup, disable preemption again. + */ + Disable_Interrupts(); + g_preemptionDisabled = false; + Wait(&cond->waitQueue); + g_preemptionDisabled = true; + Enable_Interrupts(); + + if (to_state.timed_out == 0) { + /* Reacquire the mutex. */ + Mutex_Lock_Imp(mutex); + } + + /* Turn scheduling back on. */ + g_preemptionDisabled = false; + + + return to_state.timed_out; +} + /* * Wake up one thread waiting on the given condition. * The mutex guarding the condition should be held!