Contiki 2.6

etimer.c

Go to the documentation of this file.
00001 /**
00002  * \addtogroup etimer
00003  * @{
00004  */
00005 
00006 /**
00007  * \file
00008  * Event timer library implementation.
00009  * \author
00010  * Adam Dunkels <adam@sics.se>
00011  */
00012 
00013 /*
00014  * Copyright (c) 2004, Swedish Institute of Computer Science.
00015  * All rights reserved.
00016  *
00017  * Redistribution and use in source and binary forms, with or without
00018  * modification, are permitted provided that the following conditions
00019  * are met:
00020  * 1. Redistributions of source code must retain the above copyright
00021  *    notice, this list of conditions and the following disclaimer.
00022  * 2. Redistributions in binary form must reproduce the above copyright
00023  *    notice, this list of conditions and the following disclaimer in the
00024  *    documentation and/or other materials provided with the distribution.
00025  * 3. Neither the name of the Institute nor the names of its contributors
00026  *    may be used to endorse or promote products derived from this software
00027  *    without specific prior written permission.
00028  *
00029  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00030  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00031  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00032  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00033  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00034  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00035  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00036  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00037  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00038  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00039  * SUCH DAMAGE.
00040  *
00041  * This file is part of the Contiki operating system.
00042  *
00043  * Author: Adam Dunkels <adam@sics.se>
00044  *
00045  * $Id: etimer.c,v 1.3 2007/10/07 19:59:27 joxe Exp $
00046  */
00047 
00048 #include "contiki-conf.h"
00049 
00050 #include "sys/etimer.h"
00051 #include "sys/process.h"
00052 
00053 static struct etimer *timerlist;
00054 static clock_time_t next_expiration;
00055 
00056 PROCESS(etimer_process, "Event timer");
00057 /*---------------------------------------------------------------------------*/
00058 static void
00059 update_time(void)
00060 {
00061   clock_time_t tdist;
00062   clock_time_t now;
00063   struct etimer *t;
00064 
00065   if (timerlist == NULL) {
00066     next_expiration = 0;
00067   } else {
00068     now = clock_time();
00069     t = timerlist;
00070     /* Must calculate distance to next time into account due to wraps */
00071     tdist = t->timer.start + t->timer.interval - now;
00072     for(t = t->next; t != NULL; t = t->next) {
00073       if(t->timer.start + t->timer.interval - now < tdist) {
00074         tdist = t->timer.start + t->timer.interval - now;
00075       }
00076     }
00077     next_expiration = now + tdist;
00078   }
00079 }
00080 /*---------------------------------------------------------------------------*/
00081 PROCESS_THREAD(etimer_process, ev, data)
00082 {
00083   struct etimer *t, *u;
00084         
00085   PROCESS_BEGIN();
00086 
00087   timerlist = NULL;
00088   
00089   while(1) {
00090     PROCESS_YIELD();
00091 
00092     if(ev == PROCESS_EVENT_EXITED) {
00093       struct process *p = data;
00094 
00095       while(timerlist != NULL && timerlist->p == p) {
00096         timerlist = timerlist->next;
00097       }
00098 
00099       if(timerlist != NULL) {
00100         t = timerlist;
00101         while(t->next != NULL) {
00102           if(t->next->p == p) {
00103             t->next = t->next->next;
00104           } else
00105             t = t->next;
00106         }
00107       }
00108       continue;
00109     } else if(ev != PROCESS_EVENT_POLL) {
00110       continue;
00111     }
00112 
00113   again:
00114     
00115     u = NULL;
00116     
00117     for(t = timerlist; t != NULL; t = t->next) {
00118       if(timer_expired(&t->timer)) {
00119         if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
00120           
00121           /* Reset the process ID of the event timer, to signal that the
00122              etimer has expired. This is later checked in the
00123              etimer_expired() function. */
00124           t->p = PROCESS_NONE;
00125           if(u != NULL) {
00126             u->next = t->next;
00127           } else {
00128             timerlist = t->next;
00129           }
00130           t->next = NULL;
00131           update_time();
00132           goto again;
00133         } else {
00134           etimer_request_poll();
00135         }
00136       }
00137       u = t;
00138     }
00139     
00140   }
00141   
00142   PROCESS_END();
00143 }
00144 /*---------------------------------------------------------------------------*/
00145 void
00146 etimer_request_poll(void)
00147 {
00148   process_poll(&etimer_process);
00149 }
00150 /*---------------------------------------------------------------------------*/
00151 static void
00152 add_timer(struct etimer *timer)
00153 {
00154   struct etimer *t;
00155 
00156   etimer_request_poll();
00157 
00158   if(timer->p != PROCESS_NONE) {
00159     /* Timer not on list. */
00160     
00161     for(t = timerlist; t != NULL; t = t->next) {
00162       if(t == timer) {
00163         /* Timer already on list, bail out. */
00164         update_time();
00165         return;
00166       }
00167     }
00168   }
00169 
00170   timer->p = PROCESS_CURRENT();
00171   timer->next = timerlist;
00172   timerlist = timer;
00173 
00174   update_time();
00175 }
00176 /*---------------------------------------------------------------------------*/
00177 void
00178 etimer_set(struct etimer *et, clock_time_t interval)
00179 {
00180   timer_set(&et->timer, interval);
00181   add_timer(et);
00182 }
00183 /*---------------------------------------------------------------------------*/
00184 void
00185 etimer_reset(struct etimer *et)
00186 {
00187   timer_reset(&et->timer);
00188   add_timer(et);
00189 }
00190 /*---------------------------------------------------------------------------*/
00191 void
00192 etimer_restart(struct etimer *et)
00193 {
00194   timer_restart(&et->timer);
00195   add_timer(et);
00196 }
00197 /*---------------------------------------------------------------------------*/
00198 void
00199 etimer_adjust(struct etimer *et, int timediff)
00200 {
00201   et->timer.start += timediff;
00202   update_time();
00203 }
00204 /*---------------------------------------------------------------------------*/
00205 int
00206 etimer_expired(struct etimer *et)
00207 {
00208   return et->p == PROCESS_NONE;
00209 }
00210 /*---------------------------------------------------------------------------*/
00211 clock_time_t
00212 etimer_expiration_time(struct etimer *et)
00213 {
00214   return et->timer.start + et->timer.interval;
00215 }
00216 /*---------------------------------------------------------------------------*/
00217 clock_time_t
00218 etimer_start_time(struct etimer *et)
00219 {
00220   return et->timer.start;
00221 }
00222 /*---------------------------------------------------------------------------*/
00223 int
00224 etimer_pending(void)
00225 {
00226   return timerlist != NULL;
00227 }
00228 /*---------------------------------------------------------------------------*/
00229 clock_time_t
00230 etimer_next_expiration_time(void)
00231 {
00232   return etimer_pending() ? next_expiration : 0;
00233 }
00234 /*---------------------------------------------------------------------------*/
00235 void
00236 etimer_stop(struct etimer *et)
00237 {
00238   struct etimer *t;
00239 
00240   /* First check if et is the first event timer on the list. */
00241   if(et == timerlist) {
00242     timerlist = timerlist->next;
00243     update_time();
00244   } else {
00245     /* Else walk through the list and try to find the item before the
00246        et timer. */
00247     for(t = timerlist; t != NULL && t->next != et; t = t->next);
00248 
00249     if(t != NULL) {
00250       /* We've found the item before the event timer that we are about
00251          to remove. We point the items next pointer to the event after
00252          the removed item. */
00253       t->next = et->next;
00254 
00255       update_time();
00256     }
00257   }
00258 
00259   /* Remove the next pointer from the item to be removed. */
00260   et->next = NULL;
00261   /* Set the timer as expired */
00262   et->p = PROCESS_NONE;
00263 }
00264 /*---------------------------------------------------------------------------*/
00265 /** @} */