]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - doc/html/tutorial/lesson2.html
Merge devel code into the trunk.
[tinyos-2.x.git] / doc / html / tutorial / lesson2.html
diff --git a/doc/html/tutorial/lesson2.html b/doc/html/tutorial/lesson2.html
new file mode 100644 (file)
index 0000000..f418209
--- /dev/null
@@ -0,0 +1,779 @@
+<html>
+    <head>
+      <title>TinyOS Tutorial Lesson 2: Modules and the TinyOS Execution Model</title>
+      <link href="../../stylesheets/tutorial.css" rel="stylesheet" type="text/css">
+  </head>
+  <body>
+    
+    <div class="title">Lesson 2: Modules and the TinyOS Execution Model</div>
+    <div class="subtitle">Last updated June 27 2006</div>
+    
+    <p>This lesson introduces nesC modules, commands, events, and
+      tasks. It explains the TinyOS execution model.</p>
+    
+    <h1>Modules and State</h1>
+    
+    <p>Compiling TinyOS applications produces a single binary image that assumes
+      it has complete control of the hardware. Therefore, a mote only
+      runs one TinyOS image at a time. An image consists of the
+      components needed for a single application. As most more platforms
+      do not have hardware-based memory protection, there is
+      no seperation between a "user" address space and a "system"
+      address space; there is only one address space that all
+      components share. This is why many TinyOS components try to keep
+      their state private and avoid passing pointers: since there is
+      no hardware protection, the best way to keep memory uncorrupted
+      is to share it as little as possible.</p>
+    
+    <p>Recall from lesson 1 that the set of interfaces a component uses
+      and provides
+      define its signature. Both kinds of components -- configurations and
+      modules -- provide and use interfaces. The difference between the
+      two lies in their implementation: configurations are implemented
+      in terms of other components, which they wire, while modules
+      are executable code. After unwrapping all of the layers of abstraction
+      that configurations introduce, modules always lie within. Module
+      implementations are for the most part written in C, with
+      some extra constructions for nesC abstractions.</p>
+
+    <p>Modules can declare state variables. Any state a component declares
+      is private: no
+      other component can name it or directly access it. The only
+      way two components can directly interact is through interfaces.
+      Let's revisit the Blink application.
+      Here is the Blink module BlinkC's implementation in
+      its entirety:</p>
+
+<pre></pre>
+<prehead>apps/Blink/BlinkC.nc:</prehead>
+<pre>
+module BlinkC {
+  uses interface Timer&lt;TMilli&gt; as Timer0;
+  uses interface Timer&lt;TMilli&gt; as Timer1;
+  uses interface Timer&lt;TMilli&gt; as Timer2;
+  uses interface Leds;
+  uses interface Boot;
+}
+implementation
+{
+  event void Boot.booted()
+  {
+    call Timer0.startPeriodic( 250 );
+    call Timer1.startPeriodic( 500 );
+    call Timer2.startPeriodic( 1000 );
+  }
+
+  event void Timer0.fired()
+  {
+    call Leds.led0Toggle();
+  }
+  
+  event void Timer1.fired()
+  {
+    call Leds.led1Toggle();
+  }
+  
+  event void Timer2.fired()
+  {
+    call Leds.led2Toggle();
+  }
+}
+</pre>
+
+    <p>BlinkC does not allocate any state. Let's change it so that its
+      logic is a little different: rather than blink the LEDs from three
+      different timers, we'll blink them with a single timer and keep
+      some state to know which ones to toggle. Make a copy of the Blink
+      application, <tt>BlinkSingle</tt>, and go into its directory.</p>
+
+    <pre>
+$ cd tinyos-2.x/apps
+$ cp -R Blink BlinkSingle
+$ cd BlinkSingle
+    </pre>
+
+    <p>Open the BlinkC module in an editor.
+      The first step is to comment out the LED toggles in Timer1 and
+      Timer2:</p>
+
+    <pre>
+  event void Timer1.fired()
+  {
+    // call Leds.led1Toggle();
+  }
+  
+  event void Timer2.fired()
+  {
+    // call Leds.led2Toggle();
+  }
+    </pre>
+
+    <p>The next step is to add some state to BlinkC, a single byte. Just
+      like in C, variables and functions must be declared before they are
+      used, so put it at the beginning of the implementation:</p>
+
+    <pre>
+implementation
+{
+
+  uint8_t counter = 0;
+
+  event void Boot.booted()
+  {
+    call Timer0.startPeriodic( 250 );
+    call Timer1.startPeriodic( 500 );
+    call Timer2.startPeriodic( 1000 );
+  }
+    </pre>
+
+    <p>Rather than the standard C names of <tt>int</tt>, <tt>long</tt>,
+      or <tt>char</tt>, TinyOS code uses more explicit types, which
+      declare their size. In reality, these map to the basic C types, but
+      do so differently for different platforms. TinyOS code avoids using
+      <tt>int</tt>, for example, because it is platform-specific. For example,
+      on mica and Telos motes, <tt>int</tt> is 16 bits, while on the
+      IntelMote2, it is 32 bits. Additionally, TinyOS code often
+      uses unsigned values heavily, as wrap-arounds to negative numbers
+      can often lead to very unintended consequences. The commonly used
+      types are:</p>
+
+    <CENTER>
+      <table border=1 cellpadding=6>
+       <tr>
+         <td></td><td>8 bits</td><td>16 bits</td><td>32 bits</td><td>64 bits</td>
+       </tr>
+       <tr>
+         <td>signed</td><td><tt>int8_t</tt></td><td><tt>int16_t</tt></td><td><tt>int32_t</tt></td><td><tt>int64_t</tt></td>
+       </tr>
+       <tr>
+         <td>unsigned</td><td><tt>uint8_t</td><td><tt>uint16_t</td><td><tt>uint32_t</td><td><tt>uint64_t</tt></td>
+       </tr>
+      </table>
+    </CENTER>
+      <p>There is also a <tt>bool</tt> type. You can use the standard C
+       types, but doing so might raise cross-platform issues. Also,
+       <tt>uint32_t</tt> is often easier to write than <tt>unsigned
+         long</tt>. Most platforms support floating point numbers
+      (<tt>float</tt> almost always, <tt>double</tt> sometimes),
+       although their arithmetic is in software rather than hardware.</p>
+
+      <p>Returning to our modified BlinkC, we've allocated a single unsigned
+       byte, <tt>counter</tt>. When the mote boots, the <tt>counter</tt>
+       will be initialized to zero. The next step is to make it that
+       when Timer0 fires, it increments <tt>counter</tt> and displays the
+       result:</p>
+
+      <pre>
+  event void Timer0.fired()
+  {
+    counter++;
+    if (counter & 0x1) {
+      call Leds.led0On();
+    }
+    else {
+      call Leds.led0Off();
+    }
+    if (counter & 0x2) {
+      call Leds.led2On();
+    }
+    else {
+      call Leds.led2Off();
+    }
+    if (counter & 0x4) {
+      call Leds.led2On();
+    }
+    else {
+      call Leds.led2Off();
+    }
+  }
+      </pre>
+
+      <p>Another, more succinct way to do it is to use the <tt>set</tt>
+       command:</p>
+
+      <pre>
+  event void Timer0.fired()
+  {
+    counter++;
+    call Leds.set(counter);
+  }
+      </pre>
+
+      <p>Compile your program and install it on a mote. You'll see
+       that it behaves just as before, except that now the LEDs
+       are being driven by a single, rather than three, timers.</p>
+
+      <p>As only one timer is being used, this means that you don't need
+       Timer1 and Timer2: they waste CPU resources and memory. Open
+       BlinkC again and remove them from its signature and implementation.
+       You should have something that looks like this:</p>
+
+      <pre>
+module BlinkC {
+  uses interface Timer&lt;TMilli&gt; as Timer0;
+  uses interface Leds;
+  users interface Boot;
+}
+implementation
+{
+  uint8_t counter = 0;
+
+  event void Boot.booted()
+  {
+    call Timer0.startPeriodic( 250 );
+  }
+
+  event void Timer0.fired()
+  {
+    counter++;
+    call Leds.set(counter);
+  }
+  
+}
+      </pre>
+       
+      <p>Try to compile the application: nesC will throw an error, because
+       the configuration BlinkAppC is wiring to interfaces on BlinkC
+       that no longer exist (Timer1 and Timer2):</p>
+
+      <pre>
+dark /root/src/tinyos-2.x/apps/BlinkSingle -5-> make micaz
+mkdir -p build/micaz
+    compiling BlinkAppC to a micaz binary
+ncc -o build/micaz/main.exe -Os -finline-limit=100000 -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb  -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/micaz/wiring-check.xml BlinkAppC.nc -lm 
+In component `BlinkAppC':
+BlinkAppC.nc:54: cannot find `Timer1'
+BlinkAppC.nc:55: cannot find `Timer2'
+make: *** [exe0] Error 1
+      </pre>
+
+      <p>Open BlinkAppC and remove the two Timers and their wirings. Compile
+       the application:</p>
+
+      <pre>
+mkdir -p build/micaz
+    compiling BlinkAppC to a micaz binary
+ncc -o build/micaz/main.exe -Os -finline-limit=100000 -Wall -Wshadow -DDEF_TOS_AM_GROUP=0x7d -Wnesc-all -target=micaz -fnesc-cfile=build/micaz/app.c -board=micasb  -fnesc-dump=wiring -fnesc-dump='interfaces(!abstract())' -fnesc-dump='referenced(interfacedefs, components)' -fnesc-dumpfile=build/micaz/wiring-check.xml BlinkAppC.nc -lm 
+    compiled BlinkAppC to build/micaz/main.exe
+            2428 bytes in ROM
+              39 bytes in RAM
+avr-objcopy --output-target=srec build/micaz/main.exe build/micaz/main.srec
+avr-objcopy --output-target=ihex build/micaz/main.exe build/micaz/main.ihex
+    writing TOS image
+      </pre>
+
+      <p>If you compare the ROM and RAM sizes with the unmodified Blink
+       application, you should see that they are a bit smaller: TinyOS
+       is only allocating state for a single timer, and there is
+       event code for only one timer.</p>
+
+      <h1>Interfaces, Commands, and Events</h1>
+      
+      <p>Go back to <tt>tinyos-2.x/apps/Blink</tt>.
+      In lesson 1 we learned that if a component uses an interface, it can
+       call the interface's commands and must implement handlers for its
+       events.  We also saw that the BlinkC component uses the Timer, Leds,
+       and Boot interfaces. 
+       Let's take a look at those interfaces:</p>
+
+<pre></pre>
+<prehead>tos/interfaces/Boot.nc:</prehead>
+<pre>
+interface Boot {
+  event void booted();
+}
+</pre>
+
+<prehead>tos/interfaces/Leds.nc:</prehead>
+<pre>
+interface Leds {
+
+  /**
+   * Turn LED n on, off, or toggle its present state.
+   */
+  async command void led0On();
+  async command void led0Off();
+  async command void led0Toggle();
+
+  async command void led1On();
+  async command void led1Off();
+  async command void led1Toggle();
+
+  async command void led2On();
+  async command void led2Off();
+  async command void led2Toggle();
+
+  /**
+   * Get/Set the current LED settings as a bitmask. Each bit corresponds to
+   * whether an LED is on; bit 0 is LED 0, bit 1 is LED 1, etc. 
+   */
+  async command uint8_t get();
+  async command void set(uint8_t val);
+  
+}
+</pre>
+
+<prehead>tos/interfaces/Timer.nc:</prehead>
+<pre>
+interface Timer<precision_tag>
+{
+  // basic interface
+  command void startPeriodic( uint32_t dt );
+  command void startOneShot( uint32_t dt );
+  command void stop();
+  event void fired();
+
+  // extended interface omitted (all commands)
+}
+</pre>
+
+    <p>Looking over the interfaces for <code>Boot</code>,
+      <code>Leds</code>, and
+      <code>Timer</code>, we can see that since <code>BlinkC</code> uses
+      those interfaces it must implement handlers for the
+      <code>Boot.booted()</code> event, and the <code>Timer.fired()</code>
+      event. The <code>Leds</code> interface signature does not include any
+      events, so <code>BlinkC</code> need not implement any in order
+      to call the Leds commands. Here, again, is <code>BlinkC</code>'s
+      implementation of <code>Boot.booted()</code>:</p>
+    
+<pre></pre>
+<prehead>apps/Blink/BlinkC.nc:</prehead>
+<pre>
+  event void Boot.booted()
+  {
+    call Timer0.startPeriodic( 250 );
+    call Timer1.startPeriodic( 500 );
+    call Timer2.startPeriodic( 1000 );
+  }
+</pre>
+
+    <p><code>BlinkC</code> uses 3 instances of the TimerMilliC component,
+      wired to the interfaces <code>Timer0</code>, <code>Timer1</code>, and
+      <code>Timer2</code>. The <code>Boot.booted()</code> event handler
+      starts each instance. The parameter to
+      <code>startPeriodic()</code> specifies the period in milliseconds after 
+      which the timer will fire (it's millseconds because of the
+      <tt>&lt;TMilli&gt;</tt> in the interface).
+      Because the timer is started using
+      the <code>startPeriodic()</code> 
+      command, the timer will be reset after firing such that the
+      <code>fired()</code> event is 
+      triggered every n milliseconds.</p>
+
+    <p>Invoking an interface command requires the <tt>call</tt> keyword,
+      and invoking an interface event requires the <tt>signal</tt> keyword.
+      BlinkC does not provide any interfaces, so its code
+      does not have any signal statements: in a later lesson,
+      we'll look at the boot sequence, which signals the Boot.booted()
+      event.</p>
+    
+    <p>Next, look at the implementation of the <code>Timer.fired()</code>:</p>
+
+<pre></pre>
+<prehead>apps/Blink/BlinkC.nc:</prehead>
+<pre>
+  event void Timer0.fired()
+  {
+    call Leds.led0Toggle();
+  }
+  
+  event void Timer1.fired()
+  {
+    call Leds.led1Toggle();
+  }
+  
+  event void Timer2.fired()
+  {
+    call Leds.led2Toggle();
+  }
+}
+</pre>
+       
+    <p>Because it uses three instances of the Timer interface,
+      <code>BlinkC</code> 
+      must implement three instances of <code>Timer.fired()</code>
+      event. When implementing or invoking an interface function, the
+      function name is always <i>interface</i>.<i>function</i>. As
+      BlinkC's three Timer instances are named <tt>Timer0</tt>,
+      <tt>Timer1</tt>, and <tt>Timer2</tt>, it implements the three
+      functions <tt>Timer0.fired</tt>, <tt>Timer1.fired</tt>, and
+      <tt>Timer2.fired</tt>.</p>
+    
+    
+    
+    <h1>TinyOS Execution Model: Tasks</h1>
+    
+    <p>All of the code we've looked at so far is <i>synchronous</i>.
+      It runs in a single execution context and does not have
+      any kind of pre-emption. That is, when synchronous (sync) code
+      starts running, it does not relinquish the CPU to other
+      sync code until it completes. This simple mechanism allows
+      the TinyOS scheduler to minimize its RAM consumption and
+      keeps sync code very simple. However, it means that if one
+      piece of sync code runs for a long time, it prevents other
+      sync code from running, which can adversely affect system
+      responsiveness. For example, a long-running piece of code
+      can increase the time it takes for a mote to respond to a
+      packet.</p>
+    
+    <p>So far, all of the examples we've looked at have been
+      direct function calls. System components, such as the
+         boot sequence or timers, signal events to a component,
+         which takes some action (perhaps calling a command) and
+         returns. In most cases, this programming approach works
+         well. Because sync code is non-preemptive, however,
+         this approach does not work well for large computations.
+         A component needs to be able to split a large computation
+         into smaller parts, which can be executed one at a time.
+         Also, there are times when a component needs to do something,
+         but it's fine to do it a little later. Giving TinyOS the
+         ability to defer the computation until later can let it
+         deal with everything else that's waiting first.</p>
+
+       <p><b>Tasks</b> enable components to perform general-purpose
+         "background" processing in an application. A task is a function
+         which a component tells TinyOS to run later, rather than now.
+         The closest analogies in traditonal operating systems are
+         <A HREF="http://www.tldp.org/LDP/tlk/kernel/kernel.html">interrupt
+           bottom halves</A> and <A HREF="http://opensource.adobe.com/twiki/bin/view/AdobeSource/DeferredProcSystem">deferred
+           procedure calls</A>.</p>
+
+       <p>Make a copy of the Blink application, and call it BlinkTask:</p>
+
+       <pre>
+$ cd tinyos-2.x/apps
+$ cp -R Blink BlinkTask
+$ cd BlinkTask
+       </pre>
+
+       <p>Open <code>BlinkC.nc</code>. Currently, the event handler
+         for <code>Timer0.fired()</code> is:</p>
+
+       <pre>
+event void Timer0.fired() {
+  dbg("BlinkC", "Timer 0 fired @ %s\n", sim_time_string());
+  call Leds.led0Toggle();
+}
+       </pre>
+
+       <p>Let's change it so that it does a bit of work, enough that
+         we'll be able to see how long it runs. In terms of a mote,
+         the rate at which we can see things (about 24 Hz, or 40 ms)
+         is <u>slow</u>: the micaZ and Telos can send about 20 packets
+         in that time. So this example is really exaggerated, but it's
+         also simple enough that you can observe it with the naked eye.
+         Change the handler to be this:</p>
+
+       <pre>
+event void Timer0.fired() {
+  uint32_t i;
+  dbg("BlinkC", "Timer 0 fired @ %s\n", sim_time_string());
+  for (i = 0; i < 400001; i++) {
+    call Leds.led0Toggle();
+  }
+}
+       </pre>
+        
+    <p>This will cause the timer to toggle 400,001 times, rather
+      than once. Because the number is odd, it will have the end
+      result of a single toggle, with a bit of flickering in-between.
+      Compile and install the program. You'll see that
+      Led 0 introduces so much latency in the Led 1 and Led 2
+      toggles that you never see a situation where only one is on.
+      On TelosB motes, this long running task can cause the Timer stack
+      to completely skip events (try setting the count to 200,001 or 100,001).
+    </p>
+
+    <p>The problem is that this computation is interfering with the timer's
+      operation. What we'd like to do is tell TinyOS to execute the computation
+      later. We can accomplish this with a <b>task</b>.</p>
+
+    <p>A task is declared in your implementation module using the syntax
+    <pre>&nbsp; task void taskname() { ... }</pre> where
+    <tt>taskname()</tt> is whatever symbolic name you want to assign to the
+    task. Tasks must return <tt>void</tt> and may not take any
+    arguments. To dispatch a task for (later) execution, use the syntax
+    <pre>&nbsp; post taskname();</pre> A component can post a task in a
+    command, an event, or a task.  Because they are the root of a call
+    graph, a tasks can safely both call commands and signal events. We will
+    see later that, by convention, commands do not signal events to avoid
+    creating recursive loops across component boundaries (e.g., if command
+    X in component 1 signals event Y in component 2, which itself calls
+    command X in component 1). These loops would be hard for the programmer to
+    detect (as they depend on how the application is wired) and would lead to
+    large stack usage.</p>
+
+
+    <p>Modify BlinkC to perform the loop in a task:</p>
+
+    <pre>
+task void computeTask() {
+  uint32_t i;
+  for (i = 0; i < 400001; i++) {}
+}
+
+event void Timer0.fired() {
+  call Leds.led0Toggle();
+  post computeTask();
+}
+    </pre>
+
+    <p>Telos platforms will still struggle, but mica platforms will
+      operate OK.</p>
+
+    
+    <p>The <tt>post</tt> operation places the task on an internal
+      <b>task queue</b> which is processed in FIFO order. When a
+      task is executed, it runs to completion
+      before the next task is run. Therefore, and as the above examples
+      showed, a task should not run for long periods of time.
+      Tasks do not preempt each
+      other, but a task can  be preempted by a hardware interrupts (which
+      we haven't seen yet).
+      If you need to run a series of long operations,
+      you should dispatch a separate task for each operation, rather
+      than using one big task. The <tt>post</tt> operation returns
+      an <tt>error_t</tt>, whose value is either <tt>SUCCESS</tt>
+      or <tt>FAIL</tt>. A post fails if and only if the task is
+      already pending to run (it has been posted successfully and has not been invoked yet).(<A HREF="#task_footnote">1</A>)</p>
+
+    <p>For example, try this:</p>
+
+    <pre>
+uint32_t i;
+
+task void computeTask() {
+  uint32_t start = i;
+  for (;i < start + 10000 && i < 400001; i++) {}
+  if (i >= 400000) {
+    i = 0;
+  }
+  else {
+    post computeTask();
+  }
+}
+    </pre>
+
+    <p>This code breaks the compute task up into many smaller tasks.
+      Each invocation of computeTask runs through 10,000 iterations of
+      the  loop. If it hasn't completed all 400,001 iterations, it reposts
+      itself. Compile this code and run it; it will run fine on both
+      Telos and mica-family motes.</p>
+
+    <p>Note that using a task in this way required including another
+      variable (<tt>i</tt>) in the component. Because computeTask()
+      returns after 10,000 iterations, it needs somewhere to store
+      its state for the next invocation. In this situation, <tt>i</tt>
+      is acting as a static function variable often does in C. However,
+      as nesC component state is completely private, using the
+      <tt>static</tt> keyword to limit naming scope is not as useful.
+      This code, for example, is equivalent:</p>
+    <pre>
+task void computeTask() {
+  static uint32_t i;
+  uint32_t start = i;
+  for (;i < start + 10000 && i < 400001; i++) {}
+  if (i >= 400000) {
+    i = 0;
+  }
+  else {
+    post computeTask();
+  }
+}
+    </pre>
+
+    <h1>Internal Functions</h1>
+
+    <p>Commands and events are the only way that a function in a component
+      can be made callable by another component. There are situations
+      when a component wants private functions for its own internal
+      use. A component can define standard C functions, which other
+      components cannot name and therefore cannot invoke directly. 
+      While these functions do not have the <tt>command</tt> or <tt>event</tt>
+      modifier, they can freely call commands or signal events. For example,
+      this is perfectly reasonable nesC code:</p>
+
+    <pre>
+module BlinkC {
+  uses interface Timer&lt;TMilli&gt; as Timer0;
+  uses interface Timer&lt;TMilli&gt; as Timer1;
+  uses interface Timer&lt;TMilli&gt; as Timer2;
+  uses interface Leds;
+  uses interface Boot;
+}
+implementation
+{
+
+  void startTimers() {
+    call Timer0.startPeriodic( 250 );
+    call Timer1.startPeriodic( 500 );
+    call Timer2.startPeriodic( 1000 );
+  }
+
+  event void Boot.booted()
+  {
+    startTimers();
+  }
+
+  event void Timer0.fired()
+  {
+    call Leds.led0Toggle();
+  }
+  
+  event void Timer1.fired()
+  {
+    call Leds.led1Toggle();
+  }
+  
+  event void Timer2.fired()
+  {
+    call Leds.led2Toggle();
+  }
+}
+    </pre>
+    
+    <p>Internal functions act just like C functions: they don't need the <tt>
+       call</tt> or <tt>signal</tt> keywords.</p>
+
+    <h1>Split-Phase Operations</h1>
+
+    <p>Because nesC interfaces are wired at compile time,
+      callbacks (events) in TinyOS are very efficient. In most
+      C-like languages, callbacks have to be registered at run-time
+      with a function pointer. This can prevent the compiler from
+      being able to optimize code across callback call paths. Since
+      they are wired statically in nesC, the compiler knows exactly
+      what functions are called where and can optimize heavily.</p>
+
+    <p>The ability to optimize across component boundaries is
+      very important in TinyOS, because it has no blocking operations.
+      Instead, every long-running operation is <b>split-phase</b>.
+      In a blocking system, when a program calls a long-running operation,
+      the call does not return until the operation is complete: the program
+      blocks. In a split-phase system, when a program calls a long-running
+      operation, the call returns immediately, and the called abstraction
+      issues a callback when it completes. This approach is called
+      split-phase because it splits invocation and completion into two
+      separate phases of execution. Here is a simple example of the
+      difference between the two:</p>
+
+<center>
+    <table>
+      <tr><td align=center>Blocking</td> <td align=center>Split-Phase</td></tr>
+      <tr>
+        <td valign=top>
+<pre>
+if (send() == SUCCESS) {
+  sendCount++;
+}
+</pre>
+</td>
+        <td valign=top>
+<pre>
+// start phase
+send(); 
+
+//completion phase
+void sendDone(error_t err) {
+  if (err == SUCCESS) {
+    sendCount++;
+  }
+}
+</pre>
+</td>
+      </tr>
+    </table>
+</center>
+
+    <p>Split-phase code is often a bit more verbose and complex than
+     sequential code. But it has several advantages. First, split-phase
+     calls do not tie up stack memory while they are executing. Second,
+     they keep the system reponsive: there is never a situation when
+     an application needs to take an action but all of its threads are
+     tied up in blocking calls. Third, it tends to reduce stack
+     utilization, as creating large variables on the stack is rarely
+     necessary.</p>
+
+    <p>Split-phase interfaces enable a TinyOS component to easily start
+      several operations at once and have them execute in parallel.
+      Also, split-phase operations can save memory. This is because
+      when a program calls a blocking operation, all of the state it
+      has stored on the call stack (e.g., variables declared in functions)
+      have to be saved. As determining the exact size of the stack is
+      difficult, operating systems often choose a very conservative
+      and therefore large size.  Of course, if there is data that 
+      has to be kept across the 
+      call, split-phase operations still need to save it.</p>
+
+    <p>The command <tt>Timer.startOneShot</tt> is an example of
+     a split-phase call. The user of the Timer inteface calls the command,
+     which returns immediately. Some time later (specified by the
+     argument), the component providing Timer signals <tt>Timer.fired</tt>.
+     In a system with blocking calls, a program might use <tt>sleep()</tt>:
+
+     <center>
+       <table>
+         <tr>
+           <td align=center>Blocking</td><td align=center>Split-phase</td>
+         </tr>
+         <tr>
+           <td valign=top>
+             <pre>
+state = WAITING;
+op1();
+sleep(500);
+op2();
+state = RUNNING
+             </pre>
+           </td>
+           <td valign=top>
+             <pre>
+state = WAITING;
+op1();
+call Timer.startOneShot(500);
+
+command void Timer.fired() {
+  op2();
+  state = RUNNING;
+}
+             </pre>
+           </td>
+         </tr>
+       </table>
+     </center> 
+
+<p>In the next lesson, we'll look at one of the most basic
+split-phase operations: sending packets.</p>
+
+<a name=#related_docs>
+<h1>Related Documentation</h1>
+</a>
+<ul>
+<li> <a href="../tep107.html">TEP 102: Timers</a>
+<li> <a href="../tep106.html">TEP 106: Schedulers and Tasks</a>
+</ul>
+
+<p>
+<hr>
+
+<p><a name="task_footnote">(1)</a> The task semantics have changed
+significantly from tinyos-2.x. In 1.x, a task could be posted more
+than once and a post could fail if the task queue were full. In 2.x, a
+basic post will only fail if that task has already been posted and has
+not started execution. So a task can always run, but can only have one
+outstanding post at any time. If a component needs to post task
+several times, then the end of the task logic can repost itself as
+need be.
+
+
+<!-- Begin footer -->
+<br>
+<hr>
+<center>
+<p>&lt;&nbsp;<b><a href="lesson1.html">Previous Lesson</a></b> |&nbsp; <b><a
+ href="index.html">Top</a></b> &nbsp;|&nbsp; <b><a href="lesson3.html">Next Lesson </a>&nbsp;&gt;</b>
+</center>
+
+</body>
+</html>