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.
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 }
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);
void Cond_Destroy(struct Condition *cond); //added by Lei
extern volatile ulong_t g_numTicks;
-typedef void (*timerCallback)(int);
+typedef void (*timerCallback)(int, void*);
void Init_Timer(void);
typedef struct {
- int ticks; /* timer code decrements this */
- int id; /* unqiue id for this timer even */
- timerCallback callBack; /* Queue to wakeup on timer expire */
- int origTicks;
+ int ticks; /* timer code decrements this */
+ int id; /* unqiue id for this timer even */
+ timerCallback callBack; /* Queue to wakeup on timer expire */
+ void * cb_arg; /* Argument to add to callback */
+ int origTicks;
+
} timerEvent;
-int Start_Timer_Secs(int seconds, timerCallback cb);
-int Start_Timer_MSecs(int msecs, timerCallback cb);
-int Start_Timer(int ticks, timerCallback);
+int Start_Timer_Secs(int seconds, timerCallback cb, void * arg);
+int Start_Timer_MSecs(int msecs, timerCallback cb, void * arg);
+int Start_Timer(int ticks, timerCallback, void * arg);
double Get_Remaining_Timer_Secs(int id);
int Get_Remaining_Timer_MSecs(int id);
}
}
+
+
+/*
+ * 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.
*/
static int Packet_Received(struct NE2K_Packet_Info* info, uchar_t *pkt);
-static void periodic_caller(int timer_id);
+static void periodic_caller(int timer_id, void * arg);
void init_socket_layer() {
int i = 0;
Init_Ne2k(&Packet_Received);
iflag = Begin_Int_Atomic();
- Start_Timer(2, periodic_caller);
+ Start_Timer(2, periodic_caller, NULL);
End_Int_Atomic(iflag);
}
-static void periodic_caller(int timer_id) {
+static void periodic_caller(int timer_id, void * arg) {
int i;
//handle the periodic calls of uIP
#include <geekos/kassert.h>
#include <geekos/screen.h>
#include <geekos/synch.h>
+#include <geekos/timer.h>
/*
* NOTES:
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!
if (pendingTimerEvents[i].ticks == 0) {
if (timerDebug) Print("timer: event %d expired (%d ticks)\n",
pendingTimerEvents[i].id, pendingTimerEvents[i].origTicks);
- (pendingTimerEvents[i].callBack)(pendingTimerEvents[i].id);
+ (pendingTimerEvents[i].callBack)(pendingTimerEvents[i].id, pendingTimerEvents[i].cb_arg);
pendingTimerEvents[i].ticks = pendingTimerEvents[i].origTicks;
} else {
pendingTimerEvents[i].ticks--;
}
-int Start_Timer_Secs(int seconds, timerCallback cb) {
- return Start_Timer(seconds * HZ, cb);
+int Start_Timer_Secs(int seconds, timerCallback cb, void * arg) {
+ return Start_Timer(seconds * HZ, cb, arg);
}
-int Start_Timer_MSecs(int msecs, timerCallback cb) {
+int Start_Timer_MSecs(int msecs, timerCallback cb, void * arg) {
msecs += 10 - (msecs % 10);
- return Start_Timer(msecs * (HZ / 1000), cb);
+ return Start_Timer(msecs * (HZ / 1000), cb, arg);
}
-int Start_Timer(int ticks, timerCallback cb)
+int Start_Timer(int ticks, timerCallback cb, void * arg)
{
int ret;
ret = nextEventID++;
pendingTimerEvents[timeEventCount].id = ret;
pendingTimerEvents[timeEventCount].callBack = cb;
+ pendingTimerEvents[timeEventCount].cb_arg = arg;
pendingTimerEvents[timeEventCount].ticks = ticks;
pendingTimerEvents[timeEventCount].origTicks = ticks;
timeEventCount++;