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
_______________________________________________
Tinyos-help mailing list
[email protected]
https://mail.millennium.berkeley.edu/cgi-bin/mailman/listinfo/tinyos-help