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
26 * $Id: sigio.c 25375 2008-05-16 15:19:51Z androsyn $
30 #define _GNU_SOURCE 1 /* Needed for F_SETSIG */
33 #include <libratbox_config.h>
34 #include <ratbox_lib.h>
35 #include <commio-int.h>
36 #include <event-int.h>
37 #include <fcntl.h> /* Yes this needs to be before the ifdef */
39 #if defined(HAVE_SYS_POLL_H) && (HAVE_POLL) && (F_SETSIG)
49 #if defined(USE_TIMER_CREATE)
50 #define SIGIO_SCHED_EVENT 1
53 #define RTSIGIO SIGRTMIN
54 #define RTSIGTIM (SIGRTMIN+1)
59 struct pollfd
*pollfds
;
60 int maxindex
; /* highest FD number */
64 typedef struct _pollfd_list pollfd_list_t
;
66 pollfd_list_t pollfd_list
;
67 static int can_do_event
= 0;
68 static int sigio_is_screwed
= 0; /* We overflowed our sigio queue */
69 static sigset_t our_sigset
;
75 * This is a needed exported function which will be called to initialise
76 * the network loop code.
79 rb_init_netio_sigio(void)
82 pollfd_list
.pollfds
= rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd
)));
83 pollfd_list
.allocated
= rb_getmaxconnect();
84 for (fd
= 0; fd
< rb_getmaxconnect(); fd
++)
86 pollfd_list
.pollfds
[fd
].fd
= -1;
89 pollfd_list
.maxindex
= 0;
91 sigio_is_screwed
= 1; /* Start off with poll first.. */
93 sigemptyset(&our_sigset
);
94 sigaddset(&our_sigset
, RTSIGIO
);
95 sigaddset(&our_sigset
, SIGIO
);
96 #ifdef SIGIO_SCHED_EVENT
97 sigaddset(&our_sigset
, RTSIGTIM
);
99 sigprocmask(SIG_BLOCK
, &our_sigset
, NULL
);
104 resize_pollarray(int fd
)
106 if(rb_unlikely(fd
>= pollfd_list
.allocated
))
108 int x
, old_value
= pollfd_list
.allocated
;
109 pollfd_list
.allocated
+= 1024;
110 pollfd_list
.pollfds
=
111 rb_realloc(pollfd_list
.pollfds
,
112 pollfd_list
.allocated
* (sizeof(struct pollfd
)));
113 memset(&pollfd_list
.pollfds
[old_value
+ 1], 0, sizeof(struct pollfd
) * 1024);
114 for (x
= old_value
+ 1; x
< pollfd_list
.allocated
; x
++)
116 pollfd_list
.pollfds
[x
].fd
= -1;
123 * void setup_sigio_fd(int fd)
125 * Input: File descriptor
127 * Side Effect: Sets the FD up for SIGIO
131 rb_setup_fd_sigio(rb_fde_t
* F
)
135 flags
= fcntl(fd
, F_GETFL
, 0);
138 /* if set async, clear it so we can reset it in the kernel :/ */
142 fcntl(fd
, F_SETFL
, flags
);
145 flags
|= O_ASYNC
| O_NONBLOCK
;
147 if(fcntl(fd
, F_SETFL
, flags
) == -1)
150 if(fcntl(fd
, F_SETSIG
, RTSIGIO
) == -1)
152 if(fcntl(fd
, F_SETOWN
, getpid()) == -1)
161 * This is a needed exported function which will be called to register
162 * and deregister interest in a pending IO state for a given FD.
165 rb_setselect_sigio(rb_fde_t
* F
, unsigned int type
, PF
* handler
, void *client_data
)
170 if(type
& RB_SELECT_READ
)
172 F
->read_handler
= handler
;
173 F
->read_data
= client_data
;
175 F
->pflags
|= POLLRDNORM
;
177 F
->pflags
&= ~POLLRDNORM
;
179 if(type
& RB_SELECT_WRITE
)
181 F
->write_handler
= handler
;
182 F
->write_data
= client_data
;
184 F
->pflags
|= POLLWRNORM
;
186 F
->pflags
&= ~POLLWRNORM
;
189 resize_pollarray(F
->fd
);
193 pollfd_list
.pollfds
[F
->fd
].events
= 0;
194 pollfd_list
.pollfds
[F
->fd
].fd
= -1;
195 if(F
->fd
== pollfd_list
.maxindex
)
197 while (pollfd_list
.maxindex
>= 0
198 && pollfd_list
.pollfds
[pollfd_list
.maxindex
].fd
== -1)
199 pollfd_list
.maxindex
--;
204 pollfd_list
.pollfds
[F
->fd
].events
= F
->pflags
;
205 pollfd_list
.pollfds
[F
->fd
].fd
= F
->fd
;
206 if(F
->fd
> pollfd_list
.maxindex
)
207 pollfd_list
.maxindex
= F
->fd
;
214 /* int rb_select(long delay)
215 * Input: The maximum time to delay.
216 * Output: Returns -1 on error, 0 on success.
217 * Side-effects: Deregisters future interest in IO and calls the handlers
218 * if an event occurs for an FD.
219 * Comments: Check all connections for new connections and input data
220 * that is to be processed. Also check for connections with data queued
221 * and whether we can write it out.
222 * Called to do the new-style IO, courtesy of squid (like most of this
223 * new IO code). This routine handles the stuff we've hidden in
224 * rb_setselect and fd_table[] and calls callbacks for IO ready
228 rb_select_sigio(long delay
)
240 struct timespec timeout
;
241 if(rb_sigio_supports_event() || delay
>= 0)
243 timeout
.tv_sec
= (delay
/ 1000);
244 timeout
.tv_nsec
= (delay
% 1000) * 1000000;
249 if(!sigio_is_screwed
)
251 if(can_do_event
|| delay
< 0)
253 sig
= sigwaitinfo(&our_sigset
, &si
);
256 sig
= sigtimedwait(&our_sigset
, &si
, &timeout
);
264 ("Kernel RT Signal queue overflowed. Is ulimit -i too small(or perhaps /proc/sys/kernel/rtsig-max on old kernels)");
265 sigio_is_screwed
= 1;
268 #ifdef SIGIO_SCHED_EVENT
269 if(sig
== RTSIGTIM
&& can_do_event
)
271 struct ev_entry
*ev
= (struct ev_entry
*) si
.si_ptr
;
279 pollfd_list
.pollfds
[fd
].revents
|= si
.si_band
;
280 revents
= pollfd_list
.pollfds
[fd
].revents
;
286 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
288 hdl
= F
->read_handler
;
290 F
->read_handler
= NULL
;
296 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
298 hdl
= F
->write_handler
;
299 data
= F
->write_data
;
300 F
->write_handler
= NULL
;
301 F
->write_data
= NULL
;
314 if(!sigio_is_screwed
) /* We don't need to proceed */
320 signal(RTSIGIO
, SIG_IGN
);
321 signal(RTSIGIO
, SIG_DFL
);
322 sigio_is_screwed
= 0;
325 num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, delay
);
329 if(!rb_ignore_errno(errno
))
337 /* XXX we *could* optimise by falling out after doing num fds ... */
338 for (ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
340 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0)
341 || (pollfd_list
.pollfds
[ci
].fd
) == -1)
343 fd
= pollfd_list
.pollfds
[ci
].fd
;
347 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
349 hdl
= F
->read_handler
;
351 F
->read_handler
= NULL
;
357 if(IsFDOpen(F
) && (revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
)))
359 hdl
= F
->write_handler
;
360 data
= F
->write_data
;
361 F
->write_handler
= NULL
;
362 F
->write_data
= NULL
;
366 if(F
->read_handler
== NULL
)
367 rb_setselect_sigio(F
, RB_SELECT_READ
, NULL
, NULL
);
368 if(F
->write_handler
== NULL
)
369 rb_setselect_sigio(F
, RB_SELECT_WRITE
, NULL
, NULL
);
376 #if defined(SIGIO_SCHED_EVENT)
378 rb_sigio_init_event(void)
380 rb_sigio_supports_event();
385 rb_sigio_supports_event(void)
389 if(can_do_event
== 1)
391 if(can_do_event
== -1)
394 ev
.sigev_signo
= SIGVTALRM
;
395 ev
.sigev_notify
= SIGEV_SIGNAL
;
396 if(timer_create(CLOCK_REALTIME
, &ev
, &timer
) != 0)
407 rb_sigio_sched_event(struct ev_entry
*event
, int when
)
411 struct itimerspec ts
;
412 if(can_do_event
<= 0)
415 memset(&ev
, 0, sizeof(&ev
));
416 event
->comm_ptr
= rb_malloc(sizeof(timer_t
));
417 id
= event
->comm_ptr
;
418 ev
.sigev_notify
= SIGEV_SIGNAL
;
419 ev
.sigev_signo
= RTSIGTIM
;
420 ev
.sigev_value
.sival_ptr
= event
;
422 if(timer_create(CLOCK_REALTIME
, &ev
, id
) < 0)
424 rb_lib_log("timer_create: %s\n", strerror(errno
));
427 memset(&ts
, 0, sizeof(ts
));
428 ts
.it_value
.tv_sec
= when
;
429 ts
.it_value
.tv_nsec
= 0;
430 if(event
->frequency
!= 0)
431 ts
.it_interval
= ts
.it_value
;
433 if(timer_settime(*id
, 0, &ts
, NULL
) < 0)
435 rb_lib_log("timer_settime: %s\n", strerror(errno
));
442 rb_sigio_unsched_event(struct ev_entry
*event
)
444 if(can_do_event
<= 0)
446 timer_delete(*((timer_t
*) event
->comm_ptr
));
447 rb_free(event
->comm_ptr
);
448 event
->comm_ptr
= NULL
;
450 #endif /* SIGIO_SCHED_EVENT */
455 rb_init_netio_sigio(void)
461 rb_setselect_sigio(rb_fde_t
* F
, unsigned int type
, PF
* handler
, void *client_data
)
468 rb_select_sigio(long delay
)
475 rb_setup_fd_sigio(rb_fde_t
* F
)
483 #if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
485 rb_sigio_init_event(void)
491 rb_sigio_sched_event(struct ev_entry
*event
, int when
)
498 rb_sigio_unsched_event(struct ev_entry
*event
)
504 rb_sigio_supports_event(void)
509 #endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */