]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/lib/timer/VirtualizeTimerC.nc
mark more modules as safe code
[tinyos-2.x.git] / tos / lib / timer / VirtualizeTimerC.nc
index 8b6bea257a87c623608bbd936b46d9d640a0b359..4f3f109bf5f9f72dd649fbdcfd3a2be74ca27b95 100644 (file)
@@ -32,7 +32,7 @@
  * @author Cory Sharp <cssharp@eecs.berkeley.edu>
  */
 
-generic module VirtualizeTimerC(typedef precision_tag, int max_timers)
+generic module VirtualizeTimerC(typedef precision_tag, int max_timers) @safe()
 {
   provides interface Timer<precision_tag> as Timer[uint8_t num];
   uses interface Timer<precision_tag> as TimerFrom;
@@ -40,10 +40,10 @@ generic module VirtualizeTimerC(typedef precision_tag, int max_timers)
 implementation
 {
   enum
-  {
-    NUM_TIMERS = max_timers,
-    END_OF_LIST = 255,
-  };
+    {
+      NUM_TIMERS = max_timers,
+      END_OF_LIST = 255,
+    };
 
   typedef struct
   {
@@ -55,112 +55,79 @@ implementation
   } Timer_t;
 
   Timer_t m_timers[NUM_TIMERS];
+  bool m_timers_changed;
 
-  enum {
-    /* bitmask */
-    S_TIMER_RUNNING = 1,
-    S_TIMER_CHANGED = 2
-  };
-  bool state;
+  task void updateFromTimer();
 
-  task void executeTimersNow();
-
-  void executeTimers(uint32_t then)
+  void fireTimers(uint32_t now)
   {
-    int32_t min_remaining = (1UL<<31)-1; //max signed int32_t
-    bool min_remaining_isset = FALSE;
-    int num;
-
-    /* We always come here with the timer stopped */
-    state = 0;
-
-    for(num=0; num<NUM_TIMERS; num++)
-    {
-      Timer_t* timer = &m_timers[num];
+    uint8_t num;
 
-      if (timer->isrunning)
+    for (num=0; num<NUM_TIMERS; num++)
       {
-       // Calculate "remaining" before the timer is fired.  If a timer
-       // restarts itself in a fired event, then we 1) need a consistent
-       // "remaining" value to work with, and no worries because 2) all
-       // start commands post executeTimersNow, so the timer will be
-       // recomputed later, anyway.
-
-       uint32_t elapsed = then - timer->t0;
-       int32_t remaining = timer->dt - elapsed;
-
-       if (remaining <= 0)
-       {
-         if (timer->isoneshot)
-         {
-           timer->isrunning = FALSE;
-         }
-         else
+       Timer_t* timer = &m_timers[num];
+
+       if (timer->isrunning)
          {
-           // The remaining time is non-positive (the timer had fired).
-           // So add dt to convert it to remaining for the next event.
-           timer->t0 += timer->dt;
-           remaining += timer->dt; 
+           uint32_t elapsed = now - timer->t0;
+
+           if (elapsed >= timer->dt)
+             {
+               if (timer->isoneshot)
+                 timer->isrunning = FALSE;
+               else // Update timer for next event
+                 timer->t0 += timer->dt;
+
+               signal Timer.fired[num]();
+    break;
+             }
          }
+      }
+    post updateFromTimer();
+  }
+  
+  task void updateFromTimer()
+  {
+    /* This code supports a maximum dt of MAXINT. If min_remaining and
+       remaining were switched to uint32_t, and the logic changed a
+       little, dt's up to 2^32-1 should work (but at a slightly higher
+       runtime cost). */
+    uint32_t now = call TimerFrom.getNow();
+    int32_t min_remaining = (1UL << 31) - 1; /* max int32_t */
+    bool min_remaining_isset = FALSE;
+    uint8_t num;
+
+    call TimerFrom.stop();
 
-         signal Timer.fired[num]();
-       }
+    for (num=0; num<NUM_TIMERS; num++)
+      {
+       Timer_t* timer = &m_timers[num];
 
-       // check isrunning in case the timer was stopped in the fired
-       // event or this was a one shot timer; note that a one shot
-       // timer that was restarted in its fired event will push us
-       // through here with remaining <= 0, but we're already scheduled
-       // an executeTimersTask in that case (and suppressed setting
-       // TimerFrom)
        if (timer->isrunning)
-       {
-         if (remaining < min_remaining)
-           min_remaining = remaining;
-         min_remaining_isset = TRUE;
-       }
+         {
+           uint32_t elapsed = now - timer->t0;
+           int32_t remaining = timer->dt - elapsed;
+
+           if (remaining < min_remaining)
+             {
+               min_remaining = remaining;
+               min_remaining_isset = TRUE;
+             }
+         }
       }
-    }
 
-    if (!(state & S_TIMER_CHANGED) && min_remaining_isset)
-    {
-      if (min_remaining <= 0)
-       post executeTimersNow();
-      else
-       {
-         call TimerFrom.startOneShotAt(then, min_remaining);
-         state |= S_TIMER_RUNNING;
-       }
-    }
+    if (min_remaining_isset)
+      {
+       if (min_remaining <= 0)
+         fireTimers(now);
+       else
+         call TimerFrom.startOneShotAt(now, min_remaining);
+      }
   }
   
-
   event void TimerFrom.fired()
   {
-    executeTimers(call TimerFrom.gett0() + call TimerFrom.getdt());
-  }
-
-  task void executeTimersNow()
-  {
-    /* If we set a timer, try and stop it. But if it believes it's
-       not running, that means that the execution of its fired event
-       is pending, so we:
-       - don't need to call executeTimers (it will happen soon)
-       - we must not call executeTimers, because that would change the
-         timer's setting, confusing the pending call to TimerFrom.fired
-        (it would call executeTimers with an incorrect "then"
-        parameter)
-       We need to use an atomic section even though it's a "timer",
-       because it's based on an underlying alarm, whose transitions
-       are asynchronous (yuck?)
-    */
-    if (state & S_TIMER_RUNNING)
-      atomic
-       {
-         if (!call TimerFrom.isRunning())
-           return;
-         call TimerFrom.stop();
-       }
-    executeTimers(call TimerFrom.getNow());
+    fireTimers(call TimerFrom.getNow());
   }
 
   void startTimer(uint8_t num, uint32_t t0, uint32_t dt, bool isoneshot)
@@ -170,8 +137,7 @@ implementation
     timer->dt = dt;
     timer->isoneshot = isoneshot;
     timer->isrunning = TRUE;
-    state |= S_TIMER_CHANGED;
-    post executeTimersNow();
+    post updateFromTimer();
   }
 
   command void Timer.startPeriodic[uint8_t num](uint32_t dt)