Contiki 2.5
etimer.c
Go to the documentation of this file.
1 /**
2  * \addtogroup etimer
3  * @{
4  */
5 
6 /**
7  * \file
8  * Event timer library implementation.
9  * \author
10  * Adam Dunkels <adam@sics.se>
11  */
12 
13 /*
14  * Copyright (c) 2004, Swedish Institute of Computer Science.
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  * notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in the
24  * documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the Institute nor the names of its contributors
26  * may be used to endorse or promote products derived from this software
27  * without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  * This file is part of the Contiki operating system.
42  *
43  * Author: Adam Dunkels <adam@sics.se>
44  *
45  * $Id: etimer.c,v 1.3 2007/10/07 19:59:27 joxe Exp $
46  */
47 
48 #include "contiki-conf.h"
49 
50 #include "sys/etimer.h"
51 #include "sys/process.h"
52 
53 static struct etimer *timerlist;
54 static clock_time_t next_expiration;
55 
56 PROCESS(etimer_process, "Event timer");
57 /*---------------------------------------------------------------------------*/
58 static void
59 update_time(void)
60 {
61  clock_time_t tdist;
62  clock_time_t now;
63  struct etimer *t;
64 
65  if (timerlist == NULL) {
66  next_expiration = 0;
67  } else {
68  now = clock_time();
69  t = timerlist;
70  /* Must calculate distance to next time into account due to wraps */
71  tdist = t->timer.start + t->timer.interval - now;
72  for(t = t->next; t != NULL; t = t->next) {
73  if(t->timer.start + t->timer.interval - now < tdist) {
74  tdist = t->timer.start + t->timer.interval - now;
75  }
76  }
77  next_expiration = now + tdist;
78  }
79 }
80 /*---------------------------------------------------------------------------*/
81 PROCESS_THREAD(etimer_process, ev, data)
82 {
83  struct etimer *t, *u;
84 
85  PROCESS_BEGIN();
86 
87  timerlist = NULL;
88 
89  while(1) {
90  PROCESS_YIELD();
91 
92  if(ev == PROCESS_EVENT_EXITED) {
93  struct process *p = data;
94 
95  while(timerlist != NULL && timerlist->p == p) {
96  timerlist = timerlist->next;
97  }
98 
99  if(timerlist != NULL) {
100  t = timerlist;
101  while(t->next != NULL) {
102  if(t->next->p == p) {
103  t->next = t->next->next;
104  } else
105  t = t->next;
106  }
107  }
108  continue;
109  } else if(ev != PROCESS_EVENT_POLL) {
110  continue;
111  }
112 
113  again:
114 
115  u = NULL;
116 
117  for(t = timerlist; t != NULL; t = t->next) {
118  if(timer_expired(&t->timer)) {
119  if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
120 
121  /* Reset the process ID of the event timer, to signal that the
122  etimer has expired. This is later checked in the
123  etimer_expired() function. */
124  t->p = PROCESS_NONE;
125  if(u != NULL) {
126  u->next = t->next;
127  } else {
128  timerlist = t->next;
129  }
130  t->next = NULL;
131  update_time();
132  goto again;
133  } else {
135  }
136  }
137  u = t;
138  }
139 
140  }
141 
142  PROCESS_END();
143 }
144 /*---------------------------------------------------------------------------*/
145 void
147 {
148  process_poll(&etimer_process);
149 }
150 /*---------------------------------------------------------------------------*/
151 static void
152 add_timer(struct etimer *timer)
153 {
154  struct etimer *t;
155 
157 
158  if(timer->p != PROCESS_NONE) {
159  /* Timer not on list. */
160 
161  for(t = timerlist; t != NULL; t = t->next) {
162  if(t == timer) {
163  /* Timer already on list, bail out. */
164  update_time();
165  return;
166  }
167  }
168  }
169 
170  timer->p = PROCESS_CURRENT();
171  timer->next = timerlist;
172  timerlist = timer;
173 
174  update_time();
175 }
176 /*---------------------------------------------------------------------------*/
177 void
178 etimer_set(struct etimer *et, clock_time_t interval)
179 {
180  timer_set(&et->timer, interval);
181  add_timer(et);
182 }
183 /*---------------------------------------------------------------------------*/
184 void
185 etimer_reset(struct etimer *et)
186 {
187  timer_reset(&et->timer);
188  add_timer(et);
189 }
190 /*---------------------------------------------------------------------------*/
191 void
193 {
194  timer_restart(&et->timer);
195  add_timer(et);
196 }
197 /*---------------------------------------------------------------------------*/
198 void
199 etimer_adjust(struct etimer *et, int timediff)
200 {
201  et->timer.start += timediff;
202  update_time();
203 }
204 /*---------------------------------------------------------------------------*/
205 int
207 {
208  return et->p == PROCESS_NONE;
209 }
210 /*---------------------------------------------------------------------------*/
211 clock_time_t
213 {
214  return et->timer.start + et->timer.interval;
215 }
216 /*---------------------------------------------------------------------------*/
217 clock_time_t
219 {
220  return et->timer.start;
221 }
222 /*---------------------------------------------------------------------------*/
223 int
225 {
226  return timerlist != NULL;
227 }
228 /*---------------------------------------------------------------------------*/
229 clock_time_t
231 {
232  return etimer_pending() ? next_expiration : 0;
233 }
234 /*---------------------------------------------------------------------------*/
235 void
236 etimer_stop(struct etimer *et)
237 {
238  struct etimer *t;
239 
240  /* First check if et is the first event timer on the list. */
241  if(et == timerlist) {
242  timerlist = timerlist->next;
243  update_time();
244  } else {
245  /* Else walk through the list and try to find the item before the
246  et timer. */
247  for(t = timerlist; t != NULL && t->next != et; t = t->next);
248 
249  if(t != NULL) {
250  /* We've found the item before the event timer that we are about
251  to remove. We point the items next pointer to the event after
252  the removed item. */
253  t->next = et->next;
254 
255  update_time();
256  }
257  }
258 
259  /* Remove the next pointer from the item to be removed. */
260  et->next = NULL;
261  /* Set the timer as expired */
262  et->p = PROCESS_NONE;
263 }
264 /*---------------------------------------------------------------------------*/
265 /** @} */