]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/tosthreads/system/TinyThreadSchedulerP.nc
Merge TinyOS 2.1.1 into master.
[tinyos-2.x.git] / tos / lib / tosthreads / system / TinyThreadSchedulerP.nc
index 1ae67708558488bad103d2c6760a5a5d2dd75864..8466a9821513ef86e4987f450682b956b9b1322d 100644 (file)
@@ -32,7 +32,7 @@
 /**
  * @author Kevin Klues <klueska@cs.stanford.edu>
  */
+  
 module TinyThreadSchedulerP {
   provides {
     interface ThreadScheduler;
@@ -43,6 +43,7 @@ module TinyThreadSchedulerP {
     interface Boot as ThreadSchedulerBoot;
     interface ThreadInfo[uint8_t id];
     interface ThreadQueue;
+    interface BitArrayUtils;
     interface McuSleep;
     interface Leds;
     interface Timer<TMilli> as PreemptionAlarm;
@@ -56,10 +57,19 @@ implementation {
   //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 
@@ -88,7 +98,7 @@ implementation {
     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();
     }
   }
@@ -100,7 +110,7 @@ implementation {
    */
   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);
 
@@ -128,22 +138,48 @@ implementation {
   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
    */
@@ -163,7 +199,7 @@ implementation {
   } 
   
   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);
@@ -178,6 +214,7 @@ implementation {
     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;
   }
@@ -186,9 +223,13 @@ implementation {
     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;
@@ -224,7 +265,8 @@ implementation {
     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;
       }
@@ -232,11 +274,31 @@ implementation {
     }
   }
   
+  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;
@@ -267,4 +329,3 @@ implementation {
     return NULL;
   }
 }
-