Bug Summary

File:su_timer.c
Warning:line 229, column 73
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name su_timer.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/su -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-31-193534-364-1 -x c su_timer.c -faddrsig
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
38typedef 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
159struct 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 */
173enum 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
181HEAP_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
183su_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
188su_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
196su_inlinestatic inline void *timers_alloc(void *argument, void *memory, size_t size)
197{
198 (void)argument;
199
200 if (size)
13
Taking true branch
33
Assuming 'size' is 0
34
Taking false branch
201 return realloc(memory, size);
14
Memory is allocated
202 else
203 return free(memory), NULL((void*)0);
35
Memory is released
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);
213static __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; }
9
Assuming '_priv' is null
10
Taking false branch
26
Taking true branch
27
Taking true branch
28
Assuming 'new_size' is >= '_used'
29
Taking false branch
218 if (new_size < _min_size) new_size = _min_size; _bytes = (_offset + 1 + new_size) * sizeof(su_timer_t*);
11
Taking true branch
30
Assuming 'new_size' is >= '_min_size'
31
Taking false branch
219 (void)realloc_arg; _priv = timers_alloc(realloc_arg, *(struct timers_priv**)h, _bytes);
12
Calling 'timers_alloc'
15
Returned allocated memory
32
Calling 'timers_alloc'
36
Returning; memory was released via 2nd parameter
220 if (!_priv) return -1; *(struct timers_priv**)h = _priv; _priv->_size = new_size; _priv->_used = _used; return 0;
16
Assuming '_priv' is non-null
17
Taking false branch
37
Taking true branch
221}
222static __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}
226static __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;
40
Use of memory after it is freed
230}
231static __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}
241static __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}
259static __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}
264static __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 */
275su_inlinestatic inline int
276su_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))
22
Taking false branch
286 return -1;
287
288 if (SU_TIMER_IS_SET(t)((t)->sut_set != 0))
23
Taking true branch
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])) {
24
Taking true branch
296 timers_resize(NULL((void*)0), timers, 0);
25
Calling 'timers_resize'
38
Returning; memory was released
297 // assert(!timers_is_full(timers[0]));
298 if (timers_is_full(timers[0]))
39
Calling 'timers_is_full'
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 */
312static
313su_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)) {
2
Assuming 't' is not equal to NULL
3
Taking false branch
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)
4
Assuming the condition is false
5
Taking false branch
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)) {
6
Assuming 'timers' is not equal to NULL
7
Taking false branch
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) {
8
Calling 'timers_resize'
18
Returned allocated memory
19
Taking false branch
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 */
359su_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 */
384void 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 */
401int 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 */
418su_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 */
436int 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 */
458int 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 */
478int 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");
1
Calling 'su_timer_queue'
20
Returned allocated memory
484
485 return su_timer_set0(timers, t, wakeup, arg, when, 0);
21
Calling 'su_timer_set0'
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 */
506int 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 */
537int 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 */
560int 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 */
590int 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. */
647su_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 */
676int 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 */
712su_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 */
736int 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}