Chinaunix首页 | 论坛 | 博客
  • 博客访问: 837586
  • 博文数量: 756
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 4980
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:40
文章分类

全部博文(756)

文章存档

2011年(1)

2008年(755)

我的朋友

分类:

2008-10-13 16:12:03


//封装的epoll

static GObjectClass *parent_class = NULL;

#if HAVE_EPOLL_SUPPORT

#include
#include

/* epoll_create() etc based main-loop.

   Note that we use Level-Triggered behavior,
   not edge-triggered, since that is how GskMainLoops are.
 */

#define EPOLL_INITIAL_SIZE 2048
#define MAX_EPOLL_EVENTS 512

static inline const char *
op_to_string (int op)
{
  return (op == EPOLL_CTL_DEL) ? "del"
       : (op == EPOLL_CTL_MOD) ? "mod"
       : (op == EPOLL_CTL_ADD) ? "add"
       : "op-unknown";
}

/* --- GskMainLoopPollBase methods --- */
static gboolean
gsk_main_loop_epoll_setup  (GskMainLoop       *main_loop)
{
  GskMainLoopClass *pclass = GSK_MAIN_LOOP_CLASS (parent_class);
  int fd;
  if (pclass->setup != NULL)
    if (!(*pclass->setup) (main_loop))
      return FALSE;
  fd = epoll_create (EPOLL_INITIAL_SIZE);
  if (fd < 0)
    return FALSE;
  GSK_MAIN_LOOP_EPOLL (main_loop)->fd = fd;
  return TRUE;
}

static void
gsk_main_loop_epoll_config_fd (GskMainLoopPollBase   *main_loop,
                               int                    fd,
          GIOCondition           old_io_conditions,
                               GIOCondition           io_conditions)
{
  GskMainLoopEpoll *epoll = GSK_MAIN_LOOP_EPOLL (main_loop);
  int op = (io_conditions == 0) ? EPOLL_CTL_DEL
         : (old_io_conditions == 0) ? EPOLL_CTL_ADD
  : EPOLL_CTL_MOD;
  struct epoll_event event;
  if (old_io_conditions == 0 && io_conditions == 0)
    return;
  event.events = ((io_conditions & G_IO_IN) ? (EPOLLIN) : 0)
               | ((io_conditions & G_IO_OUT) ? (EPOLLOUT) : 0)
               | ((io_conditions & G_IO_HUP) ? (EPOLLHUP) : 0)
        ;
  event.data.fd = fd;
  if (epoll_ctl (epoll->fd, op, fd, &event) < 0)
    {
      g_warning ("epoll_ctl: op=%s, fd=%d, new_events=%x failed: %s",
   op_to_string (op), fd, event.events, g_strerror (errno));
    }
}

static gboolean
gsk_main_loop_epoll_do_polling (GskMainLoopPollBase   *main_loop,
                                int                    max_timeout,
                                guint                  max_events,
                                guint                 *num_events_out,
                                GskMainLoopEvent      *events)
{
  GskMainLoopEpoll *main_loop_epoll = GSK_MAIN_LOOP_EPOLL (main_loop);
  struct epoll_event *e_events = main_loop_epoll->epoll_events;
  int n_events;
  int i;
  guint n_out = 0;
  errno = EINTR;  // HACK: ignore errors which don't set errno !?!
  n_events = epoll_wait (main_loop_epoll->fd, e_events,
    MIN (max_events, MAX_EPOLL_EVENTS),
    max_timeout);
#if 0
  g_message ("epoll_wait: max_timeout=%d, max_events=%u, n_events out=%d",
      max_timeout, max_events, n_events);
#endif
  if (n_events < 0)
    {
      int e = errno;
      *num_events_out = 0;
      if (gsk_errno_is_ignorable (e))
 return TRUE;
      g_warning ("error running epoll_wait: %s", g_strerror (e));
      return TRUE;
    }

  for (i = 0; i < n_events; i++)
    {
      int fd = e_events[i].data.fd;
      unsigned e = e_events[i].events;
      GIOCondition condition = 0;
      if (e & EPOLLIN)
 condition |= G_IO_IN;
      if (e & EPOLLHUP)
 condition |= G_IO_HUP;
      if (e & EPOLLOUT)
 condition |= G_IO_OUT;
      events[n_out].type = GSK_MAIN_LOOP_EVENT_IO;
      events[n_out].data.io.events = condition;
      events[n_out].data.io.fd = fd;
      n_out++;
    }
  *num_events_out = n_out;

  return TRUE;
}

static void
gsk_main_loop_epoll_finalize (GObject *object)
{
  GskMainLoopEpoll *main_loop_epoll = GSK_MAIN_LOOP_EPOLL (object);
  g_free (main_loop_epoll->epoll_events);
  (*parent_class->finalize) (object);
}
#endif  /* HAVE_EPOLL_SUPPORT */

/* --- functions --- */
static void
gsk_main_loop_epoll_init (GskMainLoopEpoll *main_loop_epoll)
{
#if HAVE_EPOLL_SUPPORT
  main_loop_epoll->fd = -1;
  main_loop_epoll->epoll_events = g_new (struct epoll_event, MAX_EPOLL_EVENTS);
#endif  /* HAVE_EPOLL_SUPPORT */
}

static void
gsk_main_loop_epoll_class_init (GskMainLoopEpollClass *class)
{
#if HAVE_EPOLL_SUPPORT
  GskMainLoopPollBaseClass *main_loop_poll_base_class = GSK_MAIN_LOOP_POLL_BASE_CLASS (class);
  GskMainLoopClass *main_loop_class = GSK_MAIN_LOOP_CLASS (class);
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  main_loop_class->setup = gsk_main_loop_epoll_setup;
  main_loop_poll_base_class->config_fd = gsk_main_loop_epoll_config_fd;
  main_loop_poll_base_class->do_polling = gsk_main_loop_epoll_do_polling;
  object_class->finalize = gsk_main_loop_epoll_finalize;
#endif  /* HAVE_EPOLL_SUPPORT */
  parent_class = g_type_class_peek_parent (class);
}

GType gsk_main_loop_epoll_get_type()
{
  static GType main_loop_epoll_type = 0;
  if (!main_loop_epoll_type)
    {
      static const GTypeInfo main_loop_epoll_info =
      {
 sizeof(GskMainLoopEpollClass),
 (GBaseInitFunc) NULL,
 (GBaseFinalizeFunc) NULL,
 (GClassInitFunc) gsk_main_loop_epoll_class_init,
 NULL,  /* class_finalize */
 NULL,  /* class_data */
 sizeof (GskMainLoopEpoll),
 0,  /* n_preallocs */
 (GInstanceInitFunc) gsk_main_loop_epoll_init,
 NULL  /* value_table */
      };
      main_loop_epoll_type = g_type_register_static (GSK_TYPE_MAIN_LOOP_POLL_BASE,
                                                  "GskMainLoopEpoll",
        &main_loop_epoll_info, 0);
    }
  return main_loop_epoll_type;
}

//封装的kqueue

static GObjectClass *parent_class = NULL;

#if HAVE_KQUEUE
#include

/* Include headers for kqueue(), kevent() and struct kevent. */
#include
#include
#include
#endif

#include     /* needed for close() */
#include

/* --- GskMainLoop methods --- */

static gboolean
gsk_main_loop_kqueue_setup (GskMainLoop *main_loop)
{
  GskMainLoopKqueue *main_loop_kqueue = GSK_MAIN_LOOP_KQUEUE (main_loop);
#if HAVE_KQUEUE
  main_loop_kqueue->kernel_queue_id = kqueue ();
  return (main_loop_kqueue->kernel_queue_id >= 0);
#else
  (void) main_loop_kqueue;
  return FALSE;
#endif
}

#if HAVE_KQUEUE
static void
kqueue_flush_pending_changes (GskMainLoopKqueue *main_loop_kqueue)
{
  if (main_loop_kqueue->num_updates > 0)
    {
      struct timespec timeout = { 0, 0 };
      kevent (main_loop_kqueue->kernel_queue_id,
              (const struct kevent *) main_loop_kqueue->kevent_array,
       main_loop_kqueue->num_updates,
       NULL, 0,
              &timeout);
      main_loop_kqueue->num_updates = 0;
    }
}

static inline void
change_signal (int signo, gboolean ignore)
{
  struct sigaction action;
  memset (&action, 0, sizeof (action));
  action.sa_handler = ignore ? SIG_IGN : SIG_DFL;
  sigaction (signo, &action, NULL);
}

static inline struct kevent *
get_next_update ( GskMainLoopKqueue *main_loop_kqueue)
{
  if (main_loop_kqueue->num_updates == main_loop_kqueue->max_updates)
    {
      if (main_loop_kqueue->max_updates == 0)
        main_loop_kqueue->max_updates = 128;
      else
        main_loop_kqueue->max_updates *= 2;
      main_loop_kqueue->kevent_array
 = g_realloc (main_loop_kqueue->kevent_array,
       sizeof (struct kevent) * main_loop_kqueue->max_updates);
    }
  return ((struct kevent *) (main_loop_kqueue->kevent_array))
        + main_loop_kqueue->num_updates;
}
 

static void
gsk_main_loop_kqueue_change (GskMainLoop       *main_loop,
                             GskMainLoopChange *change)
{
  GskMainLoopKqueue *main_loop_kqueue = GSK_MAIN_LOOP_KQUEUE (main_loop);
  if (main_loop_kqueue->num_updates + 1 >= main_loop_kqueue->max_updates)
    {
      if (main_loop_kqueue->max_updates == 0)
        main_loop_kqueue->max_updates = 128;
      else
        main_loop_kqueue->max_updates *= 2;
      main_loop_kqueue->kevent_array
 = g_realloc (main_loop_kqueue->kevent_array,
       sizeof (struct kevent) * main_loop_kqueue->max_updates);
    }
  switch (change->type)
    {
      static gboolean has_ignored_sigchld = FALSE;
      struct kevent *event;
    case GSK_MAIN_LOOP_EVENT_PROCESS:
      if (change->data.process.did_exit)
        return;
      event = get_next_update (main_loop_kqueue);
      event->ident = change->data.process.pid;
      event->filter = EVFILT_PROC;
      event->flags = change->data.process.add ? (EV_ADD|EV_ONESHOT|EV_CLEAR) : EV_DELETE;
      event->fflags = NOTE_EXIT;
      event->data = 0;
      event->udata = NULL;
      main_loop_kqueue->num_updates++;
      if (!has_ignored_sigchld)
        {
          change_signal (SIGCHLD, TRUE);
          has_ignored_sigchld = TRUE;
        }
      break;
    case GSK_MAIN_LOOP_EVENT_SIGNAL:
      event = get_next_update (main_loop_kqueue);
      event->ident = change->data.signal.number;
      event->filter = EVFILT_SIGNAL;
      event->flags = change->data.signal.add ? EV_ADD : EV_DELETE;
      event->fflags = 0;
      event->data = 0;
      event->udata = NULL;
      change_signal (change->data.signal.number, change->data.signal.add);
      main_loop_kqueue->num_updates++;
      kqueue_flush_pending_changes (main_loop_kqueue);
      break;
    case GSK_MAIN_LOOP_EVENT_IO:
      if ((change->data.io.old_events ^ change->data.io.events) & G_IO_IN)
 {
          event = get_next_update (main_loop_kqueue);
   event->ident = change->data.io.fd;
   event->filter = EVFILT_READ;
   event->flags = (change->data.io.events & G_IO_IN) ? EV_ADD : EV_DELETE;
   event->fflags = 0;
   event->data = 0;
   event->udata = NULL;
   main_loop_kqueue->num_updates++;
 }
      if ((change->data.io.old_events ^ change->data.io.events) & G_IO_OUT)
 {
          event = get_next_update (main_loop_kqueue);
   event->ident = change->data.io.fd;
   event->filter = EVFILT_WRITE;
   event->flags = (change->data.io.events & G_IO_OUT) ? EV_ADD : EV_DELETE;
   event->fflags = 0;
   event->data = 0;
   event->udata = NULL;
   main_loop_kqueue->num_updates++;
 }
      kqueue_flush_pending_changes (main_loop_kqueue);
      break;
    }
}

static guint
gsk_main_loop_kqueue_poll (GskMainLoop       *main_loop,
                           guint              max_events_out,
                           GskMainLoopEvent  *events,
                           gint               timeout_milli)
{
  struct kevent *out = alloca (sizeof (struct kevent) * max_events_out);
  GskMainLoopKqueue *main_loop_kqueue = GSK_MAIN_LOOP_KQUEUE (main_loop);
  guint kevent_rv;
  guint i;
  guint rv = 0;
  struct timespec timeout;
  struct timespec *p_timeout;
  if (timeout_milli < 0)
    {
      p_timeout = NULL;
    }
  else
    {
      timeout.tv_sec = timeout_milli / 1000;
      timeout.tv_nsec = timeout_milli % 1000 * 1000 * 1000;
      p_timeout = &timeout;
    }
  kevent_rv = kevent (main_loop_kqueue->kernel_queue_id,
        main_loop_kqueue->kevent_array,
        main_loop_kqueue->num_updates,
        out,
        max_events_out,
        p_timeout);
  main_loop_kqueue->num_updates = 0;

  for (i = 0; i < kevent_rv; i++)
    {
      switch (out[i].filter)
        {
        case EVFILT_READ:
          events[rv].type = GSK_MAIN_LOOP_EVENT_IO;
          events[rv].data.io.events = G_IO_IN;
          events[rv].data.io.fd = out[i].ident;
          rv++;
          break;
         
        case EVFILT_WRITE:
          events[rv].type = GSK_MAIN_LOOP_EVENT_IO;
          events[rv].data.io.events = G_IO_OUT;
          events[rv].data.io.fd = out[i].ident;
          rv++;
          break;

        case EVFILT_SIGNAL:
          events[rv].type = GSK_MAIN_LOOP_EVENT_SIGNAL;
          events[rv].data.signal = out[i].ident;
          rv++;
          break;

        case EVFILT_PROC:
          if (out[i].fflags == NOTE_EXIT)
            {
              events[rv].type = GSK_MAIN_LOOP_EVENT_PROCESS;
              events[rv].data.process_wait_info.pid = out[i].ident;
              if (gsk_main_loop_do_waitpid (out[i].ident,
                                         &events[rv].data.process_wait_info))
                rv++;
            }
          break;

        default:
          g_warning ("unexpected type of event from kevent (%d)",
                     out[i].filter);
        }
    }
  return rv;
}
#endif

static void   
gsk_main_loop_kqueue_finalize(GObject *object)
{
  GskMainLoopKqueue *kqueue = GSK_MAIN_LOOP_KQUEUE (object);
  gsk_main_loop_destroy_all_sources (GSK_MAIN_LOOP (object));
  if (kqueue->kernel_queue_id >= 0)
    close (kqueue->kernel_queue_id);
  (*parent_class->finalize) (object);
}

/* --- class methods --- */
static void
gsk_main_loop_kqueue_init (GskMainLoopKqueue *kqueue)
{
  kqueue->kernel_queue_id = -1;
}

static void
gsk_main_loop_kqueue_class_init (GskMainLoopClass *main_loop_class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (main_loop_class);
  parent_class = g_type_class_peek_parent (main_loop_class);
  main_loop_class->setup = gsk_main_loop_kqueue_setup;
#if HAVE_KQUEUE
  main_loop_class->poll = gsk_main_loop_kqueue_poll;
  main_loop_class->change = gsk_main_loop_kqueue_change;
#endif
  object_class->finalize = gsk_main_loop_kqueue_finalize;
}

GType
gsk_main_loop_kqueue_get_type()
{
  static GType main_loop_kqueue_type = 0;
  if (!main_loop_kqueue_type)
    {
      static const GTypeInfo main_loop_kqueue_info =
      {
 sizeof(GskMainLoopKqueueClass),
 (GBaseInitFunc) NULL,
 (GBaseFinalizeFunc) NULL,
 (GClassInitFunc) gsk_main_loop_kqueue_class_init,
 NULL,  /* class_finalize */
 NULL,  /* class_data */
 sizeof (GskMainLoopKqueue),
 0,  /* n_preallocs */
 (GInstanceInitFunc) gsk_main_loop_kqueue_init,
 NULL  /* value_table */
      };
      GType parent = GSK_TYPE_MAIN_LOOP;
      main_loop_kqueue_type = g_type_register_static (parent,
                                                  "GskMainLoopKqueue",
        &main_loop_kqueue_info, 0);
    }
  return main_loop_kqueue_type;
}


--------------------next---------------------

阅读(622) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~