Bug Summary

File:su/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-26-205203-363-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)
21
Taking true branch
49
Assuming 'size' is 0
50
Taking false branch
201 return realloc(memory, size);
22
Memory is allocated
202 else
203 return free(memory), NULL((void*)0);
51
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; }
17
Assuming '_priv' is null
18
Taking false branch
42
Taking true branch
43
Taking true branch
44
Assuming 'new_size' is >= '_used'
45
Taking false branch
218 if (new_size < _min_size) new_size = _min_size; _bytes = (_offset + 1 + new_size) * sizeof(su_timer_t*);
19
Taking true branch
46
Assuming 'new_size' is >= '_min_size'
47
Taking false branch
219 (void)realloc_arg; _priv = timers_alloc(realloc_arg, *(struct timers_priv**)h, _bytes);
20
Calling 'timers_alloc'
23
Returned allocated memory
48
Calling 'timers_alloc'
52
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;
24
Assuming '_priv' is non-null
25
Taking false branch
53
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;
56
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} 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 */
274su_inlinestatic inline int
275su_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))
13
Taking false branch
38
Taking false branch
285 return -1;
286
287 if (SU_TIMER_IS_SET(t)((t)->sut_set != 0))
14
Taking false branch
39
Taking false branch
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])) {
15
Taking true branch
40
Taking true branch
295 timers_resize(NULL((void*)0), timers, 0);
16
Calling 'timers_resize'
26
Returned allocated memory
41
Calling 'timers_resize'
54
Returning; memory was released
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__); }))
;
55
Within the expansion of the macro 'assert':
a
Calling 'timers_is_full'
297 if (timers_is_full(timers[0]))
27
Taking false branch
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 */
311static
312su_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 */
358su_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 */
383void 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 */
400int 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 */
417su_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 */
435int 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 */
457int 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 */
477int 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 */
505int 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 */
536int 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 */
559int 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 */
589int 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)
1
Assuming the condition is false
2
Taking false branch
598 return 0;
599
600 while ((t = timers_get(timers[0], 1))) {
3
Loop condition is true. Entering loop body
29
Loop condition is true. Entering loop body
601 if (SU_TIME_CMP(t->sut_when, now)su_time_cmp(t->sut_when, now) > 0) {
4
Taking false branch
30
Taking false branch
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) {
5
Assuming the condition is false
6
Taking false branch
31
Assuming the condition is true
32
Taking true branch
616 while (t->sut_running == run_at_intervals &&
35
Loop condition is true. Entering loop body
617 t->sut_set == 0 &&
33
Assuming the condition is true
618 t->sut_duration > 0) {
34
Assuming the condition is true
619 if (su_time_diff(t->sut_when, now) > 0) {
36
Taking true branch
620 su_timer_set0(timers, t, f, t->sut_arg, t->sut_when, 0);
37
Calling 'su_timer_set0'
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) {
7
Assuming the condition is true
8
Taking true branch
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)
9
Assuming the condition is true
10
Assuming the condition is true
11
Taking true branch
633 su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration);
12
Calling 'su_timer_set0'
28
Returned allocated memory
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. */
646su_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 */
675int 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 */
711su_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 */
735int 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}