File: | u/su_timer.c |
Warning: | line 219, column 29 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 | } | |||
264 | 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; | |||
265 | ||||
266 | ||||
267 | #ifdef __clang__1 | |||
268 | #pragma clang diagnostic pop | |||
269 | #endif | |||
270 | ||||
271 | /**@internal Set the timer. | |||
272 | * | |||
273 | * @retval 0 when successful (always) | |||
274 | */ | |||
275 | su_inlinestatic inline int | |||
276 | su_timer_set0(su_timer_queue_t *timers, | |||
277 | su_timer_t *t, | |||
278 | su_timer_f wakeup, | |||
279 | su_wakeup_arg_t *arg, | |||
280 | su_time_t when, | |||
281 | su_duration_t offset) | |||
282 | { | |||
283 | int retval; | |||
284 | ||||
285 | if (timers == NULL((void*)0)) | |||
286 | return -1; | |||
287 | ||||
288 | if (SU_TIMER_IS_SET(t)((t)->sut_set != 0)) | |||
289 | timers_remove(timers[0], t->sut_set); | |||
290 | ||||
291 | t->sut_wakeup = wakeup; | |||
292 | t->sut_arg = arg; | |||
293 | t->sut_when = su_time_add(when, offset); | |||
294 | ||||
295 | if (timers_is_full(timers[0])) { | |||
296 | timers_resize(NULL((void*)0), timers, 0); | |||
297 | // assert(!timers_is_full(timers[0])); | |||
298 | if (timers_is_full(timers[0])) | |||
299 | return -1; | |||
300 | } | |||
301 | ||||
302 | 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" , 302, __extension__ __PRETTY_FUNCTION__); })); | |||
303 | ||||
304 | return retval; | |||
305 | } | |||
306 | ||||
307 | /**@internal Validate timer @a t and return pointer to per-port timer tree. | |||
308 | * | |||
309 | * @retval pointer to pointer to timer tree when successful | |||
310 | * @retval NULL upon an error | |||
311 | */ | |||
312 | static | |||
313 | su_timer_queue_t *su_timer_queue(su_timer_t const *t, | |||
314 | int use_sut_duration, | |||
315 | char const *caller) | |||
316 | { | |||
317 | su_timer_queue_t *timers; | |||
318 | ||||
319 | if (t == NULL((void*)0)) { | |||
320 | 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__, 321, "%s(%p): %s\n" , caller, (void *)t, "NULL argument")) : (void)0) | |||
321 | "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__, 321, "%s(%p): %s\n" , caller, (void *)t, "NULL argument")) : (void)0); | |||
322 | return NULL((void*)0); | |||
323 | } | |||
324 | ||||
325 | if (use_sut_duration && t->sut_duration == 0) { | |||
326 | 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", 326, __extension__ __PRETTY_FUNCTION__); })); | |||
327 | 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__, 328, "%s(%p): %s\n" , caller, (void *)t, "timer without default duration")) : (void )0) | |||
328 | "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__, 328, "%s(%p): %s\n" , caller, (void *)t, "timer without default duration")) : (void )0); | |||
329 | return NULL((void*)0); | |||
330 | } | |||
331 | ||||
332 | if (t->sut_deferrable) | |||
333 | timers = su_task_deferrable(t->sut_task); | |||
334 | else | |||
335 | timers = su_task_timers(t->sut_task); | |||
336 | ||||
337 | if (timers == NULL((void*)0)) { | |||
338 | 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__, 338, "%s(%p): %s\n" , caller, (void *)t, "invalid timer")) : (void)0); | |||
339 | return NULL((void*)0); | |||
340 | } | |||
341 | else if (timers_is_full(timers[0]) && timers_resize(NULL((void*)0), timers, 0) == -1) { | |||
342 | 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__, 342, "%s(%p): %s\n" , caller, (void *)t, "timer queue failed")) : (void)0); | |||
343 | return NULL((void*)0); | |||
344 | } | |||
345 | ||||
346 | return timers; | |||
347 | } | |||
348 | ||||
349 | ||||
350 | /**Create a timer. | |||
351 | * | |||
352 | * Allocate and initialize an instance of su_timer_t. | |||
353 | * | |||
354 | * @param task a task for root object with which the timer will be associated | |||
355 | * @param msec the default duration of the timer in milliseconds | |||
356 | * | |||
357 | * @return A pointer to allocated timer instance, NULL on error. | |||
358 | */ | |||
359 | su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec) | |||
360 | { | |||
361 | su_timer_t *retval; | |||
362 | ||||
363 | assert(msec >= 0)((void) sizeof ((msec >= 0) ? 1 : 0), __extension__ ({ if ( msec >= 0) ; else __assert_fail ("msec >= 0", "su_timer.c" , 363, __extension__ __PRETTY_FUNCTION__); })); | |||
364 | ||||
365 | if (!su_task_cmp(task, su_task_null)) | |||
366 | return NULL((void*)0); | |||
367 | ||||
368 | retval = su_zalloc(NULL((void*)0), sizeof(*retval)); | |||
369 | if (retval) { | |||
370 | su_task_copy(retval->sut_task, task); | |||
371 | retval->sut_duration = msec; | |||
372 | } | |||
373 | ||||
374 | return retval; | |||
375 | } | |||
376 | ||||
377 | ||||
378 | /** Destroy a timer. | |||
379 | * | |||
380 | * Deinitialize and free an instance of su_timer_t. | |||
381 | * | |||
382 | * @param t pointer to the timer object | |||
383 | */ | |||
384 | void su_timer_destroy(su_timer_t *t) | |||
385 | { | |||
386 | if (t) { | |||
387 | su_timer_reset(t); | |||
388 | su_task_deinit(t->sut_task); | |||
389 | su_free(NULL((void*)0), t); | |||
390 | } | |||
391 | } | |||
392 | ||||
393 | /** Check if the timer has been set. | |||
394 | * | |||
395 | * @param t pointer to a timer object | |||
396 | * | |||
397 | * @return Nonzero if set, zero if reset. | |||
398 | * | |||
399 | * @NEW_1_12_11 | |||
400 | */ | |||
401 | int su_timer_is_set(su_timer_t const *t) | |||
402 | { | |||
403 | return t && t->sut_set != 0; | |||
404 | } | |||
405 | ||||
406 | /**Return when the timer has been last expired. | |||
407 | * | |||
408 | * @param t pointer to a timer object | |||
409 | * | |||
410 | * @return Timestamp (as returned by su_time()). | |||
411 | * | |||
412 | * @note If the timer is running (set with su_timer_run()), the returned | |||
413 | * timestamp not the actual time but it is rather calculated from the | |||
414 | * initial timestamp. | |||
415 | * | |||
416 | * @NEW_1_12_11 | |||
417 | */ | |||
418 | su_time_t su_timer_latest(su_timer_t const *t) | |||
419 | { | |||
420 | su_time_t tv = { 0, 0 }; | |||
421 | ||||
422 | return t ? t->sut_when : tv; | |||
423 | } | |||
424 | ||||
425 | /** Set the timer for the given @a interval. | |||
426 | * | |||
427 | * Sets (starts) the given timer to expire after the specified duration. | |||
428 | * | |||
429 | * @param t pointer to the timer object | |||
430 | * @param wakeup pointer to the wakeup function | |||
431 | * @param arg argument given to the wakeup function | |||
432 | * @param interval duration in milliseconds before timer wakeup is called | |||
433 | * | |||
434 | * @return 0 if successful, -1 otherwise. | |||
435 | */ | |||
436 | int su_timer_set_interval(su_timer_t *t, | |||
437 | su_timer_f wakeup, | |||
438 | su_timer_arg_t *arg, | |||
439 | su_duration_t interval) | |||
440 | { | |||
441 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_interval"); | |||
442 | ||||
443 | return su_timer_set0(timers, t, wakeup, arg, su_now(), interval); | |||
444 | } | |||
445 | ||||
446 | /** Set the timer for the default interval. | |||
447 | * | |||
448 | * Sets (starts) the given timer to expire after the default duration. | |||
449 | * | |||
450 | * The timer must have an default duration. | |||
451 | * | |||
452 | * @param t pointer to the timer object | |||
453 | * @param wakeup pointer to the wakeup function | |||
454 | * @param arg argument given to the wakeup function | |||
455 | * | |||
456 | * @return 0 if successful, -1 otherwise. | |||
457 | */ | |||
458 | int su_timer_set(su_timer_t *t, | |||
459 | su_timer_f wakeup, | |||
460 | su_timer_arg_t *arg) | |||
461 | { | |||
462 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set"); | |||
463 | ||||
464 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
465 | } | |||
466 | ||||
467 | /** Set timer at known time. | |||
468 | * | |||
469 | * Sets the timer to expire at given time. | |||
470 | * | |||
471 | * @param t pointer to the timer object | |||
472 | * @param wakeup pointer to the wakeup function | |||
473 | * @param arg argument given to the wakeup function | |||
474 | * @param when time structure defining the wakeup time | |||
475 | * | |||
476 | * @return 0 if successful, -1 otherwise. | |||
477 | */ | |||
478 | int su_timer_set_at(su_timer_t *t, | |||
479 | su_timer_f wakeup, | |||
480 | su_wakeup_arg_t *arg, | |||
481 | su_time_t when) | |||
482 | { | |||
483 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_at"); | |||
484 | ||||
485 | return su_timer_set0(timers, t, wakeup, arg, when, 0); | |||
486 | } | |||
487 | ||||
488 | /** Set the timer for regular intervals. | |||
489 | * | |||
490 | * Run the given timer continuously, call wakeup function repeately in the | |||
491 | * default interval. If a wakeup call is missed, try to make it up (in other | |||
492 | * words, this kind of timer fails miserably if time is adjusted and it | |||
493 | * should really use /proc/uptime instead of gettimeofday()). | |||
494 | * | |||
495 | * While a continously running timer is active it @b must @b not @b be @b | |||
496 | * set using su_timer_set() or su_timer_set_at(). | |||
497 | * | |||
498 | * The timer must have an non-zero default interval. | |||
499 | * | |||
500 | * @param t pointer to the timer object | |||
501 | * @param wakeup pointer to the wakeup function | |||
502 | * @param arg argument given to the wakeup function | |||
503 | * | |||
504 | * @return 0 if successful, -1 otherwise. | |||
505 | */ | |||
506 | int su_timer_run(su_timer_t *t, | |||
507 | su_timer_f wakeup, | |||
508 | su_timer_arg_t *arg) | |||
509 | { | |||
510 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_run"); | |||
511 | ||||
512 | if (timers == NULL((void*)0)) | |||
513 | return -1; | |||
514 | ||||
515 | t->sut_running = run_at_intervals; | |||
516 | t->sut_woken = 0; | |||
517 | ||||
518 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
519 | } | |||
520 | ||||
521 | /**Set the timer for regular intervals. | |||
522 | * | |||
523 | * Run the given timer continuously, call wakeup function repeately in the | |||
524 | * default interval. While a continously running timer is active it @b must | |||
525 | * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike | |||
526 | * su_timer_run(), set for ever timer does not try to catchup missed | |||
527 | * callbacks. | |||
528 | * | |||
529 | * The timer must have an non-zero default interval. | |||
530 | * | |||
531 | * @param t pointer to the timer object | |||
532 | * @param wakeup pointer to the wakeup function | |||
533 | * @param arg argument given to the wakeup function | |||
534 | * | |||
535 | * @return 0 if successful, -1 otherwise. | |||
536 | */ | |||
537 | int su_timer_set_for_ever(su_timer_t *t, | |||
538 | su_timer_f wakeup, | |||
539 | su_timer_arg_t *arg) | |||
540 | { | |||
541 | su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set_for_ever"); | |||
542 | ||||
543 | if (timers == NULL((void*)0)) | |||
544 | return -1; | |||
545 | ||||
546 | t->sut_running = run_for_ever; | |||
547 | t->sut_woken = 0; | |||
548 | ||||
549 | return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration); | |||
550 | } | |||
551 | ||||
552 | /**Reset the timer. | |||
553 | * | |||
554 | * Resets (stops) the given timer. | |||
555 | * | |||
556 | * @param t pointer to the timer object | |||
557 | * | |||
558 | * @return 0 if successful, -1 otherwise. | |||
559 | */ | |||
560 | int su_timer_reset(su_timer_t *t) | |||
561 | { | |||
562 | su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_reset"); | |||
563 | ||||
564 | if (timers == NULL((void*)0)) | |||
565 | return -1; | |||
566 | ||||
567 | if (SU_TIMER_IS_SET(t)((t)->sut_set != 0)) | |||
568 | timers_remove(timers[0], t->sut_set); | |||
569 | ||||
570 | t->sut_wakeup = NULL((void*)0); | |||
571 | t->sut_arg = NULL((void*)0); | |||
572 | t->sut_running = reset; | |||
573 | ||||
574 | return 0; | |||
575 | } | |||
576 | ||||
577 | /** @internal Check for expired timers in queue. | |||
578 | * | |||
579 | * The function su_timer_expire() checks a timer queue and executes and | |||
580 | * removes expired timers from the queue. It also calculates the time when | |||
581 | * the next timer expires. | |||
582 | * | |||
583 | * @param timers pointer to the timer queue | |||
584 | * @param timeout timeout in milliseconds [IN/OUT] | |||
585 | * @param now current timestamp | |||
586 | * | |||
587 | * @return | |||
588 | * The number of expired timers. | |||
589 | */ | |||
590 | int su_timer_expire(su_timer_queue_t * const timers, | |||
591 | su_duration_t *timeout, | |||
592 | su_time_t now) | |||
593 | { | |||
594 | su_timer_t *t; | |||
595 | su_timer_f f; | |||
596 | int n = 0; | |||
597 | ||||
598 | if (timers_used(timers[0]) == 0) | |||
| ||||
599 | return 0; | |||
600 | ||||
601 | while ((t = timers_get(timers[0], 1))) { | |||
602 | if (SU_TIME_CMP(t->sut_when, now)su_time_cmp(t->sut_when, now) > 0) { | |||
603 | su_duration_t at = su_duration(t->sut_when, now); | |||
604 | ||||
605 | if (at < *timeout || *timeout < 0) | |||
606 | *timeout = at; | |||
607 | ||||
608 | break; | |||
609 | } | |||
610 | ||||
611 | timers_remove(timers[0], 1); | |||
612 | ||||
613 | f = t->sut_wakeup; t->sut_wakeup = NULL((void*)0); | |||
614 | assert(f)((void) sizeof ((f) ? 1 : 0), __extension__ ({ if (f) ; else __assert_fail ("f", "su_timer.c", 614, __extension__ __PRETTY_FUNCTION__); })); | |||
615 | ||||
616 | if (t->sut_running == run_at_intervals) { | |||
617 | while (t->sut_running == run_at_intervals && | |||
618 | t->sut_set == 0 && | |||
619 | t->sut_duration > 0) { | |||
620 | if (su_time_diff(t->sut_when, now) > 0) { | |||
621 | su_timer_set0(timers, t, f, t->sut_arg, t->sut_when, 0); | |||
622 | break; | |||
623 | } | |||
624 | t->sut_when = su_time_add(t->sut_when, t->sut_duration); | |||
625 | t->sut_woken++; | |||
626 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++; | |||
627 | } | |||
628 | } | |||
629 | else if (t->sut_running == run_for_ever) { | |||
630 | t->sut_woken++; | |||
631 | t->sut_when = now; | |||
632 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++; | |||
633 | if (t->sut_running == run_for_ever && t->sut_set == 0) | |||
634 | su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration); | |||
635 | } | |||
636 | else { | |||
637 | t->sut_when = now; | |||
638 | f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++; | |||
639 | } | |||
640 | } | |||
641 | ||||
642 | return n; | |||
643 | } | |||
644 | ||||
645 | ||||
646 | /** Calculate duration in milliseconds until next timer expires. */ | |||
647 | su_duration_t su_timer_next_expires(su_timer_queue_t const *timers, | |||
648 | su_time_t now) | |||
649 | { | |||
650 | su_duration_t next = SU_DURATION_MAXSU_DURATION_MAX; | |||
651 | ||||
652 | su_timer_t const *t; | |||
653 | ||||
654 | t = timers ? timers_get(timers[0], 1) : NULL((void*)0); | |||
655 | ||||
656 | if (t) { | |||
657 | next = su_duration(t->sut_when, now); | |||
658 | if (next < 0) | |||
659 | next = 0; | |||
660 | } | |||
661 | ||||
662 | return next; | |||
663 | } | |||
664 | ||||
665 | /** | |||
666 | * Resets and frees all timers belonging to a task. | |||
667 | * | |||
668 | * The function su_timer_destroy_all() resets and frees all timers belonging | |||
669 | * to the specified task in the queue. | |||
670 | * | |||
671 | * @param timers pointer to the timers | |||
672 | * @param task task owning the timers | |||
673 | * | |||
674 | * @return Number of timers reset. | |||
675 | */ | |||
676 | int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task) | |||
677 | { | |||
678 | size_t i; | |||
679 | int n = 0; | |||
680 | ||||
681 | if (!timers) | |||
682 | return 0; | |||
683 | ||||
684 | timers_sort(timers[0]); | |||
685 | ||||
686 | for (i = timers_used(timers[0]); i > 0; i--) { | |||
687 | su_timer_t *t = timers_get(timers[0], i); | |||
688 | ||||
689 | if (su_task_cmp(task, t->sut_task)) | |||
690 | continue; | |||
691 | ||||
692 | timers_remove(timers[0], i); | |||
693 | ||||
694 | su_free(NULL((void*)0), t); | |||
695 | n++; | |||
696 | } | |||
697 | ||||
698 | if (!timers_used(timers[0])) | |||
699 | free(timers->private), timers->private = NULL((void*)0); | |||
700 | ||||
701 | return n; | |||
702 | } | |||
703 | ||||
704 | /** Get the root object owning the timer. | |||
705 | * | |||
706 | * Return pointer to the root object owning the timer. | |||
707 | * | |||
708 | * @param t pointer to the timer | |||
709 | * | |||
710 | * @return Pointer to the root object. | |||
711 | */ | |||
712 | su_root_t *su_timer_root(su_timer_t const *t) | |||
713 | { | |||
714 | return t ? su_task_root(t->sut_task) : NULL((void*)0); | |||
715 | } | |||
716 | ||||
717 | ||||
718 | /** Change timer as deferrable (or as undeferrable). | |||
719 | * | |||
720 | * A deferrable timer is executed after the given timeout, however, the task | |||
721 | * tries to avoid being woken up only because the timeout. Deferable timers | |||
722 | * have their own queue and timers there are ignored when calculating the | |||
723 | * timeout for epoll()/select()/whatever unless the timeout would exceed the | |||
724 | * maximum defer time. The maximum defer time is 15 seconds by default, but | |||
725 | * it can be modified by su_root_set_max_defer(). | |||
726 | * | |||
727 | * @param t pointer to the timer | |||
728 | * @param value make timer deferrable if true, undeferrable if false | |||
729 | * | |||
730 | * @return 0 if succesful, -1 upon an error | |||
731 | * | |||
732 | * @sa su_root_set_max_defer() | |||
733 | * | |||
734 | * @NEW_1_12_7 | |||
735 | */ | |||
736 | int su_timer_deferrable(su_timer_t *t, int value) | |||
737 | { | |||
738 | if (t == NULL((void*)0) || su_task_deferrable(t->sut_task) == NULL((void*)0)) | |||
739 | return errno(*__errno_location ()) = EINVAL22, -1; | |||
740 | ||||
741 | t->sut_deferrable = value != 0; | |||
742 | ||||
743 | return 0; | |||
744 | } |