Пример #1
0
/** @internal Main loop.
 *
 * The function @c su_port_run() waits for wait objects and the timers
 * associated with the port object.  When any wait object is signaled or
 * timer is expired, it invokes the callbacks, and returns waiting.
 *
 * The function @c su_port_run() runs until @c su_port_break() is called
 * from a callback.
 *
 * @param self     pointer to port object
 *
 */
void su_base_port_run(su_port_t *self)
{
  su_duration_t tout = 0, tout2 = 0;

  assert(su_port_own_thread(self));

  for (self->sup_running = 1; self->sup_running;) {
    tout = self->sup_max_defer;

    if (self->sup_prepoll)
      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);

    if (self->sup_head)
      self->sup_vtable->su_port_getmsgs(self);

    if (self->sup_timers || self->sup_deferrable) {
      su_time_t now = su_now();
      su_timer_expire(&self->sup_timers, &tout, now);
      su_timer_expire(&self->sup_deferrable, &tout2, now);
    }

    if (!self->sup_running)
      break;

    if (self->sup_head)      /* if there are messages do a quick wait */
      tout = 0;

    self->sup_vtable->su_port_wait_events(self, tout);
  }
}
Пример #2
0
/** Unregister a su_wait_t object.
 *
 *  The function su_devpoll_port_unregister() unregisters a su_wait_t object. The
 *  wait object, a callback function and a argument are removed from the
 *  port object.
 *
 * @param self     - pointer to port object
 * @param root     - 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)
 *
 * @deprecated Use su_devpoll_port_deregister() instead.
 *
 * @return Nonzero index of the wait object, or -1 upon an error.
 */
int su_devpoll_port_unregister(su_port_t *self,
			     su_root_t *root,
			     su_wait_t *wait,
			     su_wakeup_f callback, /* XXX - ignored */
			     su_wakeup_arg_t *arg)
{
  int i, I;

  struct su_devpoll *ser;

  assert(self);
  assert(su_port_own_thread(self));

  I = self->sup_max_index;

  for (i = 1; i <= I; i++) {
    ser = self->sup_indices[i];

    if (ser->ser_cb &&
	arg == ser->ser_arg &&
	SU_WAIT_CMP(wait[0], ser->ser_wait[0]) == 0)
      return su_devpoll_port_deregister0(self, ser->ser_id, 0);
  }

  su_seterrno(ENOENT);

  return -1;
}
Пример #3
0
/** @internal
 * Unregister all su_wait_t objects.
 *
 * The function su_poll_port_unregister_all() unregisters all su_wait_t objects
 * and destroys all queued timers associated with given root object.
 *
 * @param  self     - pointer to port object
 * @param  root     - pointer to root object
 *
 * @return Number of wait objects removed.
 */
int su_poll_port_unregister_all(su_port_t *self,
				su_root_t *root)
{
  int i, j, index, N;
  int             *indices, *reverses;
  su_wait_t       *waits;
  su_wakeup_f     *wait_cbs;
  su_wakeup_arg_t**wait_args;
  su_root_t      **wait_roots;

  assert(su_port_own_thread(self));

  N          = self->sup_n_waits;
  indices    = self->sup_indices;
  reverses   = self->sup_reverses;
  waits      = self->sup_waits;
  wait_cbs   = self->sup_wait_cbs;
  wait_args  = self->sup_wait_args;
  wait_roots = self->sup_wait_roots;

  for (i = j = 0; i < N; i++) {
    index = reverses[i]; assert(index > 0 && indices[index] == i);

    if (wait_roots[i] == root) {
      /* XXX - we should free all resources associated with this, too */
      if (i < self->sup_pri_offset)
	self->sup_pri_offset--;

      indices[index] = indices[0];
      indices[0] = -index;
      continue;
    }

    if (i != j) {
      indices[index] = j;
      reverses[j]   = reverses[i];
      waits[j]      = waits[i];
      wait_cbs[j]   = wait_cbs[i];
      wait_args[j]  = wait_args[i];
      wait_roots[j] = wait_roots[i];
    }

    j++;
  }

  for (i = j; i < N; i++) {
    reverses[i] = -1;
    wait_cbs[i] = NULL;
    wait_args[i] = NULL;
    wait_roots[i] = NULL;
  }
  memset(&waits[j], 0, (char *)&waits[N] - (char *)&waits[j]);

  self->sup_n_waits = j;
  self->sup_registers++;

  return N - j;
}
Пример #4
0
/** @internal Block until wait object is signaled or timeout.
 *
 * This function waits for wait objects and the timers associated with
 * the root object.  When any wait object is signaled or timer is
 * expired, it invokes the callbacks.
 *
 *   This function returns when a callback has been invoked or @c tout
 *   milliseconds is elapsed.
 *
 * @param self     pointer to port
 * @param tout     timeout in milliseconds
 *
 * @return
 *   Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if
 *   there are no active timers.
 */
su_duration_t su_base_port_step(su_port_t *self, su_duration_t tout)
{
  su_time_t now = su_now();

  assert(su_port_own_thread(self));

  if (self->sup_prepoll)
    self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);

  if (self->sup_head)
    self->sup_vtable->su_port_getmsgs(self);

  if (self->sup_timers)
    su_timer_expire(&self->sup_timers, &tout, now);

  /* XXX: why isn't the timeout ignored here? */
  if (self->sup_deferrable)
    su_timer_expire(&self->sup_deferrable, &tout, now);

  /* if there are messages do a quick wait */
  if (self->sup_head)
    tout = 0;

  if (self->sup_vtable->su_port_wait_events(self, tout))
    tout = 0;
  else
    tout = SU_WAIT_FOREVER;

  if (self->sup_head) {
    if (self->sup_vtable->su_port_getmsgs(self)) {
      /* Check for wait events that may have been generated by messages */
      if (self->sup_vtable->su_port_wait_events(self, 0))
	tout = 0;
    }
  }

  if (self->sup_timers || self->sup_deferrable) {
    su_duration_t tout2 = SU_WAIT_FOREVER;

    now = su_now();
    su_timer_expire(&self->sup_timers, &tout, now);
    su_timer_expire(&self->sup_deferrable, &tout2, now);

    if (tout == SU_WAIT_FOREVER && tout2 != SU_WAIT_FOREVER) {
      if (tout2 < self->sup_max_defer)
	tout2 = self->sup_max_defer;
      tout = tout2;
    }
  }

  if (self->sup_head)
    tout = 0;

  return tout;
}
Пример #5
0
/**Set mask for a registered event. @internal
 *
 * The function su_poll_port_eventmask() sets the mask describing events
 * that can signal the registered callback.
 *
 * @param port   pointer to port object
 * @param index  registration index
 * @param socket socket
 * @param events new event mask
 *
 * @retval 0 when successful,
 * @retval -1 upon an error.
 */
int su_poll_port_eventmask(su_port_t *self, int index, int socket, int events)
{
  int n;
  assert(self);
  assert(su_port_own_thread(self));

  if (index <= 0 || index > self->sup_size_waits)
    return su_seterrno(EBADF);
  n = self->sup_indices[index];
  if (n < 0)
    return su_seterrno(EBADF);

  return su_wait_mask(&self->sup_waits[n], socket, events);
}
Пример #6
0
/* This version can help tuning... */
void su_base_port_run_tune(su_port_t *self)
{
  int i;
  int timers = 0, messages = 0, events = 0;
  su_duration_t tout = 0, tout2 = 0;
  su_time_t started = su_now(), woken = started, bedtime = woken;

  assert(su_port_own_thread(self));

  for (self->sup_running = 1; self->sup_running;) {
    tout = self->sup_max_defer;

    timers = 0, messages = 0;

    if (self->sup_prepoll)
      self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root);

    if (self->sup_head)
      messages = self->sup_vtable->su_port_getmsgs(self);

    if (self->sup_timers || self->sup_deferrable) {
      su_time_t now = su_now();
      timers =
	su_timer_expire(&self->sup_timers, &tout, now) +
	su_timer_expire(&self->sup_deferrable, &tout2, now);
    }

    if (!self->sup_running)
      break;

    if (self->sup_head)      /* if there are messages do a quick wait */
      tout = 0;

    bedtime = su_now();

    events = self->sup_vtable->su_port_wait_events(self, tout);

    woken = su_now();

    if (messages || timers || events)
      SU_DEBUG_1(("su_port_run(%p): %.6f: %u messages %u timers %u "
		  "events slept %.6f/%.3f\n",
		  self, su_time_diff(woken, started), messages, timers, events,
		  su_time_diff(woken, bedtime), tout * 1e-3));

    if (!self->sup_running)
      break;
  }
}
Пример #7
0
/** Deregister a su_wait_t object.
 *
 *  Deregisters a registration by index. The wait object, a callback
 *  function and a argument are removed from the port object. The wait
 *  object is destroyed.
 *
 * @param self     - pointer to port object
 * @param i        - registration index
 *
 * @return Index of the wait object, or -1 upon an error.
 */
int su_poll_port_deregister(su_port_t *self, int i)
{
  su_wait_t wait[1] = { SU_WAIT_INIT };
  int retval;

  assert(self);
  assert(su_port_own_thread(self));

  if (i <= 0 || i > self->sup_size_waits)
    return su_seterrno(EBADF);

  if (self->sup_indices[i] < 0)
    return su_seterrno(EBADF);

  retval = su_poll_port_deregister0(self, i, 1);

  su_wait_destroy(wait);

  return retval;
}
Пример #8
0
/** @internal
 * Unregister all su_wait_t objects of given su_root_t instance.
 *
 * The function su_devpoll_port_unregister_all() unregisters all su_wait_t
 * objects associated with given root object.
 *
 * @param  self     - pointer to port object
 * @param  root     - pointer to root object
 *
 * @return Number of wait objects removed.
 */
int su_devpoll_port_unregister_all(su_port_t *self, su_root_t *root)
{
  int i, I, n;

  struct su_devpoll *ser;

  assert(self); assert(root);
  assert(su_port_own_thread(self));

  I = self->sup_max_index;

  for (i = 1, n = 0; i <= I; i++) {
    ser = self->sup_indices[i];
    if (ser->ser_root != root)
      continue;
    su_devpoll_port_deregister0(self, ser->ser_id, 0);
    n++;
  }

  return n;
}
Пример #9
0
/** Unregister a su_wait_t object.
 *
 *  The function su_poll_port_unregister() unregisters a su_wait_t object. The
 *  wait object, a callback function and a argument are removed from the
 *  port object.
 *
 * @param self     - pointer to port object
 * @param root     - 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)
 *
 * @deprecated Use su_poll_port_deregister() instead.
 *
 * @return Nonzero index of the wait object, or -1 upon an error.
 */
int su_poll_port_unregister(su_port_t *self,
			    su_root_t *root,
			    su_wait_t *wait,
			    su_wakeup_f callback, /* XXX - ignored */
			    su_wakeup_arg_t *arg)
{
  int n, N;

  assert(self);
  assert(su_port_own_thread(self));

  N = self->sup_n_waits;

  for (n = 0; n < N; n++) {
    if (SU_WAIT_CMP(wait[0], self->sup_waits[n]) == 0) {
      return su_poll_port_deregister0(self, self->sup_reverses[n], 0);
    }
  }

  su_seterrno(ENOENT);

  return -1;
}
Пример #10
0
/** 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;
    }
}
Пример #11
0
/** @internal
 *
 *  Register a #su_wait_t object. The wait object, a callback function and
 *  an argument pointer is stored in the port object.  The callback function
 *  will be 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 port
 * @param root	     pointer to root object
 * @param waits	     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
 *   Positive index of the wait object,
 *   or -1 upon an error.
 */
int su_devpoll_port_register(su_port_t *self,
			     su_root_t *root,
			     su_wait_t *wait,
			     su_wakeup_f callback,
			     su_wakeup_arg_t *arg,
			     int priority)
{
  int i, j, n;
  struct su_devpoll *ser;
  struct su_devpoll **indices = self->sup_indices;
  struct su_devpoll **devpoll_by_socket = self->sup_devpoll_by_socket;
  su_home_t *h = su_port_home(self);
  struct pollfd pollfd[1];

  assert(su_port_own_thread(self));

  if (wait->fd < 0)
    return su_seterrno(EINVAL);

  n = self->sup_size_indices;

  if (n >= SU_WAIT_MAX)
    return su_seterrno(ENOMEM);

  ser = indices[0];

  if (!ser) {
    i = self->sup_max_index, j = i == 0 ? 15 : i + 16;

    if (j >= self->sup_size_indices) {
      /* Reallocate index table */
      n = n < 1024 ? 2 * n : n + 1024;
      indices = su_realloc(h, indices, n * sizeof(indices[0]));
      if (!indices)
	return -1;
      self->sup_indices = indices;
      self->sup_size_indices = n;
    }

    /* Allocate registrations */
    ser = su_zalloc(h, (j - i) * (sizeof *ser));
    if (!ser)
      return -1;

    indices[0] = ser;

    for (i++; i <= j; i++) {
      ser->ser_id = i;
      ser->ser_next = i < j ? ser + 1 : NULL;
      indices[i] = ser++;
    }

    self->sup_max_index = j;

    ser = indices[0];
  }

  if ((size_t)wait->fd >= self->sup_n_devpoll_by_socket) {
    size_t n_devpoll_by_socket = ((size_t)wait->fd + 32) / 32 * 32;

    devpoll_by_socket = su_realloc(h, devpoll_by_socket,
				   n_devpoll_by_socket *
				   (sizeof devpoll_by_socket[0]));
    if (devpoll_by_socket == NULL)
      return -1;

    memset(&devpoll_by_socket[self->sup_n_devpoll_by_socket],
	   0,
	   (char *)&devpoll_by_socket[n_devpoll_by_socket] -
	   (char *)&devpoll_by_socket[self->sup_n_devpoll_by_socket]);

    self->sup_devpoll_by_socket = devpoll_by_socket;
    self->sup_n_devpoll_by_socket = n_devpoll_by_socket;
  }


  if (devpoll_by_socket[wait->fd])
    /* XXX - we should lift this limitation with epoll, too */
    return errno = EEXIST, -1;

  i = ser->ser_id;

  pollfd->fd = wait->fd;
  pollfd->events = wait->events & ~POLLREMOVE;
  pollfd->revents = 0;

  if (write(self->sup_devpoll, pollfd, (sizeof pollfd)) != (sizeof pollfd)) {
    return errno = EIO, -1;
  }

  indices[0] = ser->ser_next;
  devpoll_by_socket[wait->fd] = ser;

  ser->ser_next = NULL;
  *ser->ser_wait = *wait;
  ser->ser_cb = callback;
  ser->ser_arg = arg;
  ser->ser_root = root;

  self->sup_registers++;
  self->sup_n_registrations++;

  return i;			/* return index */
}
Пример #12
0
/** @internal
 *
 *  Register a @c su_wait_t object. The wait object, a callback function and
 *  an argument pointer is stored in the port object.  The callback function
 *  will be 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 port
 * @param root	     pointer to root object
 * @param waits	     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
 *   Positive index of the wait object,
 *   or -1 upon an error.
 */
int su_poll_port_register(su_port_t *self,
			  su_root_t *root,
			  su_wait_t *wait,
			  su_wakeup_f callback,
			  su_wakeup_arg_t *arg,
			  int priority)
{
  int i, j, n;

  assert(su_port_own_thread(self));

  n = self->sup_n_waits;

  if (n >= SU_WAIT_MAX)
    return su_seterrno(ENOMEM);

  if (n >= self->sup_size_waits) {
    su_home_t *h = self->sup_home;
    /* Reallocate size arrays */
    int size;
    int *indices;
    int *reverses;
    su_wait_t *waits;
    su_wakeup_f *wait_cbs;
    su_wakeup_arg_t **wait_args;
    su_root_t **wait_tasks;

    if (self->sup_size_waits == 0)
      size = su_root_size_hint;
    else
      size = 2 * self->sup_size_waits;

    if (size < SU_WAIT_MIN)
      size = SU_WAIT_MIN;

    /* Too large */
    if (-3 - size > 0)
      return (errno = ENOMEM), -1;

    indices = su_realloc(h, self->sup_indices, (size + 1) * sizeof(*indices));
    if (indices) {
      self->sup_indices = indices;

      if (self->sup_size_waits == 0)
	indices[0] = -1;

      for (i = self->sup_size_waits + 1; i <= size; i++)
	indices[i] = -1 - i;
    }

    reverses = su_realloc(h, self->sup_reverses, size * sizeof(*waits));
    if (reverses) {
      for (i = self->sup_size_waits; i < size; i++)
	reverses[i] = -1;
      self->sup_reverses = reverses;
    }

    waits = su_realloc(h, self->sup_waits, size * sizeof(*waits));
    if (waits)
      self->sup_waits = waits;

    wait_cbs = su_realloc(h, self->sup_wait_cbs, size * sizeof(*wait_cbs));
    if (wait_cbs)
      self->sup_wait_cbs = wait_cbs;

    wait_args = su_realloc(h, self->sup_wait_args, size * sizeof(*wait_args));
    if (wait_args)
      self->sup_wait_args = wait_args;

    /* Add sup_wait_roots array, if needed */
    wait_tasks = su_realloc(h, self->sup_wait_roots, size * sizeof(*wait_tasks));
    if (wait_tasks)
      self->sup_wait_roots = wait_tasks;

    if (!(indices &&
	  reverses && waits && wait_cbs && wait_args && wait_tasks)) {
      return -1;
    }

    self->sup_size_waits = size;
  }

  i = -self->sup_indices[0]; assert(i <= self->sup_size_waits);

  if (priority > 0) {
    /* Insert */
    for (n = self->sup_n_waits; n > 0; n--) {
      j = self->sup_reverses[n-1]; assert(self->sup_indices[j] == n - 1);
      self->sup_indices[j] = n;
      self->sup_reverses[n] = j;
      self->sup_waits[n] = self->sup_waits[n-1];
      self->sup_wait_cbs[n] = self->sup_wait_cbs[n-1];
      self->sup_wait_args[n] = self->sup_wait_args[n-1];
      self->sup_wait_roots[n] = self->sup_wait_roots[n-1];
    }

    self->sup_pri_offset++;
  }
  else {
    /* Append - no need to move anything */
    n = self->sup_n_waits;
  }

  self->sup_n_waits++;

  self->sup_indices[0] = self->sup_indices[i];  /* Free index */
  self->sup_indices[i] = n;

  self->sup_reverses[n] = i;
  self->sup_waits[n] = *wait;
  self->sup_wait_cbs[n] = callback;
  self->sup_wait_args[n] = arg;
  self->sup_wait_roots[n] = root;

  self->sup_registers++;

  /* Just like epoll, we return -1 or positive integer */

  return i;
}
Пример #13
0
/** @internal Deinit a base implementation of port. */
void su_base_port_deinit(su_port_t *self)
{
  if (su_port_own_thread(self))
    su_port_release(self);
}