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.1 2006/06/17 22:41:20 adamdunkels 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 nextt; 00062 struct etimer *t; 00063 00064 if (timerlist == NULL) { 00065 next_expiration = 0; 00066 } else { 00067 t = timerlist; 00068 nextt = t->timer.start + t->timer.interval; 00069 for(t = t->next; t != NULL; t = t->next) { 00070 if(t->timer.start + t->timer.interval < nextt) { 00071 nextt = t->timer.start + t->timer.interval; 00072 } 00073 } 00074 next_expiration = nextt; 00075 } 00076 } 00077 /*---------------------------------------------------------------------------*/ 00078 PROCESS_THREAD(etimer_process, ev, data) 00079 { 00080 struct etimer *t, *u; 00081 00082 PROCESS_BEGIN(); 00083 00084 timerlist = NULL; 00085 00086 while(1) { 00087 PROCESS_YIELD(); 00088 00089 if(ev == PROCESS_EVENT_EXITED) { 00090 struct process *p = data; 00091 00092 while(timerlist != NULL && timerlist->p == p) { 00093 timerlist = timerlist->next; 00094 } 00095 00096 if(timerlist != NULL) { 00097 t = timerlist; 00098 while(t->next != NULL) { 00099 if(t->next->p == p) { 00100 t->next = t->next->next; 00101 } else 00102 t = t->next; 00103 } 00104 } 00105 continue; 00106 } else if(ev != PROCESS_EVENT_POLL) { 00107 continue; 00108 } 00109 00110 again: 00111 00112 u = NULL; 00113 00114 for(t = timerlist; t != NULL; t = t->next) { 00115 if(timer_expired(&t->timer)) { 00116 if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) { 00117 00118 /* Reset the process ID of the event timer, to signal that the 00119 etimer has expired. This is later checked in the 00120 etimer_expired() function. */ 00121 t->p = PROCESS_NONE; 00122 if(u != NULL) { 00123 u->next = t->next; 00124 } else { 00125 timerlist = t->next; 00126 } 00127 t->next = NULL; 00128 update_time(); 00129 goto again; 00130 } else { 00131 etimer_request_poll(); 00132 } 00133 } 00134 u = t; 00135 } 00136 00137 } 00138 00139 PROCESS_END(); 00140 } 00141 /*---------------------------------------------------------------------------*/ 00142 void 00143 etimer_request_poll(void) 00144 { 00145 process_poll(&etimer_process); 00146 } 00147 /*---------------------------------------------------------------------------*/ 00148 static void 00149 add_timer(struct etimer *timer) 00150 { 00151 struct etimer *t; 00152 00153 if(timer->p != PROCESS_NONE) { 00154 /* Timer not on list. */ 00155 00156 for(t = timerlist; t != NULL; t = t->next) { 00157 if(t == timer) { 00158 /* Timer already on list, bail out. */ 00159 update_time(); 00160 return; 00161 } 00162 } 00163 } 00164 00165 timer->p = PROCESS_CURRENT(); 00166 timer->next = timerlist; 00167 timerlist = timer; 00168 00169 update_time(); 00170 } 00171 /*---------------------------------------------------------------------------*/ 00172 void 00173 etimer_set(struct etimer *et, clock_time_t interval) 00174 { 00175 timer_set(&et->timer, interval); 00176 add_timer(et); 00177 } 00178 /*---------------------------------------------------------------------------*/ 00179 void 00180 etimer_reset(struct etimer *et) 00181 { 00182 timer_reset(&et->timer); 00183 add_timer(et); 00184 } 00185 /*---------------------------------------------------------------------------*/ 00186 void 00187 etimer_restart(struct etimer *et) 00188 { 00189 timer_restart(&et->timer); 00190 add_timer(et); 00191 } 00192 /*---------------------------------------------------------------------------*/ 00193 void 00194 etimer_adjust(struct etimer *et, int timediff) 00195 { 00196 et->timer.start += timediff; 00197 update_time(); 00198 } 00199 /*---------------------------------------------------------------------------*/ 00200 int 00201 etimer_expired(struct etimer *et) 00202 { 00203 return et->p == PROCESS_NONE; 00204 } 00205 /*---------------------------------------------------------------------------*/ 00206 clock_time_t 00207 etimer_expiration_time(struct etimer *et) 00208 { 00209 return et->timer.start + et->timer.interval; 00210 } 00211 /*---------------------------------------------------------------------------*/ 00212 clock_time_t 00213 etimer_start_time(struct etimer *et) 00214 { 00215 return et->timer.start; 00216 } 00217 /*---------------------------------------------------------------------------*/ 00218 int 00219 etimer_pending(void) 00220 { 00221 return timerlist != NULL; 00222 } 00223 /*---------------------------------------------------------------------------*/ 00224 clock_time_t 00225 etimer_next_expiration_time(void) 00226 { 00227 return etimer_pending() ? next_expiration : 0; 00228 } 00229 /*---------------------------------------------------------------------------*/ 00230 void 00231 etimer_stop(struct etimer *et) 00232 { 00233 struct etimer *t; 00234 00235 /* First check if et is the first event timer on the list. */ 00236 if(et == timerlist) { 00237 timerlist = timerlist->next; 00238 update_time(); 00239 } else { 00240 /* Else walk through the list and try to find the item before the 00241 et timer. */ 00242 for(t = timerlist; t != NULL && t->next != et; t = t->next); 00243 00244 if(t != NULL) { 00245 /* We've found the item before the event timer that we are about 00246 to remove. We point the items next pointer to the event after 00247 the removed item. */ 00248 t->next = et->next; 00249 00250 update_time(); 00251 } 00252 } 00253 00254 /* Remove the next pointer from the item to be removed. */ 00255 et->next = NULL; 00256 /* Set the timer as expired */ 00257 et->p = PROCESS_NONE; 00258 } 00259 /*---------------------------------------------------------------------------*/ 00260 /** @} */