/**
* @author Kevin Klues <klueska@cs.stanford.edu>
*/
-
+
module TinyThreadSchedulerP {
provides {
interface ThreadScheduler;
interface Boot as ThreadSchedulerBoot;
interface ThreadInfo[uint8_t id];
interface ThreadQueue;
+ interface BitArrayUtils;
interface McuSleep;
interface Leds;
interface Timer<TMilli> as PreemptionAlarm;
//Pointer to yielding thread
thread_t* yielding_thread;
//Number of threads started, and currently capable of running if given the chance
- uint8_t num_started_threads;
+ uint8_t num_runnable_threads;
//Thread queue for keeping track of threads waiting to run
thread_queue_t ready_queue;
+ void task alarmTask() {
+ uint8_t temp;
+ atomic temp = num_runnable_threads;
+ if(temp <= 1)
+ call PreemptionAlarm.stop();
+ else if(temp > 1)
+ call PreemptionAlarm.startOneShot(TOSTHREAD_PREEMPTION_PERIOD);
+ }
+
/* switch_threads()
* This routine swaps the stack and allows a thread to run.
* Needs to be in a separate function like this so that the
while(TRUE) {
bool mt;
atomic mt = (call ThreadQueue.isEmpty(&ready_queue) == TRUE);
- if(!mt) break;
+ if(!mt || tos_thread->state == TOSTHREAD_STATE_READY) break;
call McuSleep.sleep();
}
}
*/
void scheduleNextThread() {
if(tos_thread->state == TOSTHREAD_STATE_READY)
- current_thread = call ThreadQueue.remove(&ready_queue, tos_thread);
+ current_thread = tos_thread;
else
current_thread = call ThreadQueue.dequeue(&ready_queue);
void suspend(thread_t* thread) {
//if there are no active threads, put the MCU to sleep
//Then wakeup the TinyOS thread whenever the MCU wakes up again
+ #ifdef TOSTHREADS_TIMER_OPTIMIZATION
+ num_runnable_threads--;
+ post alarmTask();
+ #endif
sleepWhileIdle();
interrupt(thread);
}
+ void wakeupJoined(thread_t* t) {
+ int i,j,k;
+ k = 0;
+ for(i=0; i<sizeof(t->joinedOnMe); i++) {
+ if(t->joinedOnMe[i] == 0) {
+ k+=8;
+ continue;
+ }
+ for(j=0; j<8; j++) {
+ if(t->joinedOnMe[i] & 0x1)
+ call ThreadScheduler.wakeupThread(k);
+ t->joinedOnMe[i] >>= 1;
+ k++;
+ }
+ }
+ }
+
/* stop
* This routine stops a thread by putting it into the inactive state
* and decrementing any necessary variables used to keep track of
* threads by the thread scheduler.
*/
- void stop(thread_t* t) {
- t->state = TOSTHREAD_STATE_INACTIVE;
- num_started_threads--;
- if(num_started_threads == 1)
- call PreemptionAlarm.stop();
- signal ThreadCleanup.cleanup[t->id]();
- }
+ void stop(thread_t* t) {
+ t->state = TOSTHREAD_STATE_INACTIVE;
+ num_runnable_threads--;
+ wakeupJoined(t);
+ #ifdef TOSTHREADS_TIMER_OPTIMIZATION
+ post alarmTask();
+ #else
+ if(num_runnable_threads == 1)
+ call PreemptionAlarm.stop();
+ #endif
+ signal ThreadCleanup.cleanup[t->id]();
+ }
/* This executes and cleans up a thread
*/
}
event void ThreadSchedulerBoot.booted() {
- num_started_threads = 0;
+ num_runnable_threads = 0;
tos_thread = call ThreadInfo.get[TOSTHREAD_TOS_THREAD_ID]();
tos_thread->id = TOSTHREAD_TOS_THREAD_ID;
call ThreadQueue.init(&ready_queue);
thread_t* t = (call ThreadInfo.get[id]());
t->state = TOSTHREAD_STATE_INACTIVE;
t->init_block = current_thread->init_block;
+ call BitArrayUtils.clrArray(t->joinedOnMe, sizeof(t->joinedOnMe));
PREPARE_THREAD(t, threadWrapper);
return SUCCESS;
}
atomic {
thread_t* t = (call ThreadInfo.get[id]());
if(t->state == TOSTHREAD_STATE_INACTIVE) {
- num_started_threads++;
- if(num_started_threads == 2)
- call PreemptionAlarm.startOneShot(TOSTHREAD_PREEMPTION_PERIOD);
+ num_runnable_threads++;
+ #ifdef TOSTHREADS_TIMER_OPTIMIZATION
+ post alarmTask();
+ #else
+ if(num_runnable_threads == 2)
+ call PreemptionAlarm.startOneShot(TOSTHREAD_PREEMPTION_PERIOD);
+ #endif
t->state = TOSTHREAD_STATE_READY;
call ThreadQueue.enqueue(&ready_queue, t);
return SUCCESS;
atomic {
if(current_thread->state == TOSTHREAD_STATE_ACTIVE) {
current_thread->state = TOSTHREAD_STATE_READY;
- call ThreadQueue.enqueue(&ready_queue, current_thread);
+ if(current_thread != tos_thread)
+ call ThreadQueue.enqueue(&ready_queue, current_thread);
interrupt(current_thread);
return SUCCESS;
}
}
}
+ async command error_t ThreadScheduler.joinThread(thread_id_t id) {
+ thread_t* t = call ThreadInfo.get[id]();
+ atomic {
+ if(current_thread == tos_thread)
+ return FAIL;
+ if (t->state != TOSTHREAD_STATE_INACTIVE) {
+ call BitArrayUtils.setBit(t->joinedOnMe, current_thread->id);
+ call ThreadScheduler.suspendCurrentThread();
+ return SUCCESS;
+ }
+ }
+ return EALREADY;
+ }
+
async command error_t ThreadScheduler.wakeupThread(uint8_t id) {
thread_t* t = call ThreadInfo.get[id]();
if((t->state) == TOSTHREAD_STATE_SUSPENDED) {
t->state = TOSTHREAD_STATE_READY;
- call ThreadQueue.enqueue(&ready_queue, call ThreadInfo.get[id]());
+ if(t != tos_thread) {
+ call ThreadQueue.enqueue(&ready_queue, call ThreadInfo.get[id]());
+ #ifdef TOSTHREADS_TIMER_OPTIMIZATION
+ atomic num_runnable_threads++;
+ post alarmTask();
+ #endif
+ }
return SUCCESS;
}
return FAIL;
return NULL;
}
}
-