[Tinyos-help] async/sync events preemption

Philip Levis pal at cs.stanford.edu
Tue Jul 4 10:40:21 PDT 2006


On Jul 3, 2006, at 11:45 PM, Frigging wrote:

> Hi,
> I'm a little bit confused.
> I'm wondering, but:
> 1) only async events can preempt tasks?
> 2) async events can preempt sync commands/events?
> 3) therefore, sync events can't peempt task or other sync commands/ 
> events,
> is it?
> 4) but if a async function can preempt other async function where  
> did handle
> the policy, and where did save the program counter when there's  
> preemption?
> 5) if while interrupt is handling, an other interrupt comes, will  
> it be
> dropped?
>
> Sorry for my silly questions :-(

We run around on this every few months. :)

The basic confusion stems from the fact that the original TinyOS  
paper did not have the sync/async boundary and uses the word "event"  
for two purposes: a TinyOS event (an upcall) and a hardware event (an  
interrupt). Hardware interrupts can preempt tasks.

I find the easiest way to understand it is to just look at main(),  
which goes something like this:

main() {
   // initialize system
   while(1) {
     while(runNextTask()) {}
     sleep();
   }
}

The system is normally sleeping. When an interrupt comes in, it wakes  
up the MCU (the sleep instruction completes), which then checks if  
there are any tasks pending. If not, it goes back to sleep. If there  
are tasks in the queue, it runs them one after the other. They run  
non-preemptively, because the main() loop doesn't run a new one until  
the current one returns. This is why tasks cannot preempt one another.

Interrupts, however, can preempt tasks. All code that an interrupt  
handler calls must be async. The hardware takes care of pushing some  
context on the stack, and the compiler takes care of spilling  
registers to memory. The question of when interrupts can be handled  
or not (interrupt preemption, etc.) depends on 2 things: the chip  
architecture and whether the code has disabled interrupts or adjusted  
the interrupt priority level.

Note, however, that preemption and re-entrancy are different issues.  
This is one reason why there's the guideline of "don't signal events  
from commands." Take this example:

component A {
   busy = FALSE;

   command error_t x() {
      if (busy) {return FAIL;}
      if (call Y.start() == SUCCESS) {
         busy = TRUE;
         return SUCCESS;
      }
   }

   event void Y.done() {
      busy = FALSE;
   }
}

If Y is a truly split-phase interface, this code will work OK. But if  
Y's implementation does this:


   command error_t Y.start() {
     if (z) {
       signal Y.done();
       return SUCCESS;
     }
     // something else
   }

Then when component A calls Y.start, Y.done will be signaled while it  
is still in the statement call Y.start(). This will set busy to be  
FALSE, but then when Y.start returns, component A will set busy to be  
TRUE and the component will never make another request.

The TinyOS programming manual has a discussion of the concurrency model:

http://csl.stanford.edu/~pal/pubs/tinyos-programming.pdf

Phil





More information about the Tinyos-help mailing list