Logo Search packages:      
Sourcecode: rageircd version File versions  Download package

engine_kqueue.c

/*
 * RageIRCd: an advanced Internet Relay Chat daemon (ircd).
 * (C) 2000-2005 the RageIRCd Development Team, all rights reserved.
 *
 * This software is free, licensed under the General Public License.
 * Please refer to doc/LICENSE and doc/README for further details.
 *
 * $Id: engine_kqueue.c,v 1.22.2.3 2005/06/24 19:06:17 amcwilliam Exp $
 */

#include "setup.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "fd.h"
#include "memory.h"
#include <sys/types.h>
#include <sys/time.h>

#ifdef USE_KQUEUE

#include <sys/event.h>

#define KEVENT_LENGTH 128

#ifndef EV_SET
#define EV_SET(kep, a, b, c, d, e, f)     do { \
                                    (kep)->ident = (a); \
                                    (kep)->filter = (b); \
                                    (kep)->flags = (c); \
                                    (kep)->fflags = (d); \
                                    (kep)->data = (e); \
                                    (kep)->udata = (f); \
                              } while (0)
#endif

typedef struct _ircd_kqueue ircd_kqueue;
struct _ircd_kqueue {
      int id;
      struct kevent *list;
      int max;
      int offset;
      struct timespec timespec;
};

static ircd_kqueue kq;

static void kq_update_events(int fd, short filter, FDCB *cb)
{
      int kep_flags;
      fd_entry *fde = &fd_table[fd];
      FDCB *curcb;

      if (filter == EVFILT_READ) {
            curcb = fde->read.handler;
      }
      else if (filter == EVFILT_WRITE) {
            curcb = fde->write.handler;
      }
      else {
            return;
      }

      if (((curcb == NULL) && (cb != NULL)) || ((curcb != NULL) && (cb == NULL))) {
            struct kevent *kep = kq.list + kq.offset;

            if (cb != NULL) {
                  kep_flags = (filter == EVFILT_WRITE) ? (EV_ADD|EV_ONESHOT) : EV_ADD;
            }
            else {
                  kep_flags = EV_DELETE;
            }

            EV_SET(kep, fd, filter, kep_flags, 0, 0, 0);

            if (kq.offset == kq.max) {
                  int ret;

                  if ((ret = kevent(kq.id, kq.list, kq.offset, NULL, 0, &kq.timespec)) == -1) {
                        ircdlog(LOG_ERROR, "kevent() returned error %d: %s", errno, strerror(errno));
                        return;
                  }

                  kq.offset = 0;
            }
            else {
                  kq.offset++;
            }
      }
}
                        
void engine_init()
{
      memset(&kq, '\0', sizeof(ircd_kqueue));
      if ((kq.id = kqueue()) < 0) {
            ircdlog(LOG_ERROR, "FATAL: engine_init() aborted with kqueue failure %d: %s", errno, strerror(errno));
            abort();
      }

      kq.max = getdtablesize();
      kq.list = (struct kevent *)MyMalloc(sizeof(struct kevent) * kq.max);
      kq.timespec.tv_sec = 0;
      kq.timespec.tv_nsec = 0;
}

void engine_set_call(int fd, unsigned short flags, FDCB *cb, void *data, time_t timeout)
{
      fd_entry *fde = &fd_table[fd];

      if (flags & FDEV_READ) {
            kq_update_events(fd, EVFILT_READ, cb);
            SetCallback(fde->read, cb, data);
      }
      if (flags & FDEV_WRITE) {
            kq_update_events(fd, EVFILT_WRITE, cb);
            SetCallback(fde->write, cb, data);
      }
      if (timeout) {
            fde->timeout_time = timeofday + (timeout / 1000);
      }
}

void engine_do_netio(time_t delay)
{
      int cnt, i, fd;
      static struct kevent ke[KEVENT_LENGTH];
      struct timespec ts;
      fd_entry *fde;
      FDCB *cb;
      void *data;

      ts.tv_sec = delay / 1000; /* This is seconds */
      ts.tv_nsec = (delay % 1000) * 1000000; /* This is nanoseconds */

      for (;;) {
            cnt = kevent(kq.id, kq.list, kq.offset, ke, KEVENT_LENGTH, &ts);
            kq.offset = 0;

            if (cnt >= 0) {
                  break;
            }
            if (engine_ignore_errno(errno)) {
                  continue;
            }

            set_time();
            return;
      }

      set_time();

      if (!cnt) {
            return;
      }

      for (i = 0; i < cnt; i++) {
            fd = ke[i].ident;
            fde = &fd_table[fd];

            if (ke[i].flags & EV_ERROR) {
                  errno = ke[i].data;
                  continue;
            }

            switch (ke[i].filter) {
                  case EVFILT_READ:
                        GetCallback(fde->read, cb, data);
                        ClrCallback(fde->read);

                        if (cb != NULL) {
                              cb(fd, data, ENGINE_OK);
                        }
                        break;
                  case EVFILT_WRITE:
                        GetCallback(fde->write, cb, data);
                        ClrCallback(fde->write);

                        if (cb != NULL) {
                              cb(fd, data, ENGINE_OK);
                        }
                        break;
                  default:
                        break;
            }
      }
}

#endif

Generated by  Doxygen 1.6.0   Back to index