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) && (HAVE_POLL) && (F_SETSIG)
48 #if defined(USE_TIMER_CREATE)
49 #define SIGIO_SCHED_EVENT 1
52 #define RTSIGIO SIGRTMIN
53 #define RTSIGTIM (SIGRTMIN+1)
58 struct pollfd
*pollfds
;
59 int maxindex
; /* highest FD number */
63 typedef struct _pollfd_list pollfd_list_t
;
65 pollfd_list_t pollfd_list
;
66 static int can_do_event
= 0;
67 static int sigio_is_screwed
= 0; /* We overflowed our sigio queue */
68 static sigset_t our_sigset
;
74 * This is a needed exported function which will be called to initialise
75 * the network loop code.
78 rb_init_netio_sigio(void)
81 pollfd_list
.pollfds
= rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd
)));
82 pollfd_list
.allocated
= rb_getmaxconnect();
83 for(fd
= 0; fd
< rb_getmaxconnect(); fd
++)
85 pollfd_list
.pollfds
[fd
].fd
= -1;
88 pollfd_list
.maxindex
= 0;
90 sigio_is_screwed
= 1; /* Start off with poll first.. */
92 sigemptyset(&our_sigset
);
93 sigaddset(&our_sigset
, RTSIGIO
);
94 sigaddset(&our_sigset
, SIGIO
);
95 #ifdef SIGIO_SCHED_EVENT
96 sigaddset(&our_sigset
, RTSIGTIM
);
98 sigprocmask(SIG_BLOCK
, &our_sigset
, NULL
);
103 resize_pollarray(int fd
)
105 if(rb_unlikely(fd
>= pollfd_list
.allocated
))
107 int x
, old_value
= pollfd_list
.allocated
;
108 pollfd_list
.allocated
+= 1024;
109 pollfd_list
.pollfds
=
110 rb_realloc(pollfd_list
.pollfds
,
111 pollfd_list
.allocated
* (sizeof(struct pollfd
)));
112 memset(&pollfd_list
.pollfds
[old_value
+ 1], 0, sizeof(struct pollfd
) * 1024);
113 for(x
= old_value
+ 1; x
< pollfd_list
.allocated
; x
++)
115 pollfd_list
.pollfds
[x
].fd
= -1;
122 * void setup_sigio_fd(int fd)
124 * Input: File descriptor
126 * Side Effect: Sets the FD up for SIGIO
130 rb_setup_fd_sigio(rb_fde_t
*F
)
134 flags
= fcntl(fd
, F_GETFL
, 0);
137 /* if set async, clear it so we can reset it in the kernel :/ */
141 fcntl(fd
, F_SETFL
, flags
);
144 flags
|= O_ASYNC
| O_NONBLOCK
;
146 if(fcntl(fd
, F_SETFL
, flags
) == -1)
149 if(fcntl(fd
, F_SETSIG
, RTSIGIO
) == -1)
151 if(fcntl(fd
, F_SETOWN
, getpid()) == -1)
160 * This is a needed exported function which will be called to register
161 * and deregister interest in a pending IO state for a given FD.
164 rb_setselect_sigio(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
169 if(type
& RB_SELECT_READ
)
171 F
->read_handler
= handler
;
172 F
->read_data
= client_data
;
174 F
->pflags
|= POLLRDNORM
;
176 F
->pflags
&= ~POLLRDNORM
;
178 if(type
& RB_SELECT_WRITE
)
180 F
->write_handler
= handler
;
181 F
->write_data
= client_data
;
183 F
->pflags
|= POLLWRNORM
;
185 F
->pflags
&= ~POLLWRNORM
;
188 resize_pollarray(F
->fd
);
192 pollfd_list
.pollfds
[F
->fd
].events
= 0;
193 pollfd_list
.pollfds
[F
->fd
].fd
= -1;
194 if(F
->fd
== pollfd_list
.maxindex
)
196 while(pollfd_list
.maxindex
>= 0
197 && pollfd_list
.pollfds
[pollfd_list
.maxindex
].fd
== -1)
198 pollfd_list
.maxindex
--;
203 pollfd_list
.pollfds
[F
->fd
].events
= F
->pflags
;
204 pollfd_list
.pollfds
[F
->fd
].fd
= F
->fd
;
205 if(F
->fd
> pollfd_list
.maxindex
)
206 pollfd_list
.maxindex
= F
->fd
;
213 /* int rb_select(long delay)
214 * Input: The maximum time to delay.
215 * Output: Returns -1 on error, 0 on success.
216 * Side-effects: Deregisters future interest in IO and calls the handlers
217 * if an event occurs for an FD.
218 * Comments: Check all connections for new connections and input data
219 * that is to be processed. Also check for connections with data queued
220 * and whether we can write it out.
221 * Called to do the new-style IO, courtesy of squid (like most of this
222 * new IO code). This routine handles the stuff we've hidden in
223 * rb_setselect and fd_table[] and calls callbacks for IO ready
227 rb_select_sigio(long delay
)
239 struct timespec timeout
;
240 if(rb_sigio_supports_event() || delay
>= 0)
242 timeout
.tv_sec
= (delay
/ 1000);
243 timeout
.tv_nsec
= (delay
% 1000) * 1000000;
248 if(!sigio_is_screwed
)
250 if(can_do_event
|| delay
< 0)
252 sig
= sigwaitinfo(&our_sigset
, &si
);
255 sig
= sigtimedwait(&our_sigset
, &si
, &timeout
);
263 ("Kernel RT Signal queue overflowed. Is ulimit -i too small(or perhaps /proc/sys/kernel/rtsig-max on old kernels)");
264 sigio_is_screwed
= 1;
267 #ifdef SIGIO_SCHED_EVENT
268 if(sig
== RTSIGTIM
&& can_do_event
)
270 struct ev_entry
*ev
= (struct ev_entry
*)si
.si_ptr
;
273 rb_run_one_event(ev
);
278 pollfd_list
.pollfds
[fd
].revents
|= si
.si_band
;
279 revents
= pollfd_list
.pollfds
[fd
].revents
;
285 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
287 hdl
= F
->read_handler
;
289 F
->read_handler
= NULL
;
295 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
297 hdl
= F
->write_handler
;
298 data
= F
->write_data
;
299 F
->write_handler
= NULL
;
300 F
->write_data
= NULL
;
313 if(!sigio_is_screwed
) /* We don't need to proceed */
319 signal(RTSIGIO
, SIG_IGN
);
320 signal(RTSIGIO
, SIG_DFL
);
321 sigio_is_screwed
= 0;
324 num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, delay
);
328 if(!rb_ignore_errno(errno
))
336 /* XXX we *could* optimise by falling out after doing num fds ... */
337 for(ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
339 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0)
340 || (pollfd_list
.pollfds
[ci
].fd
) == -1)
342 fd
= pollfd_list
.pollfds
[ci
].fd
;
346 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
348 hdl
= F
->read_handler
;
350 F
->read_handler
= NULL
;
356 if(IsFDOpen(F
) && (revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
)))
358 hdl
= F
->write_handler
;
359 data
= F
->write_data
;
360 F
->write_handler
= NULL
;
361 F
->write_data
= NULL
;
365 if(F
->read_handler
== NULL
)
366 rb_setselect_sigio(F
, RB_SELECT_READ
, NULL
, NULL
);
367 if(F
->write_handler
== NULL
)
368 rb_setselect_sigio(F
, RB_SELECT_WRITE
, NULL
, NULL
);
375 #if defined(SIGIO_SCHED_EVENT)
377 rb_sigio_init_event(void)
379 rb_sigio_supports_event();
384 rb_sigio_supports_event(void)
388 if(can_do_event
== 1)
390 if(can_do_event
== -1)
393 ev
.sigev_signo
= SIGVTALRM
;
394 ev
.sigev_notify
= SIGEV_SIGNAL
;
395 if(timer_create(CLOCK_REALTIME
, &ev
, &timer
) != 0)
406 rb_sigio_sched_event(struct ev_entry
*event
, int when
)
410 struct itimerspec ts
;
411 if(can_do_event
<= 0)
414 memset(&ev
, 0, sizeof(ev
));
415 event
->comm_ptr
= rb_malloc(sizeof(timer_t
));
416 id
= event
->comm_ptr
;
417 ev
.sigev_notify
= SIGEV_SIGNAL
;
418 ev
.sigev_signo
= RTSIGTIM
;
419 ev
.sigev_value
.sival_ptr
= event
;
421 if(timer_create(CLOCK_REALTIME
, &ev
, id
) < 0)
423 rb_lib_log("timer_create: %s\n", strerror(errno
));
426 memset(&ts
, 0, sizeof(ts
));
427 ts
.it_value
.tv_sec
= when
;
428 ts
.it_value
.tv_nsec
= 0;
429 if(event
->frequency
!= 0)
430 ts
.it_interval
= ts
.it_value
;
432 if(timer_settime(*id
, 0, &ts
, NULL
) < 0)
434 rb_lib_log("timer_settime: %s\n", strerror(errno
));
441 rb_sigio_unsched_event(struct ev_entry
*event
)
443 if(can_do_event
<= 0)
445 timer_delete(*((timer_t
*) event
->comm_ptr
));
446 rb_free(event
->comm_ptr
);
447 event
->comm_ptr
= NULL
;
449 #endif /* SIGIO_SCHED_EVENT */
454 rb_init_netio_sigio(void)
460 rb_setselect_sigio(rb_fde_t
*F
, unsigned int type
, PF
* handler
, void *client_data
)
467 rb_select_sigio(long delay
)
474 rb_setup_fd_sigio(rb_fde_t
*F
)
482 #if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
484 rb_sigio_init_event(void)
490 rb_sigio_sched_event(struct ev_entry
*event
, int when
)
497 rb_sigio_unsched_event(struct ev_entry
*event
)
503 rb_sigio_supports_event(void)
508 #endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */