2 * ircd-ratbox: A slightly useful ircd.
3 * sigio.c: Linux Realtime SIGIO 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 Aaron Sethman <androsyn@ratbox.org>
9 * Copyright (C) 2002 ircd-ratbox development team
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
29 #define _GNU_SOURCE 1 /* Needed for F_SETSIG */
32 #include <librb_config.h>
34 #include <commio-int.h>
35 #include <event-int.h>
36 #include <fcntl.h> /* Yes this needs to be before the ifdef */
38 #if defined(HAVE_SYS_POLL_H) && defined(F_SETSIG)
47 #ifdef USE_TIMER_CREATE
48 #define SIGIO_SCHED_EVENT 1
51 #define RTSIGIO SIGRTMIN
52 #define RTSIGTIM (SIGRTMIN+1)
57 struct pollfd
*pollfds
;
58 int maxindex
; /* highest FD number */
62 typedef struct _pollfd_list pollfd_list_t
;
64 pollfd_list_t pollfd_list
;
65 static int can_do_event
= 0;
66 static int sigio_is_screwed
= 0; /* We overflowed our sigio queue */
67 static sigset_t our_sigset
;
73 * This is a needed exported function which will be called to initialise
74 * the network loop code.
77 rb_init_netio_sigio(void)
80 pollfd_list
.pollfds
= rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd
)));
81 pollfd_list
.allocated
= rb_getmaxconnect();
82 for(fd
= 0; fd
< rb_getmaxconnect(); fd
++)
84 pollfd_list
.pollfds
[fd
].fd
= -1;
87 pollfd_list
.maxindex
= 0;
89 sigio_is_screwed
= 1; /* Start off with poll first.. */
91 sigemptyset(&our_sigset
);
92 sigaddset(&our_sigset
, RTSIGIO
);
93 sigaddset(&our_sigset
, SIGIO
);
94 #ifdef SIGIO_SCHED_EVENT
95 sigaddset(&our_sigset
, RTSIGTIM
);
97 sigprocmask(SIG_BLOCK
, &our_sigset
, NULL
);
102 resize_pollarray(int fd
)
104 if(rb_unlikely(fd
>= pollfd_list
.allocated
))
106 int x
, old_value
= pollfd_list
.allocated
;
107 pollfd_list
.allocated
+= 1024;
108 pollfd_list
.pollfds
=
109 rb_realloc(pollfd_list
.pollfds
,
110 pollfd_list
.allocated
* (sizeof(struct pollfd
)));
111 memset(&pollfd_list
.pollfds
[old_value
+ 1], 0, sizeof(struct pollfd
) * 1024);
112 for(x
= old_value
+ 1; x
< pollfd_list
.allocated
; x
++)
114 pollfd_list
.pollfds
[x
].fd
= -1;
121 * void setup_sigio_fd(int fd)
123 * Input: File descriptor
125 * Side Effect: Sets the FD up for SIGIO
129 rb_setup_fd_sigio(rb_fde_t
*F
)
133 flags
= fcntl(fd
, F_GETFL
, 0);
136 /* if set async, clear it so we can reset it in the kernel :/ */
140 fcntl(fd
, F_SETFL
, flags
);
143 flags
|= O_ASYNC
| O_NONBLOCK
;
145 if(fcntl(fd
, F_SETFL
, flags
) == -1)
148 if(fcntl(fd
, F_SETSIG
, RTSIGIO
) == -1)
150 if(fcntl(fd
, F_SETOWN
, getpid()) == -1)
159 * This is a needed exported function which will be called to register
160 * and deregister interest in a pending IO state for a given FD.
163 rb_setselect_sigio(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
168 if(type
& RB_SELECT_READ
)
170 F
->read_handler
= handler
;
171 F
->read_data
= client_data
;
173 F
->pflags
|= POLLRDNORM
;
175 F
->pflags
&= ~POLLRDNORM
;
177 if(type
& RB_SELECT_WRITE
)
179 F
->write_handler
= handler
;
180 F
->write_data
= client_data
;
182 F
->pflags
|= POLLWRNORM
;
184 F
->pflags
&= ~POLLWRNORM
;
187 resize_pollarray(F
->fd
);
191 pollfd_list
.pollfds
[F
->fd
].events
= 0;
192 pollfd_list
.pollfds
[F
->fd
].fd
= -1;
193 if(F
->fd
== pollfd_list
.maxindex
)
195 while(pollfd_list
.maxindex
>= 0
196 && pollfd_list
.pollfds
[pollfd_list
.maxindex
].fd
== -1)
197 pollfd_list
.maxindex
--;
202 pollfd_list
.pollfds
[F
->fd
].events
= F
->pflags
;
203 pollfd_list
.pollfds
[F
->fd
].fd
= F
->fd
;
204 if(F
->fd
> pollfd_list
.maxindex
)
205 pollfd_list
.maxindex
= F
->fd
;
212 /* int rb_select(long delay)
213 * Input: The maximum time to delay.
214 * Output: Returns -1 on error, 0 on success.
215 * Side-effects: Deregisters future interest in IO and calls the handlers
216 * if an event occurs for an FD.
217 * Comments: Check all connections for new connections and input data
218 * that is to be processed. Also check for connections with data queued
219 * and whether we can write it out.
220 * Called to do the new-style IO, courtesy of squid (like most of this
221 * new IO code). This routine handles the stuff we've hidden in
222 * rb_setselect and fd_table[] and calls callbacks for IO ready
226 rb_select_sigio(long delay
)
238 struct timespec timeout
;
239 if(rb_sigio_supports_event() || delay
>= 0)
241 timeout
.tv_sec
= (delay
/ 1000);
242 timeout
.tv_nsec
= (delay
% 1000) * 1000000;
247 if(!sigio_is_screwed
)
249 if(can_do_event
|| delay
< 0)
251 sig
= sigwaitinfo(&our_sigset
, &si
);
254 sig
= sigtimedwait(&our_sigset
, &si
, &timeout
);
262 ("Kernel RT Signal queue overflowed. Is ulimit -i too small(or perhaps /proc/sys/kernel/rtsig-max on old kernels)");
263 sigio_is_screwed
= 1;
266 #ifdef SIGIO_SCHED_EVENT
267 if(sig
== RTSIGTIM
&& can_do_event
)
269 struct ev_entry
*ev
= (struct ev_entry
*)si
.si_ptr
;
272 rb_run_one_event(ev
);
277 pollfd_list
.pollfds
[fd
].revents
|= si
.si_band
;
278 revents
= pollfd_list
.pollfds
[fd
].revents
;
284 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
286 hdl
= F
->read_handler
;
288 F
->read_handler
= NULL
;
294 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
296 hdl
= F
->write_handler
;
297 data
= F
->write_data
;
298 F
->write_handler
= NULL
;
299 F
->write_data
= NULL
;
312 if(!sigio_is_screwed
) /* We don't need to proceed */
318 signal(RTSIGIO
, SIG_IGN
);
319 signal(RTSIGIO
, SIG_DFL
);
320 sigio_is_screwed
= 0;
323 num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, delay
);
327 if(!rb_ignore_errno(errno
))
335 /* XXX we *could* optimise by falling out after doing num fds ... */
336 for(ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
338 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0)
339 || (pollfd_list
.pollfds
[ci
].fd
) == -1)
341 fd
= pollfd_list
.pollfds
[ci
].fd
;
345 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
347 hdl
= F
->read_handler
;
349 F
->read_handler
= NULL
;
355 if(IsFDOpen(F
) && (revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
)))
357 hdl
= F
->write_handler
;
358 data
= F
->write_data
;
359 F
->write_handler
= NULL
;
360 F
->write_data
= NULL
;
364 if(F
->read_handler
== NULL
)
365 rb_setselect_sigio(F
, RB_SELECT_READ
, NULL
, NULL
);
366 if(F
->write_handler
== NULL
)
367 rb_setselect_sigio(F
, RB_SELECT_WRITE
, NULL
, NULL
);
374 #if defined(SIGIO_SCHED_EVENT)
376 rb_sigio_init_event(void)
378 rb_sigio_supports_event();
383 rb_sigio_supports_event(void)
387 if(can_do_event
== 1)
389 if(can_do_event
== -1)
392 ev
.sigev_signo
= SIGVTALRM
;
393 ev
.sigev_notify
= SIGEV_SIGNAL
;
394 if(timer_create(CLOCK_REALTIME
, &ev
, &timer
) != 0)
405 rb_sigio_sched_event(struct ev_entry
*event
, int when
)
409 struct itimerspec ts
;
410 if(can_do_event
<= 0)
413 memset(&ev
, 0, sizeof(ev
));
414 event
->comm_ptr
= rb_malloc(sizeof(timer_t
));
415 id
= event
->comm_ptr
;
416 ev
.sigev_notify
= SIGEV_SIGNAL
;
417 ev
.sigev_signo
= RTSIGTIM
;
418 ev
.sigev_value
.sival_ptr
= event
;
420 if(timer_create(CLOCK_REALTIME
, &ev
, id
) < 0)
422 rb_lib_log("timer_create: %s\n", strerror(errno
));
425 memset(&ts
, 0, sizeof(ts
));
426 ts
.it_value
.tv_sec
= when
;
427 ts
.it_value
.tv_nsec
= 0;
428 if(event
->frequency
!= 0)
429 ts
.it_interval
= ts
.it_value
;
431 if(timer_settime(*id
, 0, &ts
, NULL
) < 0)
433 rb_lib_log("timer_settime: %s\n", strerror(errno
));
440 rb_sigio_unsched_event(struct ev_entry
*event
)
442 if(can_do_event
<= 0)
444 timer_delete(*((timer_t
*) event
->comm_ptr
));
445 rb_free(event
->comm_ptr
);
446 event
->comm_ptr
= NULL
;
448 #endif /* SIGIO_SCHED_EVENT */
453 rb_init_netio_sigio(void)
459 rb_setselect_sigio(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
466 rb_select_sigio(long delay
)
473 rb_setup_fd_sigio(rb_fde_t
*F
)
481 #if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
483 rb_sigio_init_event(void)
489 rb_sigio_sched_event(struct ev_entry
*event
__attribute__((unused
)), int when
__attribute__((unused
)))
496 rb_sigio_unsched_event(struct ev_entry
*event
__attribute__((unused
)))
502 rb_sigio_supports_event(void)
507 #endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */