su_timer.c 16.6 KB
Newer Older
Pekka Pessi's avatar
Pekka Pessi committed
1 2 3 4 5 6 7
/*
 * This file is part of the Sofia-SIP package
 *
 * Copyright (C) 2005 Nokia Corporation.
 *
 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
 *
8
 * This library is free software; you can redistribute it and/or
Pekka Pessi's avatar
Pekka Pessi committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

/**@CFILE su_timer.c
 *
 * Timer interface for su_root.
28
 *
Pekka Pessi's avatar
Pekka Pessi committed
29 30 31 32 33 34
 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
 * Created: Fri Apr 28 15:45:41 2000 ppessi
 */

#include "config.h"

35
#include "su_port.h"
36 37 38 39 40
#include "sofia-sip/su.h"
#include "sofia-sip/su_wait.h"
#include "sofia-sip/su_alloc.h"
#include "sofia-sip/rbtree.h"

Pekka Pessi's avatar
Pekka Pessi committed
41
#include "su_module_debug.h"
42 43 44 45 46

#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
Pekka Pessi's avatar
Pekka Pessi committed
47 48

/**@ingroup su_wait
49
 *
Pekka Pessi's avatar
Pekka Pessi committed
50 51 52 53 54 55
 * @page su_timer_t Timer Objects
 *
 *  Timers are used to schedule some task to be executed at given time or
 *  after a default interval. The default interval is specified when the
 *  timer is created. We call timer activation "setting the timer", and
 *  deactivation "resetting the timer" (as in SDL). When the given time has
56
 *  arrived or the default interval has elapsed, the timer expires and
Pekka Pessi's avatar
Pekka Pessi committed
57 58 59 60 61 62
 *  it is ready for execution.
 *
 *  The functions used to create, destroy, activate, and manage timers are
 *  as follows:
 *   - su_timer_create(),
 *   - su_timer_destroy(),
63 64
 *   - su_timer_set_interval(),
 *   - su_timer_set_at(),
Pekka Pessi's avatar
Pekka Pessi committed
65
 *   - su_timer_set(),
66
 *   - su_timer_set_for_ever(),
Pekka Pessi's avatar
Pekka Pessi committed
67 68 69 70
 *   - su_timer_run(),
 *   - su_timer_reset(), and
 *   - su_timer_root().
 *
71
 * @note
Pekka Pessi's avatar
Pekka Pessi committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
 * Timers use poll() to wake up waiting thread. On Linux, the timer
 * granularity is determined by HZ kernel parameter, which decided when the
 * kernel was compiled. With kernel 2.4 the default granularity is 10
 * milliseconds, and minimum duration of a timer is approximately 20
 * milliseconds. Naturally, using RTC would give better timing results, but
 * RTC usage above 64 Hz is privileged operation.
 *
 * @par
 * On Windows, the granularity is determined by the real-time clock timer.
 * By default, it uses the 18.78 Hz granularity.  That timer can be adjusted
 * up to 1000 Hz using Windows multimedia library.
 *
 * @section su_timer_usage Using Timers
 *
 * A timer is created by calling su_timer_create():
 * @code
 *   timer = su_timer_create(su_root_task(root), 200);
 * @endcode
 * The default duration is given in milliseconds.
 *
 * Usually, timer wakeup function should be called at regular intervals. In
93
 * such case, the timer is activated using function su_timer_set_for_ever().
94 95
 * When the timer is activated it is given the wakeup function and pointer to
 * context data:
Pekka Pessi's avatar
Pekka Pessi committed
96
 * @code
97
 *   su_timer_set_for_ever(timer, timer_wakeup, args);
Pekka Pessi's avatar
Pekka Pessi committed
98 99
 * @endcode
 *
100 101
 * When the interval has passed, the root event loop calls the wakeup
 * function:
Pekka Pessi's avatar
Pekka Pessi committed
102 103 104 105
 * @code
 *   timer_wakeup(root, timer, args);
 * @endcode
 *
106 107 108 109 110 111 112 113
 * If the number of calls to callback function is important, use
 * su_timer_run() instead. The run timer tries to compensate for missed time
 * and invokes the callback function several times if needed. (Because the
 * real-time clock can be adjusted or the program suspended, e.g., while
 * debugged, the callback function can be called thousends of times in a
 * row.) Note that while the timer tries to compensate for delays occurred
 * before and during the callback, it cannot be used as an exact source of
 * timing information.
114
 *
115
 * Timer ceases running when su_timer_reset() is called.
Pekka Pessi's avatar
Pekka Pessi committed
116
 *
117
 * Alternatively, the timer can be @b set for one-time event invocation.
Pekka Pessi's avatar
Pekka Pessi committed
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
 * When the timer is set, it is given the wakeup function and pointer to
 * context data. The actual duration can also be specified using
 * su_timer_set_at(). @code su_timer_set(timer, timer_wakeup, args);
 * @endcode
 *
 * When the timer expires, the root event loop calls the wakeup function:
 * @code
 *   timer_wakeup(root, timer, args);
 * @endcode
 *
 * If the timed event is not needed anymore, the timer can be reset:
 * @code
 *   su_timer_reset(timer);
 * @endcode
 *
 * If the timer is expected to be called at regular intervals, it is
 * possible to set ro run continously with su_timer_run().  While such a
 * continously running timer is active it @b must @b not @b be @b set using
 * su_timer_set() or su_timer_set_at().
 *
 * When the timer is not needed anymore, the timer object itself should be
 * destroyed:
 * @code
 *   su_timer_destroy(timer);
 * @endcode
 */

struct su_timer_s {
146
  /** Pointers within red-black tree */
147
  su_timer_t     *sut_left, *sut_right, *sut_parent;
Pekka Pessi's avatar
Pekka Pessi committed
148 149 150 151 152
  su_task_r       sut_task;	/**< Task reference */
  su_time_t       sut_when;	/**< When timer should be waken up next time */
  su_duration_t   sut_duration;	/**< Timer duration */
  su_timer_f      sut_wakeup;	/**< Function to call when waken up */
  su_timer_arg_t *sut_arg;	/**< Pointer to argument data */
153
  su_time_t       sut_run;	/**< When this timer was last waken up */
Pekka Pessi's avatar
Pekka Pessi committed
154
  unsigned        sut_woken;	/**< Timer has waken up this many times */
155 156 157 158
  unsigned short  sut_running;	/**< Timer is running */

  unsigned char   sut_black;	/**< Black node */
  unsigned char   sut_set;	/**< Timer is set (inserted in tree) */
Pekka Pessi's avatar
Pekka Pessi committed
159 160
};

161
/** Timer running status */
162
enum sut_running {
Pekka Pessi's avatar
Pekka Pessi committed
163
  reset = 0,		/**< Timer is not running */
164 165
  run_at_intervals = 1, /**< Compensate missed wakeup calls */
  run_for_ever = 2	/**< Do not compensate  */
Pekka Pessi's avatar
Pekka Pessi committed
166 167
};

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
#define SU_TIMER_IS_SET(sut) ((sut)->sut_set)

/* Accessor macros for rbtree */
#define LEFT(sut) ((sut)->sut_left)
#define RIGHT(sut) ((sut)->sut_right)
#define PARENT(sut) ((sut)->sut_parent)
#define SET_RED(sut) ((sut)->sut_black = 0)
#define SET_BLACK(sut) ((sut)->sut_black = 1)
#define CMP(a, b) SU_TIME_CMP((a)->sut_when, (b)->sut_when)
#define IS_RED(sut) ((sut) && (sut)->sut_black == 0)
#define IS_BLACK(sut) (!(sut) || (sut)->sut_black == 1)
#define COPY_COLOR(dst, src) ((dst)->sut_black = (src)->sut_black)
#define INSERT(sut) ((sut)->sut_set = 1)
#define REMOVE(sut) ((sut)->sut_set = 0,				\
  (sut)->sut_left = (sut)->sut_right = (sut)->sut_parent = NULL)

184
RBTREE_PROTOS(su_inline, timers, su_timer_t);
185

186 187
su_inline int timers_append(su_timer_queue_t *, su_timer_t *);
su_inline void timers_remove(su_timer_queue_t *, su_timer_t *);
188 189 190 191
su_inline su_timer_t *timers_succ(su_timer_t const *);
su_inline su_timer_t *timers_prec(su_timer_t const *);
su_inline su_timer_t *timers_first(su_timer_t const *);
su_inline su_timer_t *timers_last(su_timer_t const *);
192

193
RBTREE_BODIES(su_inline, timers, su_timer_t,
194 195 196 197
	      LEFT, RIGHT, PARENT,
	      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,
	      CMP, INSERT, REMOVE);

198
/**@internal Set the timer.
199 200 201
 *
 * @retval 0 when successful (always)
 */
202
su_inline int
203
su_timer_set0(su_timer_queue_t *timers,
204 205 206
	      su_timer_t *t,
	      su_timer_f wakeup,
	      su_wakeup_arg_t *arg,
207 208
	      su_time_t when,
	      su_duration_t offset)
209 210 211 212 213 214
{
  if (SU_TIMER_IS_SET(t))
    timers_remove(timers, t);

  t->sut_wakeup = wakeup;
  t->sut_arg = arg;
215
  t->sut_when = su_time_add(when, offset);
216 217 218 219

  return timers_append(timers, t);
}

220
/**@internal Reset the timer.
221 222 223
 *
 * @retval 0 when successful (always)
 */
224
su_inline int
225
su_timer_reset0(su_timer_queue_t *timers,
226 227 228 229 230 231 232 233 234 235 236 237 238 239
		su_timer_t *t)
{
  if (SU_TIMER_IS_SET(t))
    timers_remove(timers, t);

  t->sut_wakeup = NULL;
  t->sut_arg = NULL;
  t->sut_running = reset;

  memset(&t->sut_run, 0, sizeof(t->sut_run));

  return 0;
}

240
/**@internal Validate timer @a t and return pointer to per-port timer tree.
241
 *
242 243 244 245
 * @retval pointer to pointer to timer tree when successful
 * @retval NULL upon an error
 */
static
246 247 248
su_timer_queue_t *su_timer_tree(su_timer_t const *t,
				int use_sut_duration,
				char const *caller)
249
{
250
  su_timer_queue_t *timers;
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

  if (t == NULL) {
    SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
		"NULL argument"));
    return NULL;
  }

  timers = su_task_timers(t->sut_task);

  if (timers == NULL)
    SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
		"invalid timer"));

  if (use_sut_duration && t->sut_duration == 0) {
    assert(t->sut_duration > 0);
266
    SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t,
267 268 269 270 271 272 273
		"timer without default duration"));
    return NULL;
  }

  return timers;
}

274

Pekka Pessi's avatar
Pekka Pessi committed
275 276 277
/**Create a timer.
 *
 * Allocate and initialize an instance of su_timer_t.
278
 *
Pekka Pessi's avatar
Pekka Pessi committed
279 280
 * @param task a task for root object with which the timer will be associated
 * @param msec the default duration of the timer
281
 *
Pekka Pessi's avatar
Pekka Pessi committed
282 283 284 285 286 287 288 289
 * @return A pointer to allocated timer instance, NULL on error.
 */
su_timer_t *su_timer_create(su_task_r const task, su_duration_t msec)
{
  su_timer_t *retval;

  assert(msec >= 0);

290 291
  if (!su_task_cmp(task, su_task_null))
    return NULL;
Pekka Pessi's avatar
Pekka Pessi committed
292

293
  retval = su_zalloc(NULL, sizeof(*retval));
Pekka Pessi's avatar
Pekka Pessi committed
294 295 296 297 298 299 300 301 302 303 304
  if (retval) {
    su_task_copy(retval->sut_task, task);
    retval->sut_duration = msec;
  }

  return retval;
}

/** Destroy a timer.
 *
 * Deinitialize and free an instance of su_timer_t.
305
 *
Pekka Pessi's avatar
Pekka Pessi committed
306 307 308 309 310
 * @param t pointer to the timer object
 */
void su_timer_destroy(su_timer_t *t)
{
  if (t) {
311
    su_timer_queue_t *timers = su_task_timers(t->sut_task);
312 313
    if (timers)
      su_timer_reset0(timers, t);
Pekka Pessi's avatar
Pekka Pessi committed
314 315 316 317 318
    su_task_deinit(t->sut_task);
    su_free(NULL, t);
  }
}

319
/** Set the timer for the given @a interval.
Pekka Pessi's avatar
Pekka Pessi committed
320
 *
321
 *  Sets (starts) the given timer to expire after the specified duration.
322
 *
Pekka Pessi's avatar
Pekka Pessi committed
323 324 325
 * @param t       pointer to the timer object
 * @param wakeup  pointer to the wakeup function
 * @param arg     argument given to the wakeup function
326
 * @param interval duration in milliseconds before timer wakeup is called
327
 *
Pekka Pessi's avatar
Pekka Pessi committed
328 329
 * @return 0 if successful, -1 otherwise.
 */
330 331 332 333
int su_timer_set_interval(su_timer_t *t,
			  su_timer_f wakeup,
			  su_timer_arg_t *arg,
			  su_duration_t interval)
Pekka Pessi's avatar
Pekka Pessi committed
334
{
335
  su_timer_queue_t *timers = su_timer_tree(t, 0, "su_timer_set_interval");
336

337
  if (t == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
338 339
    return -1;

340
  return su_timer_set0(timers, t, wakeup, arg, su_now(), interval);
Pekka Pessi's avatar
Pekka Pessi committed
341 342
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
/** Set the timer for the default interval.
 *
 *  Sets (starts) the given timer to expire after the default duration.
 *
 *  The timer must have an default duration.
 *
 * @param t       pointer to the timer object
 * @param wakeup  pointer to the wakeup function
 * @param arg     argument given to the wakeup function
 *
 * @return 0 if successful, -1 otherwise.
 */
int su_timer_set(su_timer_t *t,
		 su_timer_f wakeup,
		 su_timer_arg_t *arg)
{
359
  su_timer_queue_t *timers = su_timer_tree(t, 1, "su_timer_set");
360

361
  if (timers == NULL)
362 363
    return -1;

364
  return su_timer_set0(timers, t, wakeup, arg, su_now(), t->sut_duration);
365 366
}

Pekka Pessi's avatar
Pekka Pessi committed
367 368
/** Set timer at known time.
 *
369 370
 *  Sets the timer to expire at given time.
 *
Pekka Pessi's avatar
Pekka Pessi committed
371 372 373 374
 * @param t       pointer to the timer object
 * @param wakeup  pointer to the wakeup function
 * @param arg     argument given to the wakeup function
 * @param when    time structure defining the wakeup time
375
 *
Pekka Pessi's avatar
Pekka Pessi committed
376 377
 * @return 0 if successful, -1 otherwise.
 */
378 379
int su_timer_set_at(su_timer_t *t,
		    su_timer_f wakeup,
Pekka Pessi's avatar
Pekka Pessi committed
380 381 382
		    su_wakeup_arg_t *arg,
		    su_time_t when)
{
383
  su_timer_queue_t *timers = su_timer_tree(t, 0, "su_timer_set_at");
Pekka Pessi's avatar
Pekka Pessi committed
384

385
  if (timers == NULL)
386
    return -1;
Pekka Pessi's avatar
Pekka Pessi committed
387

388
  return su_timer_set0(timers, t, wakeup, arg, when, 0);
Pekka Pessi's avatar
Pekka Pessi committed
389 390 391 392 393 394 395
}

/** Set the timer for regular intervals.
 *
 * Run the given timer continuously, call wakeup function repeately in the
 * default interval. If a wakeup call is missed, try to make it up (in other
 * words, this kind of timer fails miserably if time is adjusted and it
396
 * should really use /proc/uptime instead of gettimeofday()).
Pekka Pessi's avatar
Pekka Pessi committed
397 398 399 400 401
 *
 * While a continously running timer is active it @b must @b not @b be @b
 * set using su_timer_set() or su_timer_set_at().
 *
 * The timer must have an non-zero default interval.
402
 *
Pekka Pessi's avatar
Pekka Pessi committed
403 404 405
 * @param t       pointer to the timer object
 * @param wakeup  pointer to the wakeup function
 * @param arg     argument given to the wakeup function
406
 *
Pekka Pessi's avatar
Pekka Pessi committed
407 408
 * @return 0 if successful, -1 otherwise.
 */
409 410
int su_timer_run(su_timer_t *t,
		 su_timer_f wakeup,
Pekka Pessi's avatar
Pekka Pessi committed
411 412
		 su_timer_arg_t *arg)
{
413
  su_timer_queue_t *timers = su_timer_tree(t, 1, "su_timer_run");
414
  su_time_t now;
Pekka Pessi's avatar
Pekka Pessi committed
415

416
  if (timers == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
417 418 419
    return -1;

  t->sut_running = run_at_intervals;
420
  t->sut_run = now = su_now();
Pekka Pessi's avatar
Pekka Pessi committed
421 422
  t->sut_woken = 0;

423
  return su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
Pekka Pessi's avatar
Pekka Pessi committed
424 425 426 427 428 429 430
}

/**Set the timer for regular intervals.
 *
 * Run the given timer continuously, call wakeup function repeately in the
 * default interval. While a continously running timer is active it @b must
 * @b not @b be @b set using su_timer_set() or su_timer_set_at(). Unlike
431 432
 * su_timer_run(), set for ever timer does not try to catchup missed
 * callbacks.
Pekka Pessi's avatar
Pekka Pessi committed
433 434
 *
 * The timer must have an non-zero default interval.
435
 *
Pekka Pessi's avatar
Pekka Pessi committed
436 437 438
 * @param t       pointer to the timer object
 * @param wakeup  pointer to the wakeup function
 * @param arg     argument given to the wakeup function
439
 *
Pekka Pessi's avatar
Pekka Pessi committed
440 441
 * @return 0 if successful, -1 otherwise.
 */
442 443
int su_timer_set_for_ever(su_timer_t *t,
			  su_timer_f wakeup,
Pekka Pessi's avatar
Pekka Pessi committed
444 445
			  su_timer_arg_t *arg)
{
446
  su_timer_queue_t *timers = su_timer_tree(t, 1, "su_timer_set_for_ever");
447
  su_time_t now;
Pekka Pessi's avatar
Pekka Pessi committed
448

449
  if (timers == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
450 451 452
    return -1;

  t->sut_running = run_for_ever;
453
  t->sut_run = now = su_now();
454
  t->sut_woken = 0;
Pekka Pessi's avatar
Pekka Pessi committed
455

456
  return su_timer_set0(timers, t, wakeup, arg, now, t->sut_duration);
Pekka Pessi's avatar
Pekka Pessi committed
457 458 459 460 461 462 463
}

/**Reset the timer.
 *
 * Resets (stops) the given timer.
 *
 * @param t  pointer to the timer object
464
 *
Pekka Pessi's avatar
Pekka Pessi committed
465 466 467 468
 * @return 0 if successful, -1 otherwise.
 */
int su_timer_reset(su_timer_t *t)
{
469
  su_timer_queue_t *timers = su_timer_tree(t, 0, "su_timer_reset");
470

471
  if (timers == NULL)
Pekka Pessi's avatar
Pekka Pessi committed
472 473
    return -1;

474
  return su_timer_reset0(timers, t);
Pekka Pessi's avatar
Pekka Pessi committed
475 476 477
}

/** @internal Check for expired timers in queue.
478
 *
Pekka Pessi's avatar
Pekka Pessi committed
479 480 481 482
 * The function su_timer_expire() checks a timer queue and executes and
 * removes expired timers from the queue. It also calculates the time when
 * the next timer expires.
 *
483
 * @param timers   pointer to the timer queue
484
 * @param timeout  timeout in milliseconds [IN/OUT]
Pekka Pessi's avatar
Pekka Pessi committed
485
 * @param now      current timestamp
486 487
 *
 * @return
Pekka Pessi's avatar
Pekka Pessi committed
488 489
 * The number of expired timers.
 */
490
int su_timer_expire(su_timer_queue_t * const timers,
Pekka Pessi's avatar
Pekka Pessi committed
491 492 493 494 495 496 497
		    su_duration_t *timeout,
		    su_time_t now)
{
  su_timer_t *t;
  su_timer_f f;
  int n = 0;

498
  if (!*timers)
Pekka Pessi's avatar
Pekka Pessi committed
499 500
    return n;

501 502 503 504
  for (;;) {
    t = timers_first(*timers);

    if (t == NULL || SU_TIME_CMP(t->sut_when, now) > 0)
Pekka Pessi's avatar
Pekka Pessi committed
505
      break;
506 507 508

    timers_remove(timers, t);

Pekka Pessi's avatar
Pekka Pessi committed
509 510 511
    f = t->sut_wakeup; t->sut_wakeup = NULL;
    assert(f);

512 513 514 515 516 517
    if (t->sut_running == run_at_intervals) {
      while (t->sut_running == run_at_intervals &&
	     t->sut_duration > 0) {
	if (su_time_diff(t->sut_when, now) > 0) {
	  su_timer_set0(timers, t, f, t->sut_arg, t->sut_run, 0);
	  break;
518
	}
519
	t->sut_when = t->sut_run = su_time_add(t->sut_run, t->sut_duration);
520
	t->sut_woken++;
521
	f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
522
      }
523 524 525 526 527 528
    }
    else if (t->sut_running == run_for_ever) {
      t->sut_woken++;
      t->sut_when = now;
      f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg), n++;
      if (t->sut_running == run_for_ever)
529
	su_timer_set0(timers, t, f, t->sut_arg, now, t->sut_duration);
Pekka Pessi's avatar
Pekka Pessi committed
530 531
    }
    else {
532
      t->sut_when = now;
Pekka Pessi's avatar
Pekka Pessi committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
      f(su_root_magic(su_task_root(t->sut_task)), t, t->sut_arg); n++;
    }
  }

  if (t) {
    su_duration_t at = su_duration(t->sut_when, now);

    if (at < *timeout)
      *timeout = at;
  }

  return n;
}


548
/** Calculate duration in milliseconds until next timer expires. */
Pekka Pessi's avatar
Pekka Pessi committed
549 550 551
su_duration_t su_timer_next_expires(su_timer_t const * t, su_time_t now)
{
  su_duration_t tout;
552

553 554
  t = timers_first(t);

Pekka Pessi's avatar
Pekka Pessi committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568
  if (!t)
    return SU_DURATION_MAX;

  tout = su_duration(t->sut_when, now);

  return tout > 0 ? tout : 0 ;
}

/**
 * Resets and frees all timers belonging to a task.
 *
 * The function su_timer_destroy_all() resets and frees all timers belonging
 * to the specified task in the queue.
 *
569 570
 * @param timers   pointer to the timers
 * @param task     task owning the timers
Pekka Pessi's avatar
Pekka Pessi committed
571
 *
572
 * @return Number of timers reset.
Pekka Pessi's avatar
Pekka Pessi committed
573
 */
574
int su_timer_reset_all(su_timer_queue_t *timers, su_task_r task)
Pekka Pessi's avatar
Pekka Pessi committed
575
{
576
  su_timer_t *t, *t_next;
Pekka Pessi's avatar
Pekka Pessi committed
577 578
  int n = 0;

579 580 581 582 583 584 585 586 587 588 589 590
  if (!timers || !*timers)
    return 0;

  for (t = timers_first(*timers); t; t = t_next) {
    t_next = timers_succ(t);

    if (su_task_cmp(task, t->sut_task))
      continue;

    n++;
    timers_remove(timers, t);
    su_free(NULL, t);
Pekka Pessi's avatar
Pekka Pessi committed
591 592 593 594 595 596 597
  }

  return n;
}

/** Get the root object owning the timer.
 *
598
 * Return pointer to the root object owning the timer.
Pekka Pessi's avatar
Pekka Pessi committed
599 600
 *
 * @param t pointer to the timer
601
 *
602
 * @return Pointer to the root object.
Pekka Pessi's avatar
Pekka Pessi committed
603 604 605
 */
su_root_t *su_timer_root(su_timer_t const *t)
{
606
  return t ? su_task_root(t->sut_task) : NULL;
Pekka Pessi's avatar
Pekka Pessi committed
607
}