⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 su_timer.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * 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. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * Created: Fri Apr 28 15:45:41 2000 ppessi */#include "config.h"#include "su_port.h"#include "sofia-sip/su.h"#include "sofia-sip/su_wait.h"#include "sofia-sip/su_alloc.h"#include "sofia-sip/rbtree.h"#include "su_module_debug.h"#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <string.h>/**@ingroup su_wait * * @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 *  arrived or the default interval has elapsed, the timer expires and *  it is ready for execution. * *  The functions used to create, destroy, activate, and manage timers are *  as follows: *   - su_timer_create(), *   - su_timer_destroy(), *   - su_timer_set_interval(), *   - su_timer_set_at(), *   - su_timer_set(), *   - su_timer_set_for_ever(),  *   - su_timer_run(), *   - su_timer_reset(), and *   - su_timer_root(). * * @note * 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 * such case, the timer is activated using function su_timer_set_for_ever().  * When the timer is activated it is given the wakeup function and pointer to * context data: * @code *   su_timer_set_for_ever(timer, timer_wakeup, args); * @endcode * * When the interval has passed, the root event loop calls the wakeup * function: * @code *   timer_wakeup(root, timer, args); * @endcode * * 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. * * Timer ceases running when su_timer_reset() is called. * * Alternatively, the timer can be @b set for one-time event invocation. * 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 {  /** Pointers within red-black tree */  su_timer_t     *sut_left, *sut_right, *sut_parent;  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 */  su_time_t       sut_run;	/**< When this timer was last waken up */  unsigned        sut_woken;	/**< Timer has waken up this many times */  unsigned short  sut_running;	/**< Timer is running */  unsigned char   sut_black;	/**< Black node */  unsigned char   sut_set;	/**< Timer is set (inserted in tree) */};/** Timer running status */ enum sut_running {  reset = 0,		/**< Timer is not running */  run_at_intervals = 1, /**< Compensate missed wakeup calls */  run_for_ever = 2	/**< Do not compensate  */};#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)RBTREE_PROTOS(su_inline, timers, su_timer_t);su_inline int timers_append(su_timer_queue_t *, su_timer_t *);su_inline void timers_remove(su_timer_queue_t *, su_timer_t *);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 *);RBTREE_BODIES(su_inline, timers, su_timer_t,	      LEFT, RIGHT, PARENT,	      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	      CMP, INSERT, REMOVE);/**@internal Set the timer.  * * @retval 0 when successful (always) */su_inline intsu_timer_set0(su_timer_queue_t *timers,	      su_timer_t *t,	      su_timer_f wakeup,	      su_wakeup_arg_t *arg,	      su_time_t when,	      su_duration_t offset){  if (SU_TIMER_IS_SET(t))    timers_remove(timers, t);  t->sut_wakeup = wakeup;  t->sut_arg = arg;  t->sut_when = su_time_add(when, offset);  return timers_append(timers, t);}/**@internal Reset the timer.  * * @retval 0 when successful (always) */su_inline intsu_timer_reset0(su_timer_queue_t *timers,		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;}/**@internal Validate timer @a t and return pointer to per-port timer tree. *  * @retval pointer to pointer to timer tree when successful * @retval NULL upon an error */staticsu_timer_queue_t *su_timer_tree(su_timer_t const *t,				int use_sut_duration,				char const *caller){  su_timer_queue_t *timers;  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);    SU_DEBUG_1(("%s(%p): %s\n", caller, (void *)t, 		"timer without default duration"));    return NULL;  }  return timers;}/**Create a timer. * * Allocate and initialize an instance of su_timer_t. * * @param task a task for root object with which the timer will be associated * @param msec the default duration of the timer * * @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);  if (!su_task_cmp(task, su_task_null))    return NULL;  retval = su_zalloc(NULL, sizeof(*retval));  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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -