]>
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 26092 2008-09-19 15:13:52Z 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>
37 /* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
40 #define EV_SET(kevp, a, b, c, d, e, f) do { \
41 (kevp)->ident = (a); \
42 (kevp)->filter = (b); \
43 (kevp)->flags = (c); \
44 (kevp)->fflags = (d); \
46 (kevp)->udata = (f); \
51 #define KQUEUE_SCHED_EVENT
55 static void kq_update_events(rb_fde_t
*, short, PF
*);
57 static struct timespec zero_timespec
;
59 static struct kevent
*kqlst
; /* kevent buffer */
60 static struct kevent
*kqout
; /* kevent output buffer */
61 static int kqmax
; /* max structs to buffer */
62 static int kqoff
; /* offset into the buffer */
66 rb_setup_fd_kqueue(rb_fde_t
*F
)
72 kq_update_events(rb_fde_t
*F
, short filter
, PF
* handler
)
80 cur_handler
= F
->read_handler
;
83 cur_handler
= F
->write_handler
;
86 /* XXX bad! -- adrian */
91 if((cur_handler
== NULL
&& handler
!= NULL
) || (cur_handler
!= NULL
&& handler
== NULL
))
99 kep_flags
= EV_ADD
| EV_ONESHOT
;
103 kep_flags
= EV_DELETE
;
106 EV_SET(kep
, (uintptr_t)F
->fd
, filter
, kep_flags
, 0, 0, (void *)F
);
112 /* Add them one at a time, because there may be
113 * already closed fds in it. The kernel will try
114 * to report invalid fds in the output; if there
115 * is no space, it silently stops processing the
116 * array at that point. We cannot give output space
117 * because that would also return events we cannot
118 * process at this point.
120 for(i
= 0; i
< kqoff
; i
++)
122 ret
= kevent(kq
, kqlst
+ i
, 1, NULL
, 0, &zero_timespec
);
123 /* jdc -- someone needs to do error checking... */
124 /* EBADF is normal here -- jilles */
125 if(ret
== -1 && errno
!= EBADF
)
126 rb_lib_log("kq_update_events(): kevent(): %s",
136 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
137 /* Public functions */
143 * This is a needed exported function which will be called to initialise
144 * the network loop code.
147 rb_init_netio_kqueue(void)
154 kqmax
= getdtablesize();
155 kqlst
= rb_malloc(sizeof(struct kevent
) * kqmax
);
156 kqout
= rb_malloc(sizeof(struct kevent
) * kqmax
);
157 rb_open(kq
, RB_FD_UNKNOWN
, "kqueue fd");
158 zero_timespec
.tv_sec
= 0;
159 zero_timespec
.tv_nsec
= 0;
167 * This is a needed exported function which will be called to register
168 * and deregister interest in a pending IO state for a given FD.
171 rb_setselect_kqueue(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
173 lrb_assert(IsFDOpen(F
));
175 if(type
& RB_SELECT_READ
)
177 kq_update_events(F
, EVFILT_READ
, handler
);
178 F
->read_handler
= handler
;
179 F
->read_data
= client_data
;
181 if(type
& RB_SELECT_WRITE
)
183 kq_update_events(F
, EVFILT_WRITE
, handler
);
184 F
->write_handler
= handler
;
185 F
->write_data
= client_data
;
190 * Check all connections for new connections and input data that is to be
191 * processed. Also check for connections with data queued and whether we can
198 * Called to do the new-style IO, courtesy of squid (like most of this
199 * new IO code). This routine handles the stuff we've hidden in
200 * rb_setselect and fd_table[] and calls callbacks for IO ready
205 rb_select_kqueue(long delay
)
208 struct timespec poll_time
;
220 poll_time
.tv_sec
= delay
/ 1000;
221 poll_time
.tv_nsec
= (delay
% 1000) * 1000000;
226 num
= kevent(kq
, kqlst
, kqoff
, kqout
, kqmax
, pt
);
232 if(rb_ignore_errno(errno
))
245 return RB_OK
; /* No error.. */
247 for(i
= 0; i
< num
; i
++)
251 if(kqout
[i
].flags
& EV_ERROR
)
253 errno
= kqout
[i
].data
;
254 /* XXX error == bad! -- adrian */
258 switch (kqout
[i
].filter
)
263 if((hdl
= F
->read_handler
) != NULL
)
265 F
->read_handler
= NULL
;
266 hdl(F
, F
->read_data
);
273 if((hdl
= F
->write_handler
) != NULL
)
275 F
->write_handler
= NULL
;
276 hdl(F
, F
->write_data
);
279 #if defined(EVFILT_TIMER)
281 rb_run_event(kqout
[i
].udata
);
292 #if defined(KQUEUE_SCHED_EVENT)
293 static int can_do_event
= 0;
295 rb_kqueue_supports_event(void)
301 if(can_do_event
== 1)
303 if(can_do_event
== -1)
311 EV_SET(&kv
, (uintptr_t)0x0, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, 0, 1, 0);
312 if(kevent(xkq
, &kv
, 1, NULL
, 0, NULL
) < 0)
324 rb_kqueue_sched_event(struct ev_entry
*event
, int when
)
330 if(event
->frequency
== 0)
331 kep_flags
|= EV_ONESHOT
;
332 EV_SET(&kev
, (uintptr_t)event
, EVFILT_TIMER
, kep_flags
, 0, when
* 1000, event
);
333 if(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) < 0)
339 rb_kqueue_unsched_event(struct ev_entry
*event
)
342 EV_SET(&kev
, (uintptr_t)event
, EVFILT_TIMER
, EV_DELETE
, 0, 0, event
);
343 kevent(kq
, &kev
, 1, NULL
, 0, NULL
);
347 rb_kqueue_init_event(void)
351 #endif /* KQUEUE_SCHED_EVENT */
353 #else /* kqueue not supported */
355 rb_init_netio_kqueue(void)
362 rb_setselect_kqueue(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
369 rb_select_kqueue(long delay
)
376 rb_setup_fd_kqueue(rb_fde_t
*F
)
384 #if !defined(HAVE_KEVENT) || !defined(KQUEUE_SCHED_EVENT)
386 rb_kqueue_init_event(void)
392 rb_kqueue_sched_event(struct ev_entry
*event
, int when
)
399 rb_kqueue_unsched_event(struct ev_entry
*event
)
405 rb_kqueue_supports_event(void)
410 #endif /* !HAVE_KEVENT || !KQUEUE_SCHED_EVENT */