Contiki-Inga 3.x
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  */
46 
47 #include "contiki-conf.h"
48 
49 #include "sys/etimer.h"
50 #include "sys/process.h"
51 
52 static struct etimer *timerlist;
53 static clock_time_t next_expiration;
54 
55 PROCESS(etimer_process, "Event timer");
56 /*---------------------------------------------------------------------------*/
57 static void
58 update_time(void)
59 {
60  clock_time_t tdist;
61  clock_time_t now;
62  struct etimer *t;
63 
64  if (timerlist == NULL) {
65  next_expiration = 0;
66  } else {
67  now = clock_time();
68  t = timerlist;
69  /* Must calculate distance to next time into account due to wraps */
70  tdist = t->timer.start + t->timer.interval - now;
71  for(t = t->next; t != NULL; t = t->next) {
72  if(t->timer.start + t->timer.interval - now < tdist) {
73  tdist = t->timer.start + t->timer.interval - now;
74  }
75  }
76  next_expiration = now + tdist;
77  }
78 }
79 /*---------------------------------------------------------------------------*/
80 PROCESS_THREAD(etimer_process, ev, data)
81 {
82  struct etimer *t, *u;
83 
84  PROCESS_BEGIN();
85 
86  timerlist = NULL;
87 
88  while(1) {
89  PROCESS_YIELD();
90 
91  if(ev == PROCESS_EVENT_EXITED) {
92  struct process *p = data;
93 
94  while(timerlist != NULL && timerlist->p == p) {
95  timerlist = timerlist->next;
96  }
97 
98  if(timerlist != NULL) {
99  t = timerlist;
100  while(t->next != NULL) {
101  if(t->next->p == p) {
102  t->next = t->next->next;
103  } else
104  t = t->next;
105  }
106  }
107  continue;
108  } else if(ev != PROCESS_EVENT_POLL) {
109  continue;
110  }
111 
112  again:
113 
114  u = NULL;
115 
116  for(t = timerlist; t != NULL; t = t->next) {
117  if(timer_expired(&t->timer)) {
118  if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
119 
120  /* Reset the process ID of the event timer, to signal that the
121  etimer has expired. This is later checked in the
122  etimer_expired() function. */
123  t->p = PROCESS_NONE;
124  if(u != NULL) {
125  u->next = t->next;
126  } else {
127  timerlist = t->next;
128  }
129  t->next = NULL;
130  update_time();
131  goto again;
132  } else {
134  }
135  }
136  u = t;
137  }
138 
139  }
140 
141  PROCESS_END();
142 }
143 /*---------------------------------------------------------------------------*/
144 void
146 {
147  process_poll(&etimer_process);
148 }
149 /*---------------------------------------------------------------------------*/
150 static void
151 add_timer(struct etimer *timer)
152 {
153  struct etimer *t;
154 
156 
157  if(timer->p != PROCESS_NONE) {
158  for(t = timerlist; t != NULL; t = t->next) {
159  if(t == timer) {
160  /* Timer already on list, bail out. */
161  timer->p = PROCESS_CURRENT();
162  update_time();
163  return;
164  }
165  }
166  }
167 
168  /* Timer not on list. */
169  timer->p = PROCESS_CURRENT();
170  timer->next = timerlist;
171  timerlist = timer;
172 
173  update_time();
174 }
175 /*---------------------------------------------------------------------------*/
176 void
177 etimer_set(struct etimer *et, clock_time_t interval)
178 {
179  timer_set(&et->timer, interval);
180  add_timer(et);
181 }
182 /*---------------------------------------------------------------------------*/
183 void
184 etimer_reset(struct etimer *et)
185 {
186  timer_reset(&et->timer);
187  add_timer(et);
188 }
189 /*---------------------------------------------------------------------------*/
190 void
192 {
193  timer_restart(&et->timer);
194  add_timer(et);
195 }
196 /*---------------------------------------------------------------------------*/
197 void
198 etimer_adjust(struct etimer *et, int timediff)
199 {
200  et->timer.start += timediff;
201  update_time();
202 }
203 /*---------------------------------------------------------------------------*/
204 int
206 {
207  return et->p == PROCESS_NONE;
208 }
209 /*---------------------------------------------------------------------------*/
210 clock_time_t
212 {
213  return et->timer.start + et->timer.interval;
214 }
215 /*---------------------------------------------------------------------------*/
216 clock_time_t
218 {
219  return et->timer.start;
220 }
221 /*---------------------------------------------------------------------------*/
222 int
224 {
225  return timerlist != NULL;
226 }
227 /*---------------------------------------------------------------------------*/
228 clock_time_t
230 {
231  return etimer_pending() ? next_expiration : 0;
232 }
233 /*---------------------------------------------------------------------------*/
234 void
235 etimer_stop(struct etimer *et)
236 {
237  struct etimer *t;
238 
239  /* First check if et is the first event timer on the list. */
240  if(et == timerlist) {
241  timerlist = timerlist->next;
242  update_time();
243  } else {
244  /* Else walk through the list and try to find the item before the
245  et timer. */
246  for(t = timerlist; t != NULL && t->next != et; t = t->next);
247 
248  if(t != NULL) {
249  /* We've found the item before the event timer that we are about
250  to remove. We point the items next pointer to the event after
251  the removed item. */
252  t->next = et->next;
253 
254  update_time();
255  }
256  }
257 
258  /* Remove the next pointer from the item to be removed. */
259  et->next = NULL;
260  /* Set the timer as expired */
261  et->p = PROCESS_NONE;
262 }
263 /*---------------------------------------------------------------------------*/
264 /** @} */