Bug Summary

File:su_timer.c
Warning:line 211, column 1
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-181005-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)
18
Taking true branch
37
Assuming 'size' is 0
38
Taking false branch
201 return realloc(memory, size);
19
Memory is allocated
202 else
203 return free(memory), NULL((void*)0);
39
Memory is released
204}
205
206#ifdef __clang__1
207#pragma clang diagnostic push
208#pragma clang diagnostic ignored "-Wunused-function"
209#endif
210
211HEAP_BODIES(su_inline, su_timer_queue_t, timers_, su_timer_t *,static inline int timers_resize(void *realloc_arg, su_timer_queue_t
h[1], size_t new_size) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[2]; }; struct timers_priv *_priv; size_t
_offset = (__builtin_offsetof(struct timers_priv, _heap[1]) -
1) / sizeof (su_timer_t *); size_t _min_size = 32 - _offset;
size_t _bytes; size_t _used = 0; _priv = *(void **)h; if (_priv
) { if (new_size == 0) new_size = 2 * _priv->_size + _offset
+ 1; _used = _priv->_used; if (new_size < _used) new_size
= _used; } if (new_size < _min_size) new_size = _min_size
; _bytes = (_offset + 1 + new_size) * sizeof (su_timer_t *); (
void)realloc_arg; _priv = timers_alloc(realloc_arg, *(struct timers_priv
**)h, _bytes); if (!_priv) return -1; *(struct timers_priv *
*)h = _priv; _priv->_size = new_size; _priv->_used = _used
; return 0; } static inline int timers_free(void *realloc_arg
, su_timer_queue_t h[1]) { (void)realloc_arg; *(void **)h = timers_alloc
(realloc_arg, *(void **)h, 0); return 0; } static inline int timers_is_full
(su_timer_queue_t h) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[1];}; struct timers_priv *_priv = *(void
**)&h; return _priv == ((void*)0) || _priv->_used >=
_priv->_size; } static inline int timers_add(su_timer_queue_t
h, su_timer_t * e) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[1];}; struct timers_priv *_priv = *(void
**)&h; su_timer_t * *heap = _priv->_heap - 1; size_t i
, parent; if (_priv == ((void*)0) || _priv->_used >= _priv
->_size) return -1; for (i = ++_priv->_used; i > 1; i
= parent) { parent = i / 2; if (!timers_less(e, heap[parent]
)) break; timers_set(heap, i, heap[parent]); } timers_set(heap
, i, e); return 0; } static inline su_timer_t * timers_remove
(su_timer_queue_t h, size_t index) { struct timers_priv { size_t
_size, _used; su_timer_t * _heap[1];}; struct timers_priv *_priv
= *(void **)&h; su_timer_t * *heap = _priv->_heap - 1
; su_timer_t * retval[1]; su_timer_t * e; size_t top, left, right
, move; if (index - 1 >= _priv->_used) return (((void*)
0)); move = _priv->_used--; timers_set(retval, 0, heap[index
]); for (top = index;;index = top) { left = 2 * top; right = 2
* top + 1; if (left >= move) break; if (right < move &&
timers_less(heap[right], heap[left])) top = right; else top =
left; timers_set(heap, index, heap[top]); } if (index == move
) return *retval; e = heap[move]; for (; index > 1; index =
top) { top = index / 2; if (!timers_less(e, heap[top])) break
; timers_set(heap, index, heap[top]); } timers_set(heap, index
, e); return *retval; } static inline su_timer_t * timers_get
(su_timer_queue_t h, size_t index) { struct timers_priv { size_t
_size, _used; su_timer_t * _heap[1];}; struct timers_priv *_priv
= *(void **)&h; if (--index >= _priv->_used) return
(((void*)0)); return _priv->_heap[index]; } 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
17
Within the expansion of the macro 'HEAP_BODIES':
a
Assuming '_priv' is null
b
Calling 'timers_alloc'
c
Returned allocated memory
d
Assuming '_priv' is non-null
36
Within the expansion of the macro 'HEAP_BODIES':
a
Assuming 'new_size' is >= '_used'
b
Assuming 'new_size' is >= '_min_size'
c
Calling 'timers_alloc'
d
Returning; memory was released via 2nd parameter
42
Within the expansion of the macro 'HEAP_BODIES':
a
Use of memory after it is freed
212 timers_less, timers_set, timers_alloc, NULL)static inline int timers_resize(void *realloc_arg, su_timer_queue_t
h[1], size_t new_size) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[2]; }; struct timers_priv *_priv; size_t
_offset = (__builtin_offsetof(struct timers_priv, _heap[1]) -
1) / sizeof (su_timer_t *); size_t _min_size = 32 - _offset;
size_t _bytes; size_t _used = 0; _priv = *(void **)h; if (_priv
) { if (new_size == 0) new_size = 2 * _priv->_size + _offset
+ 1; _used = _priv->_used; if (new_size < _used) new_size
= _used; } if (new_size < _min_size) new_size = _min_size
; _bytes = (_offset + 1 + new_size) * sizeof (su_timer_t *); (
void)realloc_arg; _priv = timers_alloc(realloc_arg, *(struct timers_priv
**)h, _bytes); if (!_priv) return -1; *(struct timers_priv *
*)h = _priv; _priv->_size = new_size; _priv->_used = _used
; return 0; } static inline int timers_free(void *realloc_arg
, su_timer_queue_t h[1]) { (void)realloc_arg; *(void **)h = timers_alloc
(realloc_arg, *(void **)h, 0); return 0; } static inline int timers_is_full
(su_timer_queue_t h) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[1];}; struct timers_priv *_priv = *(void
**)&h; return _priv == ((void*)0) || _priv->_used >=
_priv->_size; } static inline int timers_add(su_timer_queue_t
h, su_timer_t * e) { struct timers_priv { size_t _size, _used
; su_timer_t * _heap[1];}; struct timers_priv *_priv = *(void
**)&h; su_timer_t * *heap = _priv->_heap - 1; size_t i
, parent; if (_priv == ((void*)0) || _priv->_used >= _priv
->_size) return -1; for (i = ++_priv->_used; i > 1; i
= parent) { parent = i / 2; if (!timers_less(e, heap[parent]
)) break; timers_set(heap, i, heap[parent]); } timers_set(heap
, i, e); return 0; } static inline su_timer_t * timers_remove
(su_timer_queue_t h, size_t index) { struct timers_priv { size_t
_size, _used; su_timer_t * _heap[1];}; struct timers_priv *_priv
= *(void **)&h; su_timer_t * *heap = _priv->_heap - 1
; su_timer_t * retval[1]; su_timer_t * e; size_t top, left, right
, move; if (index - 1 >= _priv->_used) return (((void*)
0)); move = _priv->_used--; timers_set(retval, 0, heap[index
]); for (top = index;;index = top) { left = 2 * top; right = 2
* top + 1; if (left >= move) break; if (right < move &&
timers_less(heap[right], heap[left])) top = right; else top =
left; timers_set(heap, index, heap[top]); } if (index == move
) return *retval; e = heap[move]; for (; index > 1; index =
top) { top = index / 2; if (!timers_less(e, heap[top])) break
; timers_set(heap, index, heap[top]); } timers_set(heap, index
, e); return *retval; } static inline su_timer_t * timers_get
(su_timer_queue_t h, size_t index) { struct timers_priv { size_t
_size, _used; su_timer_t * _heap[1];}; struct timers_priv *_priv
= *(void **)&h; if (--index >= _priv->_used) return
(((void*)0)); return _priv->_heap[index]; } 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
;
213
214#ifdef __clang__1
215#pragma clang diagnostic pop
216#endif
217
218/**@internal Set the timer.
219 *
220 * @retval 0 when successful (always)
221 */
222su_inlinestatic inline int
223su_timer_set0(su_timer_queue_t *timers,
224 su_timer_t *t,
225 su_timer_f wakeup,
226 su_wakeup_arg_t *arg,
227 su_time_t when,
228 su_duration_t offset)
229{
230 int retval;
231
232 if (timers == NULL((void*)0))
13
Taking false branch
32
Taking false branch
233 return -1;
234
235 if (SU_TIMER_IS_SET(t)((t)->sut_set != 0))
14
Taking false branch
33
Taking false branch
236 timers_remove(timers[0], t->sut_set);
237
238 t->sut_wakeup = wakeup;
239 t->sut_arg = arg;
240 t->sut_when = su_time_add(when, offset);
241
242 if (timers_is_full(timers[0])) {
15
Taking true branch
34
Taking true branch
243 timers_resize(NULL((void*)0), timers, 0);
16
Calling 'timers_resize'
20
Returned allocated memory
35
Calling 'timers_resize'
40
Returning; memory was released
244 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", 244, __extension__ __PRETTY_FUNCTION__); }))
;
41
Within the expansion of the macro 'assert':
a
Calling 'timers_is_full'
245 if (timers_is_full(timers[0]))
21
Taking false branch
246 return -1;
247 }
248
249 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"
, 249, __extension__ __PRETTY_FUNCTION__); }))
;
250
251 return retval;
252}
253
254/**@internal Validate timer @a t and return pointer to per-port timer tree.
255 *
256 * @retval pointer to pointer to timer tree when successful
257 * @retval NULL upon an error
258 */
259static
260su_timer_queue_t *su_timer_queue(su_timer_t const *t,
261 int use_sut_duration,
262 char const *caller)
263{
264 su_timer_queue_t *timers;
265
266 if (t == NULL((void*)0)) {
267 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__, 268, "%s(%p): %s\n"
, caller, (void *)t, "NULL argument")) : (void)0)
268 "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__, 268, "%s(%p): %s\n"
, caller, (void *)t, "NULL argument")) : (void)0)
;
269 return NULL((void*)0);
270 }
271
272 if (use_sut_duration && t->sut_duration == 0) {
273 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", 273, __extension__ __PRETTY_FUNCTION__); }))
;
274 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__, 275, "%s(%p): %s\n"
, caller, (void *)t, "timer without default duration")) : (void
)0)
275 "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__, 275, "%s(%p): %s\n"
, caller, (void *)t, "timer without default duration")) : (void
)0)
;
276 return NULL((void*)0);
277 }
278
279 if (t->sut_deferrable)
280 timers = su_task_deferrable(t->sut_task);
281 else
282 timers = su_task_timers(t->sut_task);
283
284 if (timers == NULL((void*)0)) {
285 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__, 285, "%s(%p): %s\n"
, caller, (void *)t, "invalid timer")) : (void)0)
;
286 return NULL((void*)0);
287 }
288 else if (timers_is_full(timers[0]) && timers_resize(NULL((void*)0), timers, 0) == -1) {
289 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__, 289, "%s(%p): %s\n"
, caller, (void *)t, "timer queue failed")) : (void)0)
;
290 return NULL((void*)0);
291 }
292
293 return timers;
294}
295
296
297/**Create a timer.
298 *
299 * Allocate and initialize an instance of su_timer_t.
300 *
301 * @param task a task for root object with which the timer will be associated
302 * @param msec the default duration of the timer in milliseconds
303 *
304 * @return A pointer to allocated timer instance, NULL on error.
305 */
306su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec)
307{
308 su_timer_t *retval;
309
310 assert(msec >= 0)((void) sizeof ((msec >= 0) ? 1 : 0), __extension__ ({ if (
msec >= 0) ; else __assert_fail ("msec >= 0", "su_timer.c"
, 310, __extension__ __PRETTY_FUNCTION__); }))
;
311
312 if (!su_task_cmp(task, su_task_null))
313 return NULL((void*)0);
314
315 retval = su_zalloc(NULL((void*)0), sizeof(*retval));
316 if (retval) {
317 su_task_copy(retval->sut_task, task);
318 retval->sut_duration = msec;
319 }
320
321 return retval;
322}
323
324
325/** Destroy a timer.
326 *
327 * Deinitialize and free an instance of su_timer_t.
328 *
329 * @param t pointer to the timer object
330 */
331void su_timer_destroy(su_timer_t *t)
332{
333 if (t) {
334 su_timer_reset(t);
335 su_task_deinit(t->sut_task);
336 su_free(NULL((void*)0), t);
337 }
338}
339
340/** Check if the timer has been set.
341 *
342 * @param t pointer to a timer object
343 *
344 * @return Nonzero if set, zero if reset.
345 *
346 * @NEW_1_12_11
347 */
348int su_timer_is_set(su_timer_t const *t)
349{
350 return t && t->sut_set != 0;
351}
352
353/**Return when the timer has been last expired.
354 *
355 * @param t pointer to a timer object
356 *
357 * @return Timestamp (as returned by su_time()).
358 *
359 * @note If the timer is running (set with su_timer_run()), the returned
360 * timestamp not the actual time but it is rather calculated from the
361 * initial timestamp.
362 *
363 * @NEW_1_12_11
364 */
365su_time_t su_timer_latest(su_timer_t const *t)
366{
367 su_time_t tv = { 0, 0 };
368
369 return t ? t->sut_when : tv;
370}
371
372/** Set the timer for the given @a interval.
373 *
374 * Sets (starts) the given timer to expire after the specified duration.
375 *
376 * @param t pointer to the timer object
377 * @param wakeup pointer to the wakeup function
378 * @param arg argument given to the wakeup function
379 * @param interval duration in milliseconds before timer wakeup is called
380 *
381 * @return 0 if successful, -1 otherwise.
382 */
383int su_timer_set_interval(su_timer_t *t,
384 su_timer_f wakeup,
385 su_timer_arg_t *arg,
386 su_duration_t interval)
387{
388 su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_interval");
389
390 return su_timer_set0(timers, t, wakeup, arg, su_now(), interval);
391}
392
393/** Set the timer for the default interval.
394 *
395 * Sets (starts) the given timer to expire after the default duration.
396 *
397 * The timer must have an default duration.
398 *
399 * @param t pointer to the timer object
400 * @param wakeup pointer to the wakeup function
401 * @param arg argument given to the wakeup function
402 *
403 * @return 0 if successful, -1 otherwise.
404 */
405int su_timer_set(su_timer_t *t,
406 su_timer_f wakeup,
407 su_timer_arg_t *arg)
408{
409 su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set");
410
411 return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration);
412}
413
414/** Set timer at known time.
415 *
416 * Sets the timer to expire at given time.
417 *
418 * @param t pointer to the timer object
419 * @param wakeup pointer to the wakeup function
420 * @param arg argument given to the wakeup function
421 * @param when time structure defining the wakeup time
422 *
423 * @return 0 if successful, -1 otherwise.
424 */
425int su_timer_set_at(su_timer_t *t,
426 su_timer_f wakeup,
427 su_wakeup_arg_t *arg,
428 su_time_t when)
429{
430 su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_set_at");
431
432 return su_timer_set0(timers, t, wakeup, arg, when, 0);
433}
434
435/** Set the timer for regular intervals.
436 *
437 * Run the given timer continuously, call wakeup function repeately in the
438 * default interval. If a wakeup call is missed, try to make it up (in other
439 * words, this kind of timer fails miserably if time is adjusted and it
440 * should really use /proc/uptime instead of gettimeofday()).
441 *
442 * While a continously running timer is active it @b must @b not @b be @b
443 * set using su_timer_set() or su_timer_set_at().
444 *
445 * The timer must have an non-zero default interval.
446 *
447 * @param t pointer to the timer object
448 * @param wakeup pointer to the wakeup function
449 * @param arg argument given to the wakeup function
450 *
451 * @return 0 if successful, -1 otherwise.
452 */
453int su_timer_run(su_timer_t *t,
454 su_timer_f wakeup,
455 su_timer_arg_t *arg)
456{
457 su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_run");
458
459 if (timers == NULL((void*)0))
460 return -1;
461
462 t->sut_running = run_at_intervals;
463 t->sut_woken = 0;
464
465 return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration);
466}
467
468/**Set the timer for regular intervals.
469 *
470 * Run the given timer continuously, call wakeup function repeately in the
471 * default interval. While a continously running timer is active it @b must
472 * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike
473 * su_timer_run(), set for ever timer does not try to catchup missed
474 * callbacks.
475 *
476 * The timer must have an non-zero default interval.
477 *
478 * @param t pointer to the timer object
479 * @param wakeup pointer to the wakeup function
480 * @param arg argument given to the wakeup function
481 *
482 * @return 0 if successful, -1 otherwise.
483 */
484int su_timer_set_for_ever(su_timer_t *t,
485 su_timer_f wakeup,
486 su_timer_arg_t *arg)
487{
488 su_timer_queue_t *timers = su_timer_queue(t, 1, "su_timer_set_for_ever");
489
490 if (timers == NULL((void*)0))
491 return -1;
492
493 t->sut_running = run_for_ever;
494 t->sut_woken = 0;
495
496 return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration);
497}
498
499/**Reset the timer.
500 *
501 * Resets (stops) the given timer.
502 *
503 * @param t pointer to the timer object
504 *
505 * @return 0 if successful, -1 otherwise.
506 */
507int su_timer_reset(su_timer_t *t)
508{
509 su_timer_queue_t *timers = su_timer_queue(t, 0, "su_timer_reset");
510
511 if (timers == NULL((void*)0))
512 return -1;
513
514 if (SU_TIMER_IS_SET(t)((t)->sut_set != 0))
515 timers_remove(timers[0], t->sut_set);
516
517 t->sut_wakeup = NULL((void*)0);
518 t->sut_arg = NULL((void*)0);
519 t->sut_running = reset;
520
521 return 0;
522}
523
524/** @internal Check for expired timers in queue.
525 *
526 * The function su_timer_expire() checks a timer queue and executes and
527 * removes expired timers from the queue. It also calculates the time when
528 * the next timer expires.
529 *
530 * @param timers pointer to the timer queue
531 * @param timeout timeout in milliseconds [IN/OUT]
532 * @param now current timestamp
533 *
534 * @return
535 * The number of expired timers.
536 */
537int su_timer_expire(su_timer_queue_t * const timers,
538 su_duration_t *timeout,
539 su_time_t now)
540{
541 su_timer_t *t;
542 su_timer_f f;
543 int n = 0;
544
545 if (timers_used(timers[0]) == 0)
1
Assuming the condition is false
2
Taking false branch
546 return 0;
547
548 while ((t = timers_get(timers[0], 1))) {
3
Loop condition is true. Entering loop body
23
Loop condition is true. Entering loop body
549 if (SU_TIME_CMP(t->sut_when, now)su_time_cmp(t->sut_when, now) > 0) {
4
Taking false branch
24
Taking false branch
550 su_duration_t at = su_duration(t->sut_when, now);
551
552 if (at < *timeout || *timeout < 0)
553 *timeout = at;
554
555 break;
556 }
557
558 timers_remove(timers[0], 1);
559
560 f = t->sut_wakeup; t->sut_wakeup = NULL((void*)0);
561 assert(f)((void) sizeof ((f) ? 1 : 0), __extension__ ({ if (f) ; else __assert_fail
("f", "su_timer.c", 561, __extension__ __PRETTY_FUNCTION__);
}))
;
562
563 if (t->sut_running == run_at_intervals) {
5
Assuming the condition is false
6
Taking false branch
25
Assuming the condition is true
26
Taking true branch
564 while (t->sut_running == run_at_intervals &&
29
Loop condition is true. Entering loop body
565 t->sut_set == 0 &&
27
Assuming the condition is true
566 t->sut_duration > 0) {
28
Assuming the condition is true
567 if (su_time_diff(t->sut_when, now) > 0) {
30
Taking true branch
568 su_timer_set0(timers, t, f, t->sut_arg, t->sut_when, 0);
31
Calling 'su_timer_set0'
569 break;
570 }
571 t->sut_when = su_time_add(t->sut_when, t->sut_duration);
572 t->sut_woken++;
573 f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
574 }
575 }
576 else if (t->sut_running == run_for_ever) {
7
Assuming the condition is true
8
Taking true branch
577 t->sut_woken++;
578 t->sut_when = now;
579 f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
580 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
581 su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration);
12
Calling 'su_timer_set0'
22
Returned allocated memory
582 }
583 else {
584 t->sut_when = now;
585 f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++;
586 }
587 }
588
589 return n;
590}
591
592
593/** Calculate duration in milliseconds until next timer expires. */
594su_duration_t su_timer_next_expires(su_timer_queue_t const *timers,
595 su_time_t now)
596{
597 su_duration_t next = SU_DURATION_MAXSU_DURATION_MAX;
598
599 su_timer_t const *t;
600
601 t = timers ? timers_get(timers[0], 1) : NULL((void*)0);
602
603 if (t) {
604 next = su_duration(t->sut_when, now);
605 if (next < 0)
606 next = 0;
607 }
608
609 return next;
610}
611
612/**
613 * Resets and frees all timers belonging to a task.
614 *
615 * The function su_timer_destroy_all() resets and frees all timers belonging
616 * to the specified task in the queue.
617 *
618 * @param timers pointer to the timers
619 * @param task task owning the timers
620 *
621 * @return Number of timers reset.
622 */
623int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task)
624{
625 size_t i;
626 int n = 0;
627
628 if (!timers)
629 return 0;
630
631 timers_sort(timers[0]);
632
633 for (i = timers_used(timers[0]); i > 0; i--) {
634 su_timer_t *t = timers_get(timers[0], i);
635
636 if (su_task_cmp(task, t->sut_task))
637 continue;
638
639 timers_remove(timers[0], i);
640
641 su_free(NULL((void*)0), t);
642 n++;
643 }
644
645 if (!timers_used(timers[0]))
646 free(timers->private), timers->private = NULL((void*)0);
647
648 return n;
649}
650
651/** Get the root object owning the timer.
652 *
653 * Return pointer to the root object owning the timer.
654 *
655 * @param t pointer to the timer
656 *
657 * @return Pointer to the root object.
658 */
659su_root_t *su_timer_root(su_timer_t const *t)
660{
661 return t ? su_task_root(t->sut_task) : NULL((void*)0);
662}
663
664
665/** Change timer as deferrable (or as undeferrable).
666 *
667 * A deferrable timer is executed after the given timeout, however, the task
668 * tries to avoid being woken up only because the timeout. Deferable timers
669 * have their own queue and timers there are ignored when calculating the
670 * timeout for epoll()/select()/whatever unless the timeout would exceed the
671 * maximum defer time. The maximum defer time is 15 seconds by default, but
672 * it can be modified by su_root_set_max_defer().
673 *
674 * @param t pointer to the timer
675 * @param value make timer deferrable if true, undeferrable if false
676 *
677 * @return 0 if succesful, -1 upon an error
678 *
679 * @sa su_root_set_max_defer()
680 *
681 * @NEW_1_12_7
682 */
683int su_timer_deferrable(su_timer_t *t, int value)
684{
685 if (t == NULL((void*)0) || su_task_deferrable(t->sut_task) == NULL((void*)0))
686 return errno(*__errno_location ()) = EINVAL22, -1;
687
688 t->sut_deferrable = value != 0;
689
690 return 0;
691}