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

📄 su_timer.c

📁 this is simple sip stack.
💻 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 "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) */};enum sut_running {  reset = 0,  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(static inline, timers, su_timer_t);static inline int timers_append(su_timer_t **, su_timer_t *);static inline void timers_remove(su_timer_t **, su_timer_t *);static inline su_timer_t *timers_succ(su_timer_t const *);static inline su_timer_t *timers_prec(su_timer_t const *);static inline su_timer_t *timers_first(su_timer_t const *);static inline su_timer_t *timers_last(su_timer_t const *);RBTREE_BODIES(static inline, timers, su_timer_t,	      LEFT, RIGHT, PARENT,	      IS_RED, SET_RED, IS_BLACK, SET_BLACK, COPY_COLOR,	      CMP, INSERT, REMOVE);/** Set the timer. */static inline intsu_timer_set0(su_timer_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);}/** Reset the timer. */static inline intsu_timer_reset0(su_timer_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;}/**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))    retval = su_zalloc(NULL, sizeof(*retval));  else    retval = NULL;  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. * * @param t pointer to the timer object */void su_timer_destroy(su_timer_t *t){  if (t) {    su_timer_t **timers = su_task_timers(t->sut_task);    if (timers)      su_timer_reset0(timers, t);    su_task_deinit(t->sut_task);    su_free(NULL, t);  }}/** Set the timer for the given @a interval. * *  Sets (starts) the given timer to expire after the specified duration. * * @param t       pointer to the timer object * @param wakeup  pointer to the wakeup function * @param arg     argument given to the wakeup function * @param interval duration in milliseconds before timer wakeup is called * * @return 0 if successful, -1 otherwise. */int su_timer_set_interval(su_timer_t *t,			  su_timer_f wakeup,			  su_timer_arg_t *arg,			  su_duration_t interval){  char const *func = "su_timer_set_interval";  su_timer_t **timers;  if (t == NULL) {    SU_DEBUG_1(("%s(%p): %s\n", func, t, "NULL argument"));    return -1;  }  timers = su_task_timers(t->sut_task);  if (timers == NULL) {    SU_DEBUG_1(("%s(%p): %s\n", func, t, "invalid timer"));    return -1;  }  su_timer_set0(timers, t, wakeup, arg, su_now(), interval);  return 0;}/** 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. *

⌨️ 快捷键说明

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