/** @internal
 * Wait (poll()) for wait objects in port.
 *
 * @param self     pointer to port
 * @param tout     timeout in milliseconds
 *
 * @return number of events handled
 */
static
int su_wsevent_port_wait_events(su_port_t *self, su_duration_t tout)
{
  int i, events = 0;
  su_wait_t *waits = self->sup_waits;
  int n = self->sup_n_waits;
  su_root_t *root;

  i = su_wait(waits, (unsigned)n, tout);

  if (i >= 0 && i < n) {
#if 0
    /* poll() can return events for multiple wait objects */
    if (self->sup_multishot) {
      unsigned version = self->sup_registers;

      for (; i < n; i++) {
        if (waits[i].revents) {
          root = self->sup_wait_roots[i];
          self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
                                &waits[i],
                                self->sup_wait_args[i]);
          events++;
          /* Callback function used su_register()/su_deregister() */
          if (version != self->sup_registers)
            break;
        }
      }
    }
#else
    if (0) ;
#endif
    else {
      root = self->sup_wait_roots[i];
      self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
                            &self->sup_waits[i],
                            self->sup_wait_args[i]);
      events++;
    }
  }

  return events;
}
static
gboolean su_source_dispatch(GSource *gs,
			    GSourceFunc callback,
			    gpointer user_data)
{
  SuSource *ss = (SuSource *)gs;
  su_port_t *self = ss->ss_port;

  enter;

  if (self->sup_base->sup_head)
    su_base_port_getmsgs(self);

  if (self->sup_base->sup_timers || self->sup_base->sup_deferrable) {
    su_time_t now;
    GTimeVal  gtimeval;
    su_duration_t tout;

    tout = SU_DURATION_MAX;

    g_source_get_current_time(gs, &gtimeval);

    now.tv_sec = gtimeval.tv_sec + 2208988800UL;
    now.tv_usec = gtimeval.tv_usec;

    su_timer_expire(&self->sup_base->sup_timers, &tout, now);
    su_timer_expire(&self->sup_base->sup_deferrable, &tout, now);
  }

#if SU_HAVE_POLL
  {
    su_root_t *root;
    su_wait_t *waits = self->sup_waits;
    unsigned i, n = self->sup_n_waits;
    unsigned version = self->sup_registers;

    for (i = 0; i < n; i++) {
      if (waits[i].revents) {
	root = self->sup_wait_roots[i];
	self->sup_wait_cbs[i](root ? su_root_magic(root) : NULL,
			      &waits[i],
			      self->sup_wait_args[i]);
	/* Callback used su_register()/su_unregister() */
	if (version != self->sup_registers)
	  break;
      }
    }
  }
#endif

  if (!callback)
    return TRUE;

  return callback(user_data);
}
/** @internal
 * Wait (poll()) for wait objects in port.
 *
 * @param self     pointer to port
 * @param tout     timeout in milliseconds
 *
 * @return number of events handled
 */
static
int su_devpoll_port_wait_events(su_port_t *self, su_duration_t tout)
{
  int j, n, events = 0;
  unsigned version = self->sup_registers;

  int const M = 4;
  struct pollfd ev[M];
  struct dvpoll dp[1];

  dp->dp_fds = memset(ev, 0, sizeof ev);
  dp->dp_nfds = self->sup_multishot ? M : 1;
  dp->dp_timeout = tout >= INT_MAX ? INT_MAX : tout;

  n = ioctl(self->sup_devpoll, DP_POLL, dp);

  for (j = 0; j < n; j++) {
    int socket;
    struct su_devpoll *ser;
    su_root_magic_t *magic;

    socket = ev[j].fd;
    if (socket < 0 || self->sup_n_devpoll_by_socket <= socket)
      continue;
    ser = self->sup_devpoll_by_socket[socket]; assert(ser);

    magic = ser->ser_root ? su_root_magic(ser->ser_root) : NULL;
    ser->ser_wait->revents = ev[j].revents;
    ser->ser_cb(magic, ser->ser_wait, ser->ser_arg);
    events++;
    if (version != self->sup_registers)
      /* Callback function used su_register()/su_deregister() */
      break;
  }

  return events;
}