Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/VibeDevelopers/Comet.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410/* * ircd-ratbox: A slightly useful ircd. * kqueue.c: FreeBSD kqueue compatible network routines. * * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center * Copyright (C) 1996-2002 Hybrid Development Team * Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au> * Copyright (C) 2002-2005 ircd-ratbox development team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */
#include <librb_config.h>#include <rb_lib.h>#include <commio-int.h>#include <event-int.h>
#if defined(HAVE_SYS_EVENT_H) && (HAVE_KEVENT)
#include <sys/event.h>
/* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
#ifndef EV_SET#define EV_SET(kevp, a, b, c, d, e, f) do { \ (kevp)->ident = (a); \ (kevp)->filter = (b); \ (kevp)->flags = (c); \ (kevp)->fflags = (d); \ (kevp)->data = (e); \ (kevp)->udata = (f); \} while(0)#endif
#ifdef EVFILT_TIMER#define KQUEUE_SCHED_EVENT#endif
static void kq_update_events(rb_fde_t *, short, PF *);static int kq;static struct timespec zero_timespec;
static struct kevent *kqlst; /* kevent buffer */static struct kevent *kqout; /* kevent output buffer */static int kqmax; /* max structs to buffer */static int kqoff; /* offset into the buffer */
intrb_setup_fd_kqueue(rb_fde_t *F){ return 0;}
static voidkq_update_events(rb_fde_t *F, short filter, PF * handler){ PF *cur_handler; int kep_flags;
switch (filter) { case EVFILT_READ: cur_handler = F->read_handler; break; case EVFILT_WRITE: cur_handler = F->write_handler; break; default: /* XXX bad! -- adrian */ return; break; }
if((cur_handler == NULL && handler != NULL) || (cur_handler != NULL && handler == NULL)) { struct kevent *kep;
kep = kqlst + kqoff;
if(handler != NULL) { kep_flags = EV_ADD | EV_ONESHOT; } else { kep_flags = EV_DELETE; }
EV_SET(kep, F->fd, filter, kep_flags, 0, 0, F);
if(++kqoff == kqmax) { int ret, i;
/* Add them one at a time, because there may be * already closed fds in it. The kernel will try * to report invalid fds in the output; if there * is no space, it silently stops processing the * array at that point. We cannot give output space * because that would also return events we cannot * process at this point. */ for(i = 0; i < kqoff; i++) { ret = kevent(kq, kqlst + i, 1, NULL, 0, &zero_timespec); /* jdc -- someone needs to do error checking... */ /* EBADF is normal here -- jilles */ if(ret == -1 && errno != EBADF) rb_lib_log("kq_update_events(): kevent(): %s", strerror(errno)); } kqoff = 0; } }}
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX *//* Public functions */
/* * rb_init_netio * * This is a needed exported function which will be called to initialise * the network loop code. */intrb_init_netio_kqueue(void){ kq = kqueue(); if(kq < 0) { return errno; } kqmax = getdtablesize(); kqlst = rb_malloc(sizeof(struct kevent) * kqmax); kqout = rb_malloc(sizeof(struct kevent) * kqmax); rb_open(kq, RB_FD_UNKNOWN, "kqueue fd"); zero_timespec.tv_sec = 0; zero_timespec.tv_nsec = 0;
return 0;}
/* * rb_setselect * * This is a needed exported function which will be called to register * and deregister interest in a pending IO state for a given FD. */voidrb_setselect_kqueue(rb_fde_t *F, unsigned int type, PF * handler, void *client_data){ lrb_assert(IsFDOpen(F));
if(type & RB_SELECT_READ) { kq_update_events(F, EVFILT_READ, handler); F->read_handler = handler; F->read_data = client_data; } if(type & RB_SELECT_WRITE) { kq_update_events(F, EVFILT_WRITE, handler); F->write_handler = handler; F->write_data = client_data; }}
/* * Check all connections for new connections and input data that is to be * processed. Also check for connections with data queued and whether we can * write it out. */
/* * rb_select * * Called to do the new-style IO, courtesy of squid (like most of this * new IO code). This routine handles the stuff we've hidden in * rb_setselect and fd_table[] and calls callbacks for IO ready * events. */
intrb_select_kqueue(long delay){ int num, i; struct timespec poll_time; struct timespec *pt; rb_fde_t *F;
if(delay < 0) { pt = NULL; } else { pt = &poll_time; poll_time.tv_sec = delay / 1000; poll_time.tv_nsec = (delay % 1000) * 1000000; }
for(;;) { num = kevent(kq, kqlst, kqoff, kqout, kqmax, pt); kqoff = 0;
if(num >= 0) break;
if(rb_ignore_errno(errno)) break;
rb_set_time();
return RB_ERROR;
/* NOTREACHED */ }
rb_set_time();
if(num == 0) return RB_OK; /* No error.. */
for(i = 0; i < num; i++) { PF *hdl = NULL;
if(kqout[i].flags & EV_ERROR) { errno = kqout[i].data; /* XXX error == bad! -- adrian */ continue; /* XXX! */ }
switch (kqout[i].filter) {
case EVFILT_READ: F = kqout[i].udata; if((hdl = F->read_handler) != NULL) { F->read_handler = NULL; hdl(F, F->read_data); }
break;
case EVFILT_WRITE: F = kqout[i].udata; if((hdl = F->write_handler) != NULL) { F->write_handler = NULL; hdl(F, F->write_data); } break;#if defined(EVFILT_TIMER) case EVFILT_TIMER: rb_run_one_event(kqout[i].udata); break;#endif default: /* Bad! -- adrian */ break; } } return RB_OK;}
#if defined(KQUEUE_SCHED_EVENT)static int can_do_event = 0;intrb_kqueue_supports_event(void){ struct kevent kv; struct timespec ts; int xkq;
if(can_do_event == 1) return 1; if(can_do_event == -1) return 0;
xkq = kqueue(); ts.tv_sec = 0; ts.tv_nsec = 1000;
EV_SET(&kv, (uintptr_t)0x0, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 1, 0); if(kevent(xkq, &kv, 1, NULL, 0, NULL) < 0) { can_do_event = -1; close(xkq); return 0; } close(xkq); can_do_event = 1; return 1;}
intrb_kqueue_sched_event(struct ev_entry *event, int when){ struct kevent kev; int kep_flags;
kep_flags = EV_ADD; if(event->frequency == 0) kep_flags |= EV_ONESHOT; EV_SET(&kev, (uintptr_t)event, EVFILT_TIMER, kep_flags, 0, when * 1000, event); if(kevent(kq, &kev, 1, NULL, 0, NULL) < 0) return 0; return 1;}
voidrb_kqueue_unsched_event(struct ev_entry *event){ struct kevent kev; EV_SET(&kev, (uintptr_t)event, EVFILT_TIMER, EV_DELETE, 0, 0, event); kevent(kq, &kev, 1, NULL, 0, NULL);}
voidrb_kqueue_init_event(void){ return;}#endif /* KQUEUE_SCHED_EVENT */
#else /* kqueue not supported */intrb_init_netio_kqueue(void){ errno = ENOSYS; return -1;}
voidrb_setselect_kqueue(rb_fde_t *F __attribute__((unused)), unsigned int type __attribute__((unused)), PF * handler __attribute__((unused)), void *client_data __attribute__((unused))){ errno = ENOSYS; return;}
intrb_select_kqueue(long delay __attribute__((unused))){ errno = ENOSYS; return -1;}
intrb_setup_fd_kqueue(rb_fde_t *F __attribute__((unused))){ errno = ENOSYS; return -1;}
#endif
#if !defined(HAVE_KEVENT) || !defined(KQUEUE_SCHED_EVENT)voidrb_kqueue_init_event(void){ return;}
intrb_kqueue_sched_event(struct ev_entry *event __attribute__((unused)), int when __attribute__((unused))){ errno = ENOSYS; return -1;}
voidrb_kqueue_unsched_event(struct ev_entry *event __attribute__((unused))){ return;}
intrb_kqueue_supports_event(void){ errno = ENOSYS; return 0;}#endif /* !HAVE_KEVENT || !KQUEUE_SCHED_EVENT */