File: | su/su_timer.c |
Warning: | line 229, column 73 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * This file is part of the Sofia-SIP package | |||
3 | * | |||
4 | * Copyright (C) 2005 Nokia Corporation. | |||
5 | * | |||
6 | * Contact: Pekka Pessi <pekka.pessi@nokia.com> | |||
7 | * | |||
8 | * This library is free software; you can redistribute it and/or | |||
9 | * modify it under the terms of the GNU Lesser General Public License | |||
10 | * as published by the Free Software Foundation; either version 2.1 of | |||
11 | * the License, or (at your option) any later version. | |||
12 | * | |||
13 | * This library is distributed in the hope that it will be useful, but | |||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
16 | * Lesser General Public License for more details. | |||
17 | * | |||
18 | * You should have received a copy of the GNU Lesser General Public | |||
19 | * License along with this library; if not, write to the Free Software | |||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||
21 | * 02110-1301 USA | |||
22 | * | |||
23 | */ | |||
24 | ||||
25 | /**@CFILE su_timer.c | |||
26 | * | |||
27 | * Timer interface for su_root. | |||
28 | * | |||
29 | * @author Pekka Pessi <Pekka.Pessi@nokia.com> | |||
30 | * Created: Fri Apr 28 15:45:41 2000 ppessi | |||
31 | */ | |||
32 | ||||
33 | #include "config.h" | |||
34 | ||||
35 | #include <sys/types.h> | |||
36 | #include "sofia-sip/heap.h" | |||
37 | ||||
38 | typedef union { | |||
39 | void *private; | |||
40 | /* Use for debugging */ | |||
41 | struct timers_priv { | |||
42 | size_t _size, _used; | |||
43 | struct su_timer_s * _heap[2]; | |||
44 | } *actual; | |||
45 | } su_timer_heap_t; | |||
46 | ||||
47 | #define SU_TIMER_QUEUE_Tsu_timer_heap_t su_timer_heap_t | |||
48 | ||||
49 | #include "sofia-sip/su.h" | |||
50 | #include "su_port.h" | |||
51 | #include "sofia-sip/su_wait.h" | |||
52 | #include "sofia-sip/su_alloc.h" | |||
53 | #include "sofia-sip/rbtree.h" | |||
54 | ||||
55 | #include "su_module_debug.h" | |||
56 | ||||
57 | #include <stdlib.h> | |||
58 | #include <assert.h> | |||
59 | #include <stdio.h> | |||
60 | #include <string.h> | |||
61 | ||||
62 | /**@ingroup su_wait | |||
63 | * | |||
64 | * @page su_timer_t Timer Objects | |||
65 | * | |||
66 | * Timers are used to schedule some task to be executed at given time or | |||
67 | * after a default interval. The default interval is specified when the | |||
68 | * timer is created. We call timer activation "setting the timer", and | |||
69 | * deactivation "resetting the timer" (as in SDL). When the given time has | |||
70 | * arrived or the default interval has elapsed, the timer expires and | |||
71 | * it is ready for execution. | |||
72 | * | |||
73 | * The functions used to create, destroy, activate, and manage timers are | |||
74 | * as follows: | |||
75 | * - su_timer_create(), | |||
76 | * - su_timer_destroy(), | |||
77 | * - su_timer_set_interval(), | |||
78 | * - su_timer_set_at(), | |||
79 | * - su_timer_set(), | |||
80 | * - su_timer_set_for_ever(), | |||
81 | * - su_timer_run(), | |||
82 | * - su_timer_reset(), and | |||
83 | * - su_timer_root(). | |||
84 | * | |||
85 | * @note | |||
86 | * Timers use poll() to wake up waiting thread. On Linux, the timer | |||
87 | * granularity is determined by HZ kernel parameter, which decided when the | |||
88 | * kernel was compiled. With kernel 2.4 the default granularity is 10 | |||
89 | * milliseconds, and minimum duration of a timer is approximately 20 | |||
90 | * milliseconds. Naturally, using RTC would give better timing results, but | |||
91 | * RTC usage above 64 Hz is privileged operation. | |||
92 | * | |||
93 | * @par | |||
94 | * On Windows, the granularity is determined by the real-time clock timer. | |||
95 | * By default, it uses the 18.78 Hz granularity. That timer can be adjusted | |||
96 | * up to 1000 Hz using Windows multimedia library. | |||
97 | * | |||
98 | * @section su_timer_usage Using Timers | |||
99 | * | |||
100 | * A timer is created by calling su_timer_create(): | |||
101 | * @code | |||
102 | * timer = su_timer_create(su_root_task(root), 200); | |||
103 | * @endcode | |||
104 | * The default duration is given in milliseconds. | |||
105 | * | |||
106 | * Usually, timer wakeup function should be called at regular intervals. In | |||
107 | * such case, the timer is activated using function su_timer_set_for_ever(). | |||
108 | * When the timer is activated it is given the wakeup function and pointer to | |||
109 | * context data: | |||
110 | * @code | |||
111 | * su_timer_set_for_ever(timer, timer_wakeup, args); | |||
112 | * @endcode | |||
113 | * | |||
114 | * When the interval has passed, the root event loop calls the wakeup | |||
115 | * function: | |||
116 | * @code | |||
117 | * timer_wakeup(root, timer, args); | |||
118 | * @endcode | |||
119 | * | |||
120 | * If the number of calls to callback function is important, use | |||
121 | * su_timer_run() instead. The run timer tries to compensate for missed time | |||
122 | * and invokes the callback function several times if needed. (Because the | |||
123 | * real-time clock can be adjusted or the program suspended, e.g., while | |||
124 | * debugged, the callback function can be called thousends of times in a | |||
125 | * row.) Note that while the timer tries to compensate for delays occurred | |||
126 | * before and during the callback, it cannot be used as an exact source of | |||
127 | * timing information. | |||
128 | * | |||
129 | * Timer ceases running when su_timer_reset() is called. | |||
130 | * | |||
131 | * Alternatively, the timer can be @b set for one-time event invocation. | |||
132 | * When the timer is set, it is given the wakeup function and pointer to | |||
133 | * context data. The actual duration can also be specified using | |||
134 | * su_timer_set_at(). @code su_timer_set(timer, timer_wakeup, args); | |||
135 | * @endcode | |||
136 | * | |||
137 | * When the timer expires, the root event loop calls the wakeup function: | |||
138 | * @code | |||
139 | * timer_wakeup(root, timer, args); | |||
140 | * @endcode | |||
141 | * | |||
142 | * If the timed event is not needed anymore, the timer can be reset: | |||
143 | * @code | |||
144 | * su_timer_reset(timer); | |||
145 | * @endcode | |||
146 | * | |||
147 | * If the timer is expected to be called at regular intervals, it is | |||
148 | * possible to set ro run continously with su_timer_run(). While such a | |||
149 | * continously running timer is active it @b must @b not @b be @b set using | |||
150 | * su_timer_set() or su_timer_set_at(). | |||
151 | * | |||
152 | * When the timer is not needed anymore, the timer object itself should be | |||
153 | * destroyed: | |||
154 | * @code | |||
155 | * su_timer_destroy(timer); | |||
156 | * @endcode | |||
157 | */ | |||
158 | ||||
159 | struct su_timer_s { | |||
160 | su_task_r sut_task; /**< Task reference */ | |||
161 | size_t sut_set; /**< Timer is set (inserted in heap) */ | |||
162 | su_time_t sut_when; /**< When timer should be waken up next time */ | |||
163 | su_duration_t sut_duration; /**< Timer duration */ | |||
164 | su_timer_f sut_wakeup; /**< Function to call when waken up */ | |||
165 | su_timer_arg_t *sut_arg; /**< Pointer to argument data */ | |||
166 | unsigned sut_woken; /**< Timer has waken up this many times */ | |||
167 | ||||
168 | unsigned sut_running:2;/**< Timer is running */ | |||
169 | unsigned sut_deferrable:1;/**< Timer can be deferrable */ | |||
170 | }; | |||
171 | ||||
172 | /** Timer running status */ | |||
173 | enum sut_running { | |||
174 | reset = 0, /**< Timer is not running */ | |||
175 | run_at_intervals = 1, /**< Compensate missed wakeup calls */ | |||
176 | run_for_ever = 2 /**< Do not compensate */ | |||
177 | }; | |||
178 | ||||
179 | #define SU_TIMER_IS_SET(sut)((sut)->sut_set != 0) ((sut)->sut_set != 0) | |||
180 | ||||
181 | HEAP_DECLARE(su_inline, su_timer_queue_t, timers_, su_timer_t *)static inline int timers_resize(void *, su_timer_queue_t *, size_t ); static inline int timers_free(void *, su_timer_queue_t *); static inline int timers_is_full(su_timer_queue_t const); static inline size_t timers_size(su_timer_queue_t const); static inline size_t timers_used(su_timer_queue_t const); static inline void timers_sort(su_timer_queue_t); static inline int timers_add( su_timer_queue_t, su_timer_t *); static inline su_timer_t * timers_remove (su_timer_queue_t, size_t); static inline su_timer_t * timers_get (su_timer_queue_t, size_t); | |||
182 | ||||
183 | su_inlinestatic inline void timers_set(su_timer_t **array, size_t index, su_timer_t *t) | |||
184 | { | |||
185 | array[t->sut_set = index] = t; | |||
186 | } | |||
187 | ||||
188 | su_inlinestatic inline int timers_less(su_timer_t *a, su_timer_t *b) | |||
189 | { | |||
190 | return | |||
191 | a->sut_when.tv_sec < b->sut_when.tv_sec || | |||
192 | (a->sut_when.tv_sec == b->sut_when.tv_sec && | |||
193 | a->sut_when.tv_usec < b->sut_when.tv_usec); | |||
194 | } | |||
195 | ||||
196 | su_inlinestatic inline void *timers_alloc(void *argument, void *memory, size_t size) | |||
197 | { | |||
198 | (void)argument; | |||
199 | ||||
200 | if (size) | |||
201 | return realloc(memory, size); | |||
202 | else | |||
203 | return free(memory), NULL((void*)0); | |||
204 | } | |||
205 | ||||
206 | #ifdef __clang__1 | |||
207 | #pragma clang diagnostic push | |||
208 | #pragma clang diagnostic ignored "-Wunused-function" | |||
209 | #endif | |||
210 | ||||
211 | //HEAP_BODIES(su_inline, su_timer_queue_t, timers_, su_timer_t *, | |||
212 | // timers_less, timers_set, timers_alloc, NULL); | |||
213 | static __inline int timers_resize(void* realloc_arg, su_timer_queue_t h[1], size_t new_size) | |||
214 | { | |||
215 | struct timers_priv { size_t _size, _used; su_timer_t* _heap[2]; }; | |||
216 | struct timers_priv* _priv; size_t _offset = (((size_t) & (((struct timers_priv*)0)->_heap[1])) - 1) / sizeof(su_timer_t*); size_t _min_size = 32 - _offset; size_t _bytes; size_t _used = 0; _priv = *(void**)h; | |||
217 | if (_priv) { if (new_size == 0) new_size = 2 * _priv->_size + _offset + 1; _used = _priv->_used; if (new_size < _used) new_size = _used; } | |||
218 | if (new_size < _min_size) new_size = _min_size; _bytes = (_offset + 1 + new_size) * sizeof(su_timer_t*); | |||
219 | (void)realloc_arg; _priv = timers_alloc(realloc_arg, *(struct timers_priv**)h, _bytes); | |||
220 | if (!_priv) return -1; *(struct timers_priv**)h = _priv; _priv->_size = new_size; _priv->_used = _used; return 0; | |||
221 | } | |||
222 | static __inline int timers_free(void* realloc_arg, su_timer_queue_t h[1]) | |||
223 | { | |||
224 | (void)realloc_arg; *(void**)h = timers_alloc(realloc_arg, *(void**)h, 0); return 0; | |||
225 | } | |||
226 | static __inline int timers_is_full(su_timer_queue_t h) | |||
227 | { | |||
228 | struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; | |||
229 | struct timers_priv* _priv = *(void**)&h; return _priv == ((void*)0) || _priv->_used >= _priv->_size; | |||
| ||||
230 | } | |||
231 | static __inline int timers_add(su_timer_queue_t h, su_timer_t* e) | |||
232 | { | |||
233 | struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; | |||
234 | struct timers_priv* _priv = *(void**)&h; su_timer_t** heap = _priv->_heap - 1; size_t i, parent; | |||
235 | if (_priv == ((void*)0) || _priv->_used >= _priv->_size) return -1; | |||
236 | for (i = ++_priv->_used; i > 1; i = parent) { | |||
237 | parent = i / 2; | |||
238 | if (!timers_less(e, heap[parent])) break; timers_set(heap, i, heap[parent]); | |||
239 | } timers_set(heap, i, e); return 0; | |||
240 | } | |||
241 | static __inline su_timer_t* timers_remove(su_timer_queue_t h, size_t index) | |||
242 | { | |||
243 | struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; | |||
244 | struct timers_priv* _priv = *(void**)&h; su_timer_t** heap = _priv->_heap - 1; | |||
245 | su_timer_t* retval[1]; su_timer_t* e; size_t top, left, right, move; | |||
246 | if (index - 1 >= _priv->_used) return (((void*)0)); | |||
247 | move = _priv->_used--; timers_set(retval, 0, heap[index]); | |||
248 | for (top = index;; index = top) { | |||
249 | left = 2 * top; right = 2 * top + 1; | |||
250 | if (left >= move) break; if (right < move&& timers_less(heap[right], heap[left])) top = right; else top = left; timers_set(heap, index, heap[top]); | |||
251 | } | |||
252 | if (index == move) return *retval; e = heap[move]; | |||
253 | for (; index > 1; index = top) { | |||
254 | top = index / 2; | |||
255 | if (!timers_less(e, heap[top])) break; timers_set(heap, index, heap[top]); | |||
256 | } | |||
257 | timers_set(heap, index, e); return *retval; | |||
258 | } | |||
259 | static __inline su_timer_t* timers_get(su_timer_queue_t h, size_t index) | |||
260 | { | |||
261 | struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; | |||
262 | struct timers_priv* _priv = *(void**)&h; if (--index >= _priv->_used) return (((void*)0)); return _priv->_heap[index]; | |||
263 | } static __inline size_t timers_size(su_timer_queue_t const h) { struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; struct timers_priv* _priv = *(void**)&h; return _priv ? _priv->_size : 0; } static __inline size_t timers_used(su_timer_queue_t const h) { struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; struct timers_priv* _priv = *(void**)&h; return _priv ? _priv->_used : 0; } static int timers__less(void* h, size_t a, size_t b) { su_timer_t** _heap = h; return timers_less(_heap[a], _heap[b]); } static void timers__swap(void* h, size_t a, size_t b) { su_timer_t** _heap = h; su_timer_t* _swap = _heap[a]; timers_set(_heap, a, _heap[b]); timers_set(_heap, b, _swap); } static __inline void timers_sort(su_timer_queue_t h) { struct timers_priv { size_t _size, _used; su_timer_t* _heap[1]; }; struct timers_priv* _priv = *(void**)&h; if (_priv) su_smoothsort(_priv->_heap - 1, 1, _priv->_used, timers__less, timers__swap); } extern int const timers_dummy_heap; | |||
264 | ||||
265 | ||||
266 | #ifdef __clang__1 | |||
267 | #pragma clang diagnostic pop | |||
268 | #endif | |||
269 | ||||
270 | /**@internal Set the timer. | |||
271 | * | |||
272 | * @retval 0 when successful (always) | |||
273 | */ | |||
274 | su_inlinestatic inline int | |||
275 | su_timer_set0(su_timer_queue_t *timers, | |||
276 | su_timer_t *t, | |||
277 | su_timer_f wakeup, | |||
278 | su_wakeup_arg_t *arg, | |||
279 | su_time_t when, | |||
280 | su_duration_t offset) | |||
281 | { | |||
282 | int retval; | |||
283 | ||||
284 | if (timers == NULL((void*)0)) | |||
285 | return -1; | |||
286 | ||||
287 | if (SU_TIMER_IS_SET(t)((t)->sut_set != 0)) | |||
288 | timers_remove(timers[0], t->sut_set); | |||
289 | ||||
290 | t->sut_wakeup = wakeup; | |||
291 | t->sut_arg = arg; | |||
292 | t->sut_when = su_time_add(when, offset); | |||
293 | ||||
294 | if (timers_is_full(timers[0])) { | |||
295 | timers_resize(NULL((void*)0), timers, 0); | |||
296 | assert(!timers_is_full(timers[0]))((void) sizeof ((!timers_is_full(timers[0])) ? 1 : 0), __extension__ ({ if (!timers_is_full(timers[0])) ; else __assert_fail ("!timers_is_full(timers[0])" , "su_timer.c", 296, __extension__ __PRETTY_FUNCTION__); })); | |||
297 | if (timers_is_full(timers[0])) | |||
298 | return -1; | |||
299 | } | |||
300 | ||||
301 | retval = timers_add(timers[0], t); assert(retval == 0)((void) sizeof ((retval == 0) ? 1 : 0), __extension__ ({ if ( retval == 0) ; else __assert_fail ("retval == 0", "su_timer.c" , 301, __extension__ __PRETTY_FUNCTION__); })); | |||
302 | ||||
303 | return retval; | |||
304 | } | |||
305 | ||||
306 | /**@internal Validate timer @a t and return pointer to per-port timer tree. | |||
307 | * | |||
308 | * @retval pointer to pointer to timer tree when successful | |||
309 | * @retval NULL upon an error | |||
310 | */ | |||
311 | static | |||
312 | su_timer_queue_t *su_timer_queue(su_timer_t const *t, | |||
313 | int use_sut_duration, | |||
314 | char const *caller) | |||
315 | { | |||
316 | su_timer_queue_t *timers; | |||
317 | ||||
318 | if (t == NULL((void*)0)) { | |||
319 | SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 320, "%s(%p): %s\n" , caller, (void *)t, "NULL argument")) : (void)0) | |||
320 | "NULL argument"))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 320, "%s(%p): %s\n" , caller, (void *)t, "NULL argument")) : (void)0); | |||
321 | return NULL((void*)0); | |||
322 | } | |||
323 | ||||
324 | if (use_sut_duration && t->sut_duration == 0) { | |||
325 | assert(t->sut_duration > 0)((void) sizeof ((t->sut_duration > 0) ? 1 : 0), __extension__ ({ if (t->sut_duration > 0) ; else __assert_fail ("t->sut_duration > 0" , "su_timer.c", 325, __extension__ __PRETTY_FUNCTION__); })); | |||
326 | SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 327, "%s(%p): %s\n" , caller, (void *)t, "timer without default duration")) : (void )0) | |||
327 | "timer without default duration"))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 327, "%s(%p): %s\n" , caller, (void *)t, "timer without default duration")) : (void )0); | |||
328 | return NULL((void*)0); | |||
329 | } | |||
330 | ||||
331 | if (t->sut_deferrable) | |||
332 | timers = su_task_deferrable(t->sut_task); | |||
333 | else | |||
334 | timers = su_task_timers(t->sut_task); | |||
335 | ||||
336 | if (timers == NULL((void*)0)) { | |||
337 | SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t, "invalid timer"))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 337, "%s(%p): %s\n" , caller, (void *)t, "invalid timer")) : (void)0); | |||
338 | return NULL((void*)0); | |||
339 | } | |||
340 | else if (timers_is_full(timers[0]) && timers_resize(NULL((void*)0), timers, 0) == -1) { | |||
341 | SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t, "timer queue failed"))((((su_log_global) != ((void*)0) && (su_log_global)-> log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) && (su_log_global)->log_init > 1) ? (su_log_global)->log_level : su_log_default->log_level)) >= 1 ? (_su_llog((su_log_global ), 1, "su_timer.c", (const char *)__func__, 341, "%s(%p): %s\n" , caller, (void *)t, "timer queue failed")) : (void)0); | |||
342 | return NULL((void*)0); | |||
343 | } | |||
344 | ||||
345 | return timers; | |||
346 | } | |||
347 | ||||
348 | ||||
349 | /**Create a timer. | |||
350 | * | |||
351 | * Allocate and initialize an instance of su_timer_t. | |||
352 | * | |||
353 | * @param task a task for root object with which the timer will be associated | |||
354 | * @param msec the default duration of the timer in milliseconds | |||
355 | * | |||
356 | * @return A pointer to allocated timer instance, NULL on error. | |||
357 | */ | |||
358 | su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec) | |||
359 | { | |||
360 | su_timer_t *retval; | |||
361 | ||||
362 | assert(msec >= 0)((void) sizeof ((msec >= 0) ? 1 : 0), __extension__ ({ if ( msec >= 0) ; else __assert_fail ("msec >= 0", "su_timer.c" , 362, __extension__ __PRETTY_FUNCTION__); })); | |||
363 | ||||
364 | if (!su_task_cmp(task, su_task_null)) | |||
365 | return NULL((void*)0); | |||
366 | ||||
367 | retval = su_zalloc(NULL((void*)0), sizeof(*retval)); | |||
368 | if (retval) { | |||
369 | su_task_copy(retval->sut_task, task); | |||
370 | retval->sut_duration = msec; | |||
371 | } | |||
372 | ||||
373 | return retval; | |||
374 | } | |||
375 | ||||
376 | ||||
377 | /** Destroy a timer. | |||
378 | * | |||
379 | * Deinitialize and free an instance of su_timer_t. | |||
380 | * | |||
381 | * @param t pointer to the timer object | |||
382 | */ | |||
383 | void su_timer_destroy(su_timer_t *t) | |||
384 | { | |||
385 | if (t) { | |||
386 | su_timer_reset(t); | |||
387 | su_task_deinit(t->sut_task); | |||
388 | su_free(NULL((void*)0), t); | |||
389 | } | |||
390 | } | |||
391 | ||||
392 | /** Check if the timer has been set. | |||
393 | * | |||
394 | * @param t pointer to a timer object | |||
395 | * | |||
396 | * @return Nonzero if set, zero if reset. | |||
397 | * | |||
398 | * @NEW_1_12_11 | |||
399 | */ | |||
400 | int su_timer_is_set(su_timer_t const *t) | |||
401 | { | |||
402 | return t && t->sut_set != 0; | |||
403 | } | |||
404 | ||||
405 | /**Return when the timer has been last expired. | |||
406 | * | |||
407 | * @param t pointer to a timer object | |||
408 | * | |||
409 | * @return Timestamp (as returned by su_time()). | |||
410 | * | |||
411 | * @note If the timer is running (set with su_timer_run()), the returned | |||
412 | * timestamp not the actual time but it is rather calculated from the | |||
413 | * initial timestamp. | |||
414 | * | |||
415 | * @NEW_1_12_11 | |||
416 | */ | |||
417 | su_time_t su_timer_latest(su_timer_t const *t) | |||
418 | { | |||
419 | su_time_t tv = { 0, 0 }; | |||
420 | ||||
421 | return t ? t->sut_when : tv; | |||
422 | } | |||
423 | ||||
424 | /** Set the timer for the given @a interval. | |||
425 | * | |||
426 | * Sets (starts) the given timer to expire after the specified duration. | |||
427 | * | |||
428 | * @param t pointer to the timer object | |||
429 | * @param wakeup pointer to the wakeup function | |||
430 | * @param arg argument given to the wakeup function | |||
431 | * @param interval duration in milliseconds before timer wakeup is called | |||
432 | * | |||
433 | * @return 0 if successful, -1 otherwise. | |||
434 | */ | |||
435 | int su_timer_set_interval(su_timer_t *t, | |||
436 | su_timer_f wakeup, | |||
437 | su_timer_arg_t *arg, | |||
438 | su_duration_t interval) | |||
439 | { | |||
440 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_interval"); | |||
441 | ||||
442 | return su_timer_set0(timers, t, wakeup, arg, su_now(), interval); | |||
443 | } | |||
444 | ||||
445 | /** Set the timer for the default interval. | |||
446 | * | |||
447 | * Sets (starts) the given timer to expire after the default duration. | |||
448 | * | |||
449 | * The timer must have an default duration. | |||
450 | * | |||
451 | * @param t pointer to the timer object | |||
452 | * @param wakeup pointer to the wakeup function | |||
453 | * @param arg argument given to the wakeup function | |||
454 | * | |||
455 | * @return 0 if successful, -1 otherwise. | |||
456 | */ | |||
457 | int su_timer_set(su_timer_t *t, | |||
458 | su_timer_f wakeup, | |||
459 | su_timer_arg_t *arg) | |||
460 | { | |||
461 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set"); | |||
462 | ||||
463 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
464 | } | |||
465 | ||||
466 | /** Set timer at known time. | |||
467 | * | |||
468 | * Sets the timer to expire at given time. | |||
469 | * | |||
470 | * @param t pointer to the timer object | |||
471 | * @param wakeup pointer to the wakeup function | |||
472 | * @param arg argument given to the wakeup function | |||
473 | * @param when time structure defining the wakeup time | |||
474 | * | |||
475 | * @return 0 if successful, -1 otherwise. | |||
476 | */ | |||
477 | int su_timer_set_at(su_timer_t *t, | |||
478 | su_timer_f wakeup, | |||
479 | su_wakeup_arg_t *arg, | |||
480 | su_time_t when) | |||
481 | { | |||
482 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_at"); | |||
483 | ||||
484 | return su_timer_set0(timers, t, wakeup, arg, when, 0); | |||
485 | } | |||
486 | ||||
487 | /** Set the timer for regular intervals. | |||
488 | * | |||
489 | * Run the given timer continuously, call wakeup function repeately in the | |||
490 | * default interval. If a wakeup call is missed, try to make it up (in other | |||
491 | * words, this kind of timer fails miserably if time is adjusted and it | |||
492 | * should really use /proc/uptime instead of gettimeofday()). | |||
493 | * | |||
494 | * While a continously running timer is active it @b must @b not @b be @b | |||
495 | * set using su_timer_set() or su_timer_set_at(). | |||
496 | * | |||
497 | * The timer must have an non-zero default interval. | |||
498 | * | |||
499 | * @param t pointer to the timer object | |||
500 | * @param wakeup pointer to the wakeup function | |||
501 | * @param arg argument given to the wakeup function | |||
502 | * | |||
503 | * @return 0 if successful, -1 otherwise. | |||
504 | */ | |||
505 | int su_timer_run(su_timer_t *t, | |||
506 | su_timer_f wakeup, | |||
507 | su_timer_arg_t *arg) | |||
508 | { | |||
509 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_run"); | |||
510 | ||||
511 | if (timers == NULL((void*)0)) | |||
512 | return -1; | |||
513 | ||||
514 | t->sut_running = run_at_intervals; | |||
515 | t->sut_woken = 0; | |||
516 | ||||
517 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
518 | } | |||
519 | ||||
520 | /**Set the timer for regular intervals. | |||
521 | * | |||
522 | * Run the given timer continuously, call wakeup function repeately in the | |||
523 | * default interval. While a continously running timer is active it @b must | |||
524 | * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike | |||
525 | * su_timer_run(), set for ever timer does not try to catchup missed | |||
526 | * callbacks. | |||
527 | * | |||
528 | * The timer must have an non-zero default interval. | |||
529 | * | |||
530 | * @param t pointer to the timer object | |||
531 | * @param wakeup pointer to the wakeup function | |||
532 | * @param arg argument given to the wakeup function | |||
533 | * | |||
534 | * @return 0 if successful, -1 otherwise. | |||
535 | */ | |||
536 | int su_timer_set_for_ever(su_timer_t *t, | |||
537 | su_timer_f wakeup, | |||
538 | su_timer_arg_t *arg) | |||
539 | { | |||
540 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set_for_ever"); | |||
541 | ||||
542 | if (timers == NULL((void*)0)) | |||
543 | return -1; | |||
544 | ||||
545 | t->sut_running = run_for_ever; | |||
546 | t->sut_woken = 0; | |||
547 | ||||
548 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
549 | } | |||
550 | ||||
551 | /**Reset the timer. | |||
552 | * | |||
553 | * Resets (stops) the given timer. | |||
554 | * | |||
555 | * @param t pointer to the timer object | |||
556 | * | |||
557 | * @return 0 if successful, -1 otherwise. | |||
558 | */ | |||
559 | int su_timer_reset(su_timer_t *t) | |||
560 | { | |||
561 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_reset"); | |||
562 | ||||
563 | if (timers == NULL((void*)0)) | |||
564 | return -1; | |||
565 | ||||
566 | if (SU_TIMER_IS_SET(t)((t)->sut_set != 0)) | |||
567 | timers_remove(timers[0], t->sut_set); | |||
568 | ||||
569 | t->sut_wakeup = NULL((void*)0); | |||
570 | t->sut_arg = NULL((void*)0); | |||
571 | t->sut_running = reset; | |||
572 | ||||
573 | return 0; | |||
574 | } | |||
575 | ||||
576 | /** @internal Check for expired timers in queue. | |||
577 | * | |||
578 | * The function su_timer_expire() checks a timer queue and executes and | |||
579 | * removes expired timers from the queue. It also calculates the time when | |||
580 | * the next timer expires. | |||
581 | * | |||
582 | * @param timers pointer to the timer queue | |||
583 | * @param timeout timeout in milliseconds [IN/OUT] | |||
584 | * @param now current timestamp | |||
585 | * | |||
586 | * @return | |||
587 | * The number of expired timers. | |||
588 | */ | |||
589 | int su_timer_expire(su_timer_queue_t * const timers, | |||
590 | su_duration_t *timeout, | |||
591 | su_time_t now) | |||
592 | { | |||
593 | su_timer_t *t; | |||
594 | su_timer_f f; | |||
595 | int n = 0; | |||
596 | ||||
597 | if (timers_used(timers[0]) == 0) | |||
| ||||
598 | return 0; | |||
599 | ||||
600 | while ((t = timers_get(timers[0], 1))) { | |||
601 | if (SU_TIME_CMP(t->sut_when, now)su_time_cmp(t->sut_when, now) > 0) { | |||
602 | su_duration_t at = su_duration(t->sut_when, now); | |||
603 | ||||
604 | if (at < *timeout || *timeout < 0) | |||
605 | *timeout = at; | |||
606 | ||||
607 | break; | |||
608 | } | |||
609 | ||||
610 | timers_remove(timers[0], 1); | |||
611 | ||||
612 | f = t->sut_wakeup; t->sut_wakeup = NULL((void*)0); | |||
613 | assert(f)((void) sizeof ((f) ? 1 : 0), __extension__ ({ if (f) ; else __assert_fail ("f", "su_timer.c", 613, __extension__ __PRETTY_FUNCTION__); })); | |||
614 | ||||
615 | if (t->sut_running == run_at_intervals) { | |||
616 | while (t->sut_running == run_at_intervals && | |||
617 | t->sut_set == 0 && | |||
618 | t->sut_duration > 0) { | |||
619 | if (su_time_diff(t->sut_when, now) > 0) { | |||
620 | su_timer_set0(timers, t, f, t->sut_arg, t->sut_when, 0); | |||
621 | break; | |||
622 | } | |||
623 | t->sut_when = su_time_add(t->sut_when, t->sut_duration); | |||
624 | t->sut_woken++; | |||
625 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++; | |||
626 | } | |||
627 | } | |||
628 | else if (t->sut_running == run_for_ever) { | |||
629 | t->sut_woken++; | |||
630 | t->sut_when = now; | |||
631 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++; | |||
632 | if (t->sut_running == run_for_ever && t->sut_set == 0) | |||
633 | su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration); | |||
634 | } | |||
635 | else { | |||
636 | t->sut_when = now; | |||
637 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++; | |||
638 | } | |||
639 | } | |||
640 | ||||
641 | return n; | |||
642 | } | |||
643 | ||||
644 | ||||
645 | /** Calculate duration in milliseconds until next timer expires. */ | |||
646 | su_duration_t su_timer_next_expires(su_timer_queue_t const *timers, | |||
647 | su_time_t now) | |||
648 | { | |||
649 | su_duration_t next = SU_DURATION_MAXSU_DURATION_MAX; | |||
650 | ||||
651 | su_timer_t const *t; | |||
652 | ||||
653 | t = timers ? timers_get(timers[0], 1) : NULL((void*)0); | |||
654 | ||||
655 | if (t) { | |||
656 | next = su_duration(t->sut_when, now); | |||
657 | if (next < 0) | |||
658 | next = 0; | |||
659 | } | |||
660 | ||||
661 | return next; | |||
662 | } | |||
663 | ||||
664 | /** | |||
665 | * Resets and frees all timers belonging to a task. | |||
666 | * | |||
667 | * The function su_timer_destroy_all() resets and frees all timers belonging | |||
668 | * to the specified task in the queue. | |||
669 | * | |||
670 | * @param timers pointer to the timers | |||
671 | * @param task task owning the timers | |||
672 | * | |||
673 | * @return Number of timers reset. | |||
674 | */ | |||
675 | int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task) | |||
676 | { | |||
677 | size_t i; | |||
678 | int n = 0; | |||
679 | ||||
680 | if (!timers) | |||
681 | return 0; | |||
682 | ||||
683 | timers_sort(timers[0]); | |||
684 | ||||
685 | for (i = timers_used(timers[0]); i > 0; i--) { | |||
686 | su_timer_t *t = timers_get(timers[0], i); | |||
687 | ||||
688 | if (su_task_cmp(task, t->sut_task)) | |||
689 | continue; | |||
690 | ||||
691 | timers_remove(timers[0], i); | |||
692 | ||||
693 | su_free(NULL((void*)0), t); | |||
694 | n++; | |||
695 | } | |||
696 | ||||
697 | if (!timers_used(timers[0])) | |||
698 | free(timers->private), timers->private = NULL((void*)0); | |||
699 | ||||
700 | return n; | |||
701 | } | |||
702 | ||||
703 | /** Get the root object owning the timer. | |||
704 | * | |||
705 | * Return pointer to the root object owning the timer. | |||
706 | * | |||
707 | * @param t pointer to the timer | |||
708 | * | |||
709 | * @return Pointer to the root object. | |||
710 | */ | |||
711 | su_root_t *su_timer_root(su_timer_t const *t) | |||
712 | { | |||
713 | return t ? su_task_root(t->sut_task) : NULL((void*)0); | |||
714 | } | |||
715 | ||||
716 | ||||
717 | /** Change timer as deferrable (or as undeferrable). | |||
718 | * | |||
719 | * A deferrable timer is executed after the given timeout, however, the task | |||
720 | * tries to avoid being woken up only because the timeout. Deferable timers | |||
721 | * have their own queue and timers there are ignored when calculating the | |||
722 | * timeout for epoll()/select()/whatever unless the timeout would exceed the | |||
723 | * maximum defer time. The maximum defer time is 15 seconds by default, but | |||
724 | * it can be modified by su_root_set_max_defer(). | |||
725 | * | |||
726 | * @param t pointer to the timer | |||
727 | * @param value make timer deferrable if true, undeferrable if false | |||
728 | * | |||
729 | * @return 0 if succesful, -1 upon an error | |||
730 | * | |||
731 | * @sa su_root_set_max_defer() | |||
732 | * | |||
733 | * @NEW_1_12_7 | |||
734 | */ | |||
735 | int su_timer_deferrable(su_timer_t *t, int value) | |||
736 | { | |||
737 | if (t == NULL((void*)0) || su_task_deferrable(t->sut_task) == NULL((void*)0)) | |||
738 | return errno(*__errno_location ()) = EINVAL22, -1; | |||
739 | ||||
740 | t->sut_deferrable = value != 0; | |||
741 | ||||
742 | return 0; | |||
743 | } |