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

📄 su_root.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 * *//**@ingroup su_wait * @CFILE su_root.c  * OS-independent synchronization interface.  * @internal * * @author Pekka Pessi <Pekka.Pessi@nokia.com> *  * @date Created: Tue Sep 14 15:51:04 1999 ppessi */#include "config.h"#include <stdlib.h>#include <assert.h>#include <stdio.h>#include <string.h>#include <errno.h>#include "sofia-sip/su.h"#if SU_HAVE_PTHREADS#include <pthread.h>#endifstruct su_root_s;#define SU_ROOT_MAGIC_T struct su_root_magic_s#define SU_WAKEUP_ARG_T struct su_wakeup_arg_s#define SU_TIMER_ARG_T  struct su_timer_arg_s#include "su_port.h"#include "sofia-sip/su_alloc.h"/**@ingroup su_wait *  * @page su_root_t Tasks and root objects * * A task is the basic execution unit for the Sofia event-driven programming * model. According to the model, the program can ask that the event loop * invokes a callback function when a certain event occurs. Such events * include @ref su_root_register "I/O activity", @ref su_timer_t "timers" or * a @ref su_msg_t "message" from other task. The event loop is run with * function su_root_run() or su_root_step(). * * Root object gives access to the task control. The root object represents * the task to the code running within task. Through the root, the task code * can access its context object (magic) and thread-synchronization features * like wait objects, timers, and messages. * * When a message is sent between tasks, a task reference #su_task_r is used * to reprent the task address. Reference counting is used to make sure that * the task references stay valid. * * The public API contains following functions: *    - su_root_create() [Do not call from cloned task] *    - su_root_destroy() [Do not call from cloned task] *    - su_root_magic() *    - su_root_register() *    - su_root_deregister() *    - su_root_unregister() *    - su_root_threading() *    - su_root_run() [Do not call from cloned task] *    - su_root_break() [Do not call from cloned task] *    - su_root_step() [Do not call from cloned task] *    - su_root_task() * * New tasks can be created via su_clone_start() function. *//**@ingroup su_wait  *  * @page su_root_register Registering Wait Objects * * When application expects I/O events, it can create a wait object and * register it, a callback function and a context pointer to the #su_root_t * object using the su_root_register() function. Whenever the wait object * receives an event, the registered @link ::su_wakeup_f callback function * @endlink is invoked. * * When successful, the su_root_register() returns an small non-negative * integer representing the registration. The registration can be * manipulated with su_root_eventmask() function, for instance, when sending * through a socket block, the application can add SU_WAIT_OUT event to the * mask. * * The registration can be removed using su_root_deregister() function. *//**@ingroup su_wait *  * Contains hint of number of sockets supported by su_root_t */ int su_root_size_hint = 64;/* ========================================================================= * Tasks */su_task_r const su_task_null = SU_TASK_R_INIT;#define SU_TASK_ZAP(t, f) \  while (t->sut_port) { \   su_port_decref(t->sut_port, #f); t->sut_port = NULL; break; }#define SU_TASK_ZAPP(t, f) \  do { if (t->sut_port) { \   su_port_decref(t->sut_port, #f); t->sut_port = NULL; } \   t->sut_root = NULL; } while(0)/** * Initialize a task handle with su_task_null. * * @param task task handle * * @return A reference to the initialized task handle. */_su_task_r su_task_init(su_task_r task){  assert(task);  memset(task, 0, sizeof(task));  return task;}/** * Destroy a task handle * * @param task task handle */void su_task_deinit(su_task_r task){  assert(task);  SU_TASK_ZAP(task, su_task_deinit);  task->sut_root = NULL;}/** * Create a new task handle. * * @param task task reference * @param root pointer to root object * @param port pointer to port object * * @return New task handle. */_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port){  assert(task);  task->sut_root = root;  if ((task->sut_port = port)) {    su_port_incref(port, "su_task_new");  }  return task;}/** * Duplicates a task handle. * * @param  dst      destination task reference * @param  src      source task reference */void su_task_copy(su_task_r dst, su_task_r const src){  su_port_t *port;    assert(src); assert(dst);  SU_TASK_ZAP(dst, su_task_copy);  port = src->sut_port;  if (port) {    su_port_incref(port, "su_task_copy");  }  dst[0] = src[0];}#define SU_TASK_COPY(d, s, by) (void)((d)[0]=(s)[0], \  (s)->sut_port?(void)su_port_incref(s->sut_port, #by):(void)0)/** * Moves a task handle. * * @param  dst      destination task reference * @param  src      source task reference */void su_task_move(su_task_r dst, su_task_r src){  SU_TASK_ZAP(dst, su_task_move);  dst[0] = src[0];  src->sut_port = 0;  src->sut_root = 0;}/** * Compare two tasks with each other. *  * @param a  First task * @param b  Second task *  * @retval negative number, if a < b * @retval positive number, if a > b * @retval 0, if a == b. */int su_task_cmp(su_task_r const a, su_task_r const b){  intptr_t retval = (char *)a->sut_port - (char *)b->sut_port;  if (retval == 0)    retval = (char *)a->sut_root - (char *)b->sut_root;  if (sizeof(retval) != sizeof(int)) {    if (retval < 0)      retval = -1;    else if (retval > 0)      retval = 1;  }  return (int)retval;}/** * Tests if a task is running. * * @param task  task handle * * @retval true (nonzero) if task is not stopped,  * @retval zero if it is null or stopped. */int su_task_is_running(su_task_r const task){  return     task &&     task->sut_port &&     task->sut_root;}/** @internal * Attach a root object to the task handle. * * @param self task handle * @param root pointer to the root object *  * @retval 0 if successful, * @retval -1 otherwise. */int su_task_attach(su_task_r self, su_root_t *root){  if (self->sut_port) {    self->sut_root = root;    return 0;  }  else     return -1;}/**  * Get root pointer attached to a task handle. * * @param self task handle * * @return  * A pointer to root object attached to the task handle, or NULL if no root * object has been attached. */su_root_t *su_task_root(su_task_r const self){  if (self->sut_port) return self->sut_root; else return NULL;}#if 0/** @internal * Detach a root pointer from task handle. * @bug Not used anymore. */int su_task_detach(su_task_r self){  self->sut_root = NULL;  return 0;}#endif/** * Return the timer list associated with given task. *  * @param task task handle * * @return A timer list of the task. If there are no timers, it returns * NULL. */su_timer_queue_t *su_task_timers(su_task_r const task){  return task->sut_port ? su_port_timers(task->sut_port) : NULL;}/** Execute the @a function by @a task thread. * * @retval 0 if successful * @retval -1 upon an error */int su_task_execute(su_task_r const task,		    int (*function)(void *), void *arg,		    int *return_value){  int dummy;  if (function == NULL)    return (errno = EFAULT), -1;  if (return_value == NULL)    return_value = &dummy;  if (!su_port_own_thread(task->sut_port)) {    return su_port_execute(task, function, arg, return_value);  }  else {    int value = function(arg);    if (return_value)      *return_value = value;    return 0;  }}_su_task_r su_task_new(su_task_r task, su_root_t *root, su_port_t *port);int su_task_attach(su_task_r self, su_root_t *root);int su_task_detach(su_task_r self);int su_timer_reset_all(su_timer_t **t0, su_task_r);/* Note that is *not* necessary same as su_root_t, * as su_root_t can be extended */#define sur_port sur_task->sut_port#define sur_root sur_task->sut_root#define SU_ROOT_OWN_THREAD(r) (r->sur_port && su_port_own_thread(r->sur_port))/** Create a reactor object. * * Allocate and initialize the instance of su_root_t. * * @param magic     pointer to user data * * @return A pointer to allocated su_root_t instance, NULL on error. */su_root_t *su_root_create(su_root_magic_t *magic){  return su_root_create_with_port(magic, su_port_create());}/**@internal * * Create a reactor object using given message port. * * Allocate and initialize the instance of su_root_t. Note that this * function always uses a reference to su_port_t, even when creating the * root fails. * * @param magic     pointer to user data * @param port      pointer to a message port * * @return A pointer to allocated su_root_t instance, NULL on error. */su_root_t *su_root_create_with_port(su_root_magic_t *magic,				    su_port_t *port){  su_root_t *self;  if (!port)    return NULL;  self = su_salloc(su_port_home(port), sizeof(struct su_root_s));  if (self) {    self->sur_magic = magic;#if SU_HAVE_PTHREADS    self->sur_threading = SU_HAVE_PTHREADS;#else    self->sur_threading = 0;#endif    /* This one creates a new reference to port */    su_task_new(self->sur_task, self, port);    /* ... so we zap the old one below */  }   su_port_decref(port, "su_root_create_with_port");  return self;}/** Destroy a root object. *  *  Stop and free an instance of su_root_t * * @param self     pointer to a root object. */void su_root_destroy(su_root_t *self){  su_port_t *port;  int unregistered, reset;  if (!self)    return;  assert(SU_ROOT_OWN_THREAD(self));  self->sur_deiniting = 1;  if (self->sur_deinit) {    su_root_deinit_f deinit = self->sur_deinit;    su_root_magic_t *magic = self->sur_magic;    self->sur_deinit = NULL;    deinit(self, magic);  }  port = self->sur_port; assert(port);  unregistered = su_port_unregister_all(port, self);  reset = su_timer_reset_all(su_task_timers(self->sur_task), self->sur_task);  if (unregistered || reset)    SU_DEBUG_1(("su_root_destroy: "		"%u registered waits, %u timers\n",		unregistered, reset));  SU_TASK_ZAP(self->sur_parent, su_root_destroy);  su_free(su_port_home(port), self);  su_port_decref(port, "su_root_destroy");}/** Get instance name. * * @param self      pointer to a root object * * @return Instance name (e.g., "epoll", "devpoll", "select"). * * @NEW_1_12_6. */char const *su_root_name(su_root_t *self){  if (!self)    return (void)(errno = EFAULT), NULL;  assert(self->sur_port);  return su_port_name(self->sur_task->sut_port);}/** Set the context pointer. * *  Set the context pointer (magic) of a root object. * * @param self      pointer to a root object * @param magic     pointer to user data * * @retval 0  when successful, * @retval -1 upon error. */int su_root_set_magic(su_root_t *self, su_root_magic_t *magic){  if (self == NULL)    return (void)(errno = EFAULT), -1;  assert(SU_ROOT_OWN_THREAD(self));  self->sur_magic = magic;  return 0;}/** Set threading option. * *   Controls whether su_clone_start() creates a new thread. * * @param self      pointer to a root object * @param enable    if true, enable threading, if false, disable threading * * @return True if threading is enabled. */int su_root_threading(su_root_t *self, int enable){  if (self == NULL)    return (void)(errno = EFAULT), -1;  assert(SU_ROOT_OWN_THREAD(self));#if SU_HAVE_PTHREADS  self->sur_threading = enable = enable != 0;  return enable;#else  return 0;#endif}/** Get context pointer. * *  The function su_root_magic() returns the user context pointer that was *  given input to su_root_create() or su_root_set_magic(). * * @param self      pointer to a root object * * @return A pointer to user data */su_root_magic_t *su_root_magic(su_root_t *self){  if (!self)    return (void)(errno = EFAULT), NULL;  return self->sur_magic;}/** Get a GSource */struct _GSource *su_root_gsource(su_root_t *self){  if (!self)    return (void)(errno = EFAULT), NULL;  assert(self->sur_port);  return su_port_gsource(self->sur_port);}/** Register a su_wait_t object.  * *  The function su_root_register() registers a su_wait_t object. The wait *  object, a callback function and a argument are stored to the root *  object. The callback function is called, when the wait object is *  signaled. * *  Please note if identical wait objects are inserted, only first one is *  ever signalled. * * @param self      pointer to root object * @param wait      pointer to wait object * @param callback  callback function pointer * @param arg       argument given to callback function when it is invoked * @param priority  relative priority of the wait object *                  (0 is normal, 1 important, 2 realtime) * * @return Nonzero index of the wait object, or -1 upon an error. */int su_root_register(su_root_t *self,		     su_wait_t *wait,		     su_wakeup_f callback,		     su_wakeup_arg_t *arg,		     int priority){  if (!self || !wait)    return (void)(errno = EFAULT), -1;  assert(self->sur_port);  return su_port_register(self->sur_port, self, wait, callback, arg, priority);}/** Unregister a su_wait_t object. * *  The function su_root_unregister() unregisters a su_wait_t object. The *  wait object, a callback function and a argument are removed from the *  root object. * * @param self      pointer to root object * @param wait      pointer to wait object * @param callback  callback function pointer (may be NULL) * @param arg       argument given to callback function when it is invoked *                  (may be NULL) * * @return Nonzero index of the wait object, or -1 upon an error. */int su_root_unregister(su_root_t *self,		       su_wait_t *wait,		       su_wakeup_f callback, /* XXX - ignored */		       su_wakeup_arg_t *arg){  if (!self || !wait)    return (void)(errno = EFAULT), -1;  assert(self->sur_port);  return su_port_unregister(self->sur_port, self, wait, callback, arg);}/** Remove a su_wait_t registration. *

⌨️ 快捷键说明

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