]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - doc/txt/tep106.txt
RC4 fixes for Epic support
[tinyos-2.x.git] / doc / txt / tep106.txt
index 11df5a8cf68ffa9e0f012fa988136cdbff6e4a18..28bf8d431331243da85159d0aa03faa8e3beb9d0 100644 (file)
@@ -5,15 +5,10 @@ Schedulers and Tasks
 :TEP: 106
 :Group: Core Working Group 
 :Type: Documentary
-:Status: Draft
+:Status: Final
 :TinyOS-Version: 2.x
 :Author: Philip Levis and Cory Sharp
 
-:Draft-Created: 10-Dec-2004
-:Draft-Version: $Revision$
-:Draft-Modified: $Date$
-:Draft-Discuss: TinyOS Developer List <tinyos-devel at mail.millennium.berkeley.edu>
-
 .. Note::
 
    This memo documents a part of TinyOS for the TinyOS Community, and
@@ -178,9 +173,8 @@ to take an integer parameter could look like this::
 Using this task interface, a component could post a task with a
 ``uint16_t`` parameter. When the scheduler runs the task, it will
 signal the ``runTask`` event with the passed parameter, which contains
-the task's logic. Note, however, that this does not save any RAM: if
-anything, it will cost RAM as space must be allocated in the scheduler
-and may then also be allocated in the component. Furthermore, as
+the task's logic. Note, however, that this does not save any RAM: 
+the scheduler must have RAM allocated for the parameter.  Furthermore, as
 there can only be one copy of a task outstanding at any time, it
 is just as simple to store the variable in the component. E.g.,
 rather than::
@@ -241,7 +235,8 @@ For example, the standard TinyOS scheduler has this signature::
 
 A scheduler MUST provide a parameterized TaskBasic interface.
 If a call to TaskBasic.postTask() returns SUCCESS, the scheduler MUST run it
-eventually. The scheduler MUST return SUCCESS to a TaskBasic.postTask()
+eventually, so that starvation is not a concern. The scheduler MUST 
+return SUCCESS to a TaskBasic.postTask()
 operation unless it is not the first call to TaskBasic.postTask() since
 that task's TaskBasic.runTask() event has been signaled. The 
 McuSleep interface is used for microcontroller power management;
@@ -270,6 +265,11 @@ runNextTask(TRUE) always return TRUE.   The taskLoop() command tells
 the scheduler to enter an infinite task-running loop, putting the MCU
 into a low power state when the processor is idle: it never returns.
 
+The scheduler is repsonsible for putting the processor to sleep
+predominantly for efficiency reasons. Including the sleep call
+within the scheduler improves the efficiency of the task loop,
+in terms of the assembly generated by the TinyOS toolchain. 
+
 This is the TaskBasic interface::
 
   interface TaskBasic {  
@@ -277,7 +277,7 @@ This is the TaskBasic interface::
     void event runTask();  
   }  
 
-When a component declares a task with the   task   keyword in nesC, it
+When a component declares a task with the ``task`` keyword in nesC, it
 is implicitly declaring that it uses an instance of the TaskBasic
 interface: the task body is the runTask event. When a component uses the
 ``post`` keyword, it calls the postTask command. Each TaskBasic MUST be
@@ -292,6 +292,10 @@ entries. When TinyOS tells the scheduler to run a task, it pulls the
 next identifier off the queue and uses it to dispatch on the
 parameterized TaskBasic interface.
 
+While the default TinyOS scheduler uses a FIFO policy, TinyOS
+components MUST NOT assume a FIFO policy. If two tasks must run
+in a particular temporal order, this order should be enforced by
+the earlier task posting the later task.
 
 5. Replacing the Scheduler
 ====================================================================
@@ -305,11 +309,11 @@ To replace the scheduler for a particular application, a developer
 SHOULD put a configuration named TinySchedulerC in the application
 directory: this will replace the default. The scheduler component
 provides a wire-through of the desired scheduler implementation. All
-scheduler implementations SHOULD provide a parameterize TaskBasic
+scheduler implementations MUST provide a parameterize TaskBasic
 interface, as SchedulerBasicP does; this supports nesC post statements
-and task declarations. If a scheduler does not provide the TaskBasic
-interface, compiling applications requires modifying the standard
-ncc scheduler parameters (as described in Appendix A). All scheduler 
+and task declarations and enables TinyOS core systems to operate
+properly. Generally, TinyOS core code needs to be able to run unchanged
+with new scheduler implementations.  All scheduler 
 implementations MUST provide the Scheduler interface.
 
 For example, imagine a hypothetical scheduler that provides earliest
@@ -350,16 +354,21 @@ For a module to have an earliest deadline first task, it uses the
 TaskEdf interface. Its configuration SHOULD wire it to TinySchedulerC.
 The key used for task unique identifiers MUST be "TinySchedulerC.TaskInterface",
 where *TaskInterface* is the name of the new task interface as presented
-by the scheduler.  For example, the module SomethingP requires two EDF
-tasks::
+by the scheduler.  A common way to make sure a consistent string is used
+is to #define it. For example, TaskEdf.nc might include::
+
+#define UQ_TASK_EDF "TinySchedulerC.TaskEdf"
 
+In this example, the module SomethingP requires two EDF
+tasks::
+  
   configuration SomethingC {  
     ...  
   }  
   implementation {  
     components SomethingP, TinySchedulerC;  
-    SomethingP.SendTask -> TinySchedulerC.TaskEdf["TinySchedulerC.TaskEdf"];  
-    SomethingP.SenseTask -> TinySchedulerC.TaskEdf["TinySchedulerC.TaskEdf"];  
+    SomethingP.SendTask -> TinySchedulerC.TaskEdf[unique(UQ_TASK_EDF)];  
+    SomethingP.SenseTask -> TinySchedulerC.TaskEdf[unique(UQ_TASK_EDF)];  
   }  
 
 The module SomethingP also has a basic task. The nesC compiler
@@ -387,11 +396,18 @@ implementation of SomethingP that uses keywords for basic tasks::
     }  
   }  
 
+The requirement that basic tasks not be subject to starvation
+requires that a scheduler supporting EDF tasks must ensure that
+basic tasks run eventually even if there is an unending stream of
+short deadline tasks to run. Quantifying "eventually" is difficult,
+but a 1% share of the MCU cycles (or invocations) is a reasonable 
+approximation. 
+
 If the scheduler provides two instances of the same task interface,
 their unique keys are based on the name of the interface as the 
 scheduler presents it (the "as" keyword). For example, imagine
 a scheduler which provides two instances of TaskBasic: standard
-tasks and high-priority tasks. The scheduler always selects a task
+tasks and high-priority tasks. The scheduler usually selects a task
 for the high priority queue before the standard queue::
 
   configuration TinySchedulerC {  
@@ -400,8 +416,9 @@ for the high priority queue before the standard queue::
     provides interface TaskBasic[uint8_t taskID] as TaskHighPriority;  
   }  
 
-A component that uses a high priority task would then wire to
-TaskHighPriority with the key "TinySchedulerC.TaskHighPriority"::
+It cannot always select a high priority task because that could
+starve basic tasks.  A component that uses a high priority task would 
+wire to TaskHighPriority with the key "TinySchedulerC.TaskHighPriority"::
 
   configuration SomethingElseC {}  
   implementation {