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

engine_epoll.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_epoll.c,v 1.9.2.2 2005/07/08 20:13:27 amcwilliam Exp $
 */

#include "setup.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "fd.h"

#ifdef USE_EPOLL

#include <sys/epoll.h>

static int ep = -1;
static struct epoll_event epoll_fds[MAXCONNECTIONS];

#ifdef HAVE_EPOLL_SYSCALL /* We need to kludge the system call */

#include <sys/syscall.h>

_syscall1(int, epoll_create, int, maxfds);
_syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, events);
_syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents, int, maxevents, int, timeout);

#endif /* HAVE_EPOLL_SYSCALL */

void engine_init()
{
      if ((ep = epoll_create(MAXCONNECTIONS)) == -1) {
            ircdlog(LOG_ERROR, "FATAL: engine_init() couldn't create epoll socket: %s", strerror(errno));
            abort();
      }

      memset(epoll_fds, 0, sizeof(epoll_fds));
}

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

      if (flags & FDEV_READ) {
            if (cb != NULL) {
                  fde->epoll_state |= EPOLLIN;
            }
            else {
                  fde->epoll_state &= ~EPOLLIN;
            }
            SetCallback(fde->read, cb, data);
      }
      if (flags & FDEV_WRITE) {
            if (cb != NULL) {
                  fde->epoll_state |= EPOLLOUT;
            }
            else {
                  fde->epoll_state &= ~EPOLLOUT;
            }
            SetCallback(fde->write, cb, data);
      }
      if (timeout) {
            fde->timeout_time = timeofday + (timeout / 1000);
      }

      if (!old_state && !fde->epoll_state) {
            return;
      }

      if (!fde->epoll_state) {
            op = EPOLL_CTL_DEL;
      }
      else if (!old_state && fde->epoll_state) {
            op = EPOLL_CTL_ADD;
      }
      else if (old_state != fde->epoll_state) {
            op = EPOLL_CTL_MOD;
      }

      if (op != -1) {
            struct epoll_event ev;

            ev.events = fde->epoll_state;
            ev.data.ptr = fde;

            if (epoll_ctl(ep, op, fd, &ev) == -1) {
                  ircdlog(LOG_ERROR, "FATAL: engine_set_call() aborted: epoll_ctl() failure: %s", strerror(errno));
                  abort();
            }
      }
}

void engine_do_netio(time_t delay)
{
      int cnt, i, fd;
      fd_entry *fde;
      unsigned int old_state, new_state;
      FDCB *cb;
      void *data;

      cnt = epoll_wait(ep, epoll_fds, MAXCONNECTIONS, delay);

      set_time();

      if (!cnt || (cnt == -1 && !engine_ignore_errno(errno))) {
            return;
      }

      for (i = 0; i < cnt; i++) {
            fde = (fd_entry *)epoll_fds[i].data.ptr;
            old_state = fde->epoll_state;
            fd = fde->fd;

            if (epoll_fds[i].events & (EPOLLIN|EPOLLHUP|EPOLLERR)) {
                  GetCallback(fde->read, cb, data);
                  ClrCallback(fde->read);

                  if (cb != NULL) {
                        cb(fd, data, ENGINE_OK);
                  }
            }
            if (!fde->open) {
                  continue;
            }

            if (epoll_fds[i].events & (EPOLLOUT|EPOLLHUP|EPOLLERR)) {
                  GetCallback(fde->write, cb, data);
                  ClrCallback(fde->write);

                  if (cb != NULL) {
                        cb(fd, data, ENGINE_OK);
                  }
            }
            if (!fde->open) {
                  continue;
            }

            new_state = 0;
            if (TheCallback(fde->read) != NULL) {
                  new_state |= EPOLLIN;
            }
            if (TheCallback(fde->write) != NULL) {
                  new_state |= EPOLLOUT;
            }

            if (new_state != old_state) {
                  struct epoll_event ev;

                  ev.events = fde->epoll_state = new_state;
                  ev.data.ptr = fde;

                  if (epoll_ctl(ep, (!new_state) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD, fd, &ev) == -1) {
                        ircdlog(LOG_ERROR, "engine_do_netio() error: epoll_ctl() failure: %s",
                              strerror(errno));
                  }
            }
      }
}

#endif

Generated by  Doxygen 1.6.0   Back to index