]>
jfr.im git - solanum.git/blob - librb/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
27 #include <librb_config.h>
29 #include <commio-int.h>
30 #include <event-int.h>
32 #if defined(HAVE_SYS_EVENT_H) && (HAVE_KEVENT)
34 #include <sys/event.h>
36 /* jlemon goofed up and didn't add EV_SET until fbsd 4.3 */
39 #define EV_SET(kevp, a, b, c, d, e, f) do { \
40 (kevp)->ident = (a); \
41 (kevp)->filter = (b); \
42 (kevp)->flags = (c); \
43 (kevp)->fflags = (d); \
45 (kevp)->udata = (f); \
50 #define KQUEUE_SCHED_EVENT
54 static void kq_update_events(rb_fde_t
*, short, PF
*);
56 static struct timespec zero_timespec
;
58 static struct kevent
*kqlst
; /* kevent buffer */
59 static struct kevent
*kqout
; /* kevent output buffer */
60 static int kqmax
; /* max structs to buffer */
61 static int kqoff
; /* offset into the buffer */
65 rb_setup_fd_kqueue(rb_fde_t
*F
)
71 kq_update_events(rb_fde_t
*F
, short filter
, PF
* handler
)
79 cur_handler
= F
->read_handler
;
82 cur_handler
= F
->write_handler
;
85 /* XXX bad! -- adrian */
90 if((cur_handler
== NULL
&& handler
!= NULL
) || (cur_handler
!= NULL
&& handler
== NULL
))
98 kep_flags
= EV_ADD
| EV_ONESHOT
;
102 kep_flags
= EV_DELETE
;
105 EV_SET(kep
, F
->fd
, filter
, kep_flags
, 0, 0, F
);
111 /* Add them one at a time, because there may be
112 * already closed fds in it. The kernel will try
113 * to report invalid fds in the output; if there
114 * is no space, it silently stops processing the
115 * array at that point. We cannot give output space
116 * because that would also return events we cannot
117 * process at this point.
119 for(i
= 0; i
< kqoff
; i
++)
121 ret
= kevent(kq
, kqlst
+ i
, 1, NULL
, 0, &zero_timespec
);
122 /* jdc -- someone needs to do error checking... */
123 /* EBADF is normal here -- jilles */
124 if(ret
== -1 && errno
!= EBADF
)
125 rb_lib_log("kq_update_events(): kevent(): %s",
135 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
136 /* Public functions */
142 * This is a needed exported function which will be called to initialise
143 * the network loop code.
146 rb_init_netio_kqueue(void)
153 kqmax
= getdtablesize();
154 kqlst
= rb_malloc(sizeof(struct kevent
) * kqmax
);
155 kqout
= rb_malloc(sizeof(struct kevent
) * kqmax
);
156 rb_open(kq
, RB_FD_UNKNOWN
, "kqueue fd");
157 zero_timespec
.tv_sec
= 0;
158 zero_timespec
.tv_nsec
= 0;
166 * This is a needed exported function which will be called to register
167 * and deregister interest in a pending IO state for a given FD.
170 rb_setselect_kqueue(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
172 lrb_assert(IsFDOpen(F
));
174 if(type
& RB_SELECT_READ
)
176 kq_update_events(F
, EVFILT_READ
, handler
);
177 F
->read_handler
= handler
;
178 F
->read_data
= client_data
;
180 if(type
& RB_SELECT_WRITE
)
182 kq_update_events(F
, EVFILT_WRITE
, handler
);
183 F
->write_handler
= handler
;
184 F
->write_data
= client_data
;
189 * Check all connections for new connections and input data that is to be
190 * processed. Also check for connections with data queued and whether we can
197 * Called to do the new-style IO, courtesy of squid (like most of this
198 * new IO code). This routine handles the stuff we've hidden in
199 * rb_setselect and fd_table[] and calls callbacks for IO ready
204 rb_select_kqueue(long delay
)
207 struct timespec poll_time
;
219 poll_time
.tv_sec
= delay
/ 1000;
220 poll_time
.tv_nsec
= (delay
% 1000) * 1000000;
225 num
= kevent(kq
, kqlst
, kqoff
, kqout
, kqmax
, pt
);
231 if(rb_ignore_errno(errno
))
244 return RB_OK
; /* No error.. */
246 for(i
= 0; i
< num
; i
++)
250 if(kqout
[i
].flags
& EV_ERROR
)
252 errno
= kqout
[i
].data
;
253 /* XXX error == bad! -- adrian */
257 switch (kqout
[i
].filter
)
262 if((hdl
= F
->read_handler
) != NULL
)
264 F
->read_handler
= NULL
;
265 hdl(F
, F
->read_data
);
272 if((hdl
= F
->write_handler
) != NULL
)
274 F
->write_handler
= NULL
;
275 hdl(F
, F
->write_data
);
278 #if defined(EVFILT_TIMER)
280 rb_run_one_event(kqout
[i
].udata
);
291 #if defined(KQUEUE_SCHED_EVENT)
292 static int can_do_event
= 0;
294 rb_kqueue_supports_event(void)
300 if(can_do_event
== 1)
302 if(can_do_event
== -1)
310 EV_SET(&kv
, (uintptr_t)0x0, EVFILT_TIMER
, EV_ADD
| EV_ONESHOT
, 0, 1, 0);
311 if(kevent(xkq
, &kv
, 1, NULL
, 0, NULL
) < 0)
323 rb_kqueue_sched_event(struct ev_entry
*event
, int when
)
329 if(event
->frequency
== 0)
330 kep_flags
|= EV_ONESHOT
;
331 EV_SET(&kev
, (uintptr_t)event
, EVFILT_TIMER
, kep_flags
, 0, when
* 1000, event
);
332 if(kevent(kq
, &kev
, 1, NULL
, 0, NULL
) < 0)
338 rb_kqueue_unsched_event(struct ev_entry
*event
)
341 EV_SET(&kev
, (uintptr_t)event
, EVFILT_TIMER
, EV_DELETE
, 0, 0, event
);
342 kevent(kq
, &kev
, 1, NULL
, 0, NULL
);
346 rb_kqueue_init_event(void)
350 #endif /* KQUEUE_SCHED_EVENT */
352 #else /* kqueue not supported */
354 rb_init_netio_kqueue(void)
361 rb_setselect_kqueue(rb_fde_t
*F
__attribute__((unused
)), unsigned int type
__attribute__((unused
)), PF
* handler
__attribute__((unused
)), void *client_data
__attribute__((unused
)))
368 rb_select_kqueue(long delay
__attribute__((unused
)))
375 rb_setup_fd_kqueue(rb_fde_t
*F
__attribute__((unused
)))
383 #if !defined(HAVE_KEVENT) || !defined(KQUEUE_SCHED_EVENT)
385 rb_kqueue_init_event(void)
391 rb_kqueue_sched_event(struct ev_entry
*event
__attribute__((unused
)), int when
__attribute__((unused
)))
398 rb_kqueue_unsched_event(struct ev_entry
*event
__attribute__((unused
)))
404 rb_kqueue_supports_event(void)
409 #endif /* !HAVE_KEVENT || !KQUEUE_SCHED_EVENT */