]>
jfr.im git - solanum.git/blob - libratbox/src/kqueue.c
2 * ircd-ratbox: A slightly useful ircd.
3 * kqueue.c: FreeBSD kqueue compatible network routines.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2001 Adrian Chadd <adrian@creative.net.au>
8 * Copyright (C) 2002-2005 ircd-ratbox development team
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
25 * $Id: kqueue.c 25038 2008-01-23 16:03:08Z androsyn $
28 #include <libratbox_config.h>
29 #include <ratbox_lib.h>
30 #include <commio-int.h>
31 #include <event-int.h>
33 #if defined(HAVE_SYS_EVENT_H) && (HAVE_KEVENT)
35 #include <sys/event.h>
39 /* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
42 #define EV_SET(kevp, a, b, c, d, e, f) do { \
43 (kevp)->ident = (a); \
44 (kevp)->filter = (b); \
45 (kevp)->flags = (c); \
46 (kevp)->fflags = (d); \
48 (kevp)->udata = (f); \
53 #define KQUEUE_SCHED_EVENT
57 static void kq_update_events(rb_fde_t
*, short, PF
*);
59 static struct timespec zero_timespec
;
61 static struct kevent
*kqlst
; /* kevent buffer */
62 static int kqmax
; /* max structs to buffer */
63 static int kqoff
; /* offset into the buffer */
67 rb_setup_fd_kqueue(rb_fde_t
* F
)
73 kq_update_events(rb_fde_t
* F
, short filter
, PF
* handler
)
81 cur_handler
= F
->read_handler
;
84 cur_handler
= F
->write_handler
;
87 /* XXX bad! -- adrian */
92 if((cur_handler
== NULL
&& handler
!= NULL
) || (cur_handler
!= NULL
&& handler
== NULL
))
100 kep_flags
= EV_ADD
| EV_ONESHOT
;
104 kep_flags
= EV_DELETE
;
107 EV_SET(kep
, (uintptr_t) F
->fd
, filter
, kep_flags
, 0, 0, (void *) F
);
113 ret
= kevent(kq
, kqlst
, kqoff
, NULL
, 0, &zero_timespec
);
114 /* jdc -- someone needs to do error checking... */
117 rb_lib_log("kq_update_events(): kevent(): %s", strerror(errno
));
127 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
128 /* Public functions */
134 * This is a needed exported function which will be called to initialise
135 * the network loop code.
138 rb_init_netio_kqueue(void)
145 kqmax
= getdtablesize();
146 kqlst
= rb_malloc(sizeof(struct kevent
) * kqmax
);
147 rb_open(kq
, RB_FD_UNKNOWN
, "kqueue fd");
148 zero_timespec
.tv_sec
= 0;
149 zero_timespec
.tv_nsec
= 0;
157 * This is a needed exported function which will be called to register
158 * and deregister interest in a pending IO state for a given FD.
161 rb_setselect_kqueue(rb_fde_t
* F
, unsigned int type
, PF
* handler
, void *client_data
)
163 lrb_assert(IsFDOpen(F
));
165 if(type
& RB_SELECT_READ
)
167 kq_update_events(F
, EVFILT_READ
, handler
);
168 F
->read_handler
= handler
;
169 F
->read_data
= client_data
;
171 if(type
& RB_SELECT_WRITE
)
173 kq_update_events(F
, EVFILT_WRITE
, handler
);
174 F
->write_handler
= handler
;
175 F
->write_data
= client_data
;
180 * Check all connections for new connections and input data that is to be
181 * processed. Also check for connections with data queued and whether we can
188 * Called to do the new-style IO, courtesy of squid (like most of this
189 * new IO code). This routine handles the stuff we've hidden in
190 * rb_setselect and fd_table[] and calls callbacks for IO ready
195 rb_select_kqueue(long delay
)
198 static struct kevent ke
[KE_LENGTH
];
199 struct timespec poll_time
;
209 poll_time
.tv_sec
= delay
/ 1000;
210 poll_time
.tv_nsec
= (delay
% 1000) * 1000000;
215 num
= kevent(kq
, kqlst
, kqoff
, ke
, KE_LENGTH
, pt
);
221 if(rb_ignore_errno(errno
))
234 return RB_OK
; /* No error.. */
236 for (i
= 0; i
< num
; i
++)
240 if(ke
[i
].flags
& EV_ERROR
)
243 /* XXX error == bad! -- adrian */
247 switch (ke
[i
].filter
)
252 if((hdl
= F
->read_handler
) != NULL
)
254 F
->read_handler
= NULL
;
255 hdl(F
, F
->read_data
);
262 if((hdl
= F
->write_handler
) != NULL
)
264 F
->write_handler
= NULL
;
265 hdl(F
, F
->write_data
);
268 #if defined(EVFILT_TIMER)
270 rb_run_event(ke
[i
].udata
);
280 static int can_do_event
= 0;
282 rb_kqueue_supports_event(void)
288 if(can_do_event
== 1)
290 if(can_do_event
== -1)
298 EV_SET(&kv
, (uintptr_t) 0x0, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, 0, 1, 0);
299 if(kevent(xkq
, &kv
, 1, NULL
, 0, NULL
) < 0)
311 rb_kqueue_sched_event(struct ev_entry
*event
, int when
)
317 if(event
->frequency
== 0)
318 kep_flags
|= EV_ONESHOT
;
319 EV_SET(&kev
, (uintptr_t) event
, EVFILT_TIMER
, kep_flags
, 0, when
* 1000, event
);
320 if(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) < 0)
326 rb_kqueue_unsched_event(struct ev_entry
*event
)
329 EV_SET(&kev
, (uintptr_t) event
, EVFILT_TIMER
, EV_DELETE
, 0, 0, event
);
330 kevent(kq
, &kev
, 1, NULL
, 0, NULL
);
334 rb_kqueue_init_event(void)
339 #else /* kqueue not supported */
341 rb_init_netio_kqueue(void)
348 rb_setselect_kqueue(rb_fde_t
* F
, unsigned int type
, PF
* handler
, void *client_data
)
355 rb_select_kqueue(long delay
)
362 rb_setup_fd_kqueue(rb_fde_t
* F
)
370 #if !defined(HAVE_KEVENT) || !defined(KQUEUE_SCHED_EVENT)
372 rb_kqueue_init_event(void)
378 rb_kqueue_sched_event(struct ev_entry
*event
, int when
)
385 rb_kqueue_unsched_event(struct ev_entry
*event
)
391 rb_kqueue_supports_event(void)
396 #endif /* !HAVE_KEVENT || !KQUEUE_SCHED_EVENT */