]> jfr.im git - irc/rqf/shadowircd.git/blame - libratbox/src/sigio.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / sigio.c
CommitLineData
b57f37fb
WP
1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * sigio.c: Linux Realtime SIGIO compatible network routines.
4 *
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
10 *
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.
15 *
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.
20 *
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
24 * USA
25 *
94b4fbf9 26 * $Id: sigio.c 26092 2008-09-19 15:13:52Z androsyn $
b57f37fb
WP
27 */
28
29#ifndef _GNU_SOURCE
30#define _GNU_SOURCE 1 /* Needed for F_SETSIG */
31#endif
32
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 */
38
39#if defined(HAVE_SYS_POLL_H) && (HAVE_POLL) && (F_SETSIG)
40#define USING_SIGIO
41#endif
42
43
44#ifdef USING_SIGIO
45
46#include <signal.h>
47#include <sys/poll.h>
48
49#if defined(USE_TIMER_CREATE)
50#define SIGIO_SCHED_EVENT 1
51#endif
52
53#define RTSIGIO SIGRTMIN
54#define RTSIGTIM (SIGRTMIN+1)
55
56
57struct _pollfd_list
58{
59 struct pollfd *pollfds;
60 int maxindex; /* highest FD number */
61 int allocated;
62};
63
64typedef struct _pollfd_list pollfd_list_t;
65
66pollfd_list_t pollfd_list;
67static int can_do_event = 0;
68static int sigio_is_screwed = 0; /* We overflowed our sigio queue */
69static sigset_t our_sigset;
70
71
72/*
73 * rb_init_netio
74 *
75 * This is a needed exported function which will be called to initialise
76 * the network loop code.
77 */
78int
79rb_init_netio_sigio(void)
80{
81 int fd;
82 pollfd_list.pollfds = rb_malloc(rb_getmaxconnect() * (sizeof(struct pollfd)));
83 pollfd_list.allocated = rb_getmaxconnect();
94b4fbf9 84 for(fd = 0; fd < rb_getmaxconnect(); fd++)
b57f37fb
WP
85 {
86 pollfd_list.pollfds[fd].fd = -1;
87 }
88
89 pollfd_list.maxindex = 0;
90
91 sigio_is_screwed = 1; /* Start off with poll first.. */
92
93 sigemptyset(&our_sigset);
94 sigaddset(&our_sigset, RTSIGIO);
95 sigaddset(&our_sigset, SIGIO);
96#ifdef SIGIO_SCHED_EVENT
97 sigaddset(&our_sigset, RTSIGTIM);
98#endif
99 sigprocmask(SIG_BLOCK, &our_sigset, NULL);
100 return 0;
101}
102
103static inline void
104resize_pollarray(int fd)
105{
033be687 106 if(rb_unlikely(fd >= pollfd_list.allocated))
b57f37fb
WP
107 {
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);
94b4fbf9 114 for(x = old_value + 1; x < pollfd_list.allocated; x++)
b57f37fb
WP
115 {
116 pollfd_list.pollfds[x].fd = -1;
117 }
118 }
119}
120
121
122/*
123 * void setup_sigio_fd(int fd)
124 *
125 * Input: File descriptor
126 * Output: None
127 * Side Effect: Sets the FD up for SIGIO
128 */
129
130int
94b4fbf9 131rb_setup_fd_sigio(rb_fde_t *F)
b57f37fb
WP
132{
133 int flags = 0;
134 int fd = F->fd;
135 flags = fcntl(fd, F_GETFL, 0);
136 if(flags == -1)
137 return 0;
138 /* if set async, clear it so we can reset it in the kernel :/ */
139 if(flags & O_ASYNC)
140 {
141 flags &= ~O_ASYNC;
142 fcntl(fd, F_SETFL, flags);
143 }
144
145 flags |= O_ASYNC | O_NONBLOCK;
146
147 if(fcntl(fd, F_SETFL, flags) == -1)
148 return 0;
149
150 if(fcntl(fd, F_SETSIG, RTSIGIO) == -1)
151 return 0;
152 if(fcntl(fd, F_SETOWN, getpid()) == -1)
153 return 0;
154
155 return 1;
156}
157
158/*
159 * rb_setselect
160 *
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.
163 */
164void
94b4fbf9 165rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
b57f37fb
WP
166{
167 if(F == NULL)
168 return;
169
170 if(type & RB_SELECT_READ)
171 {
172 F->read_handler = handler;
173 F->read_data = client_data;
174 if(handler != NULL)
175 F->pflags |= POLLRDNORM;
176 else
177 F->pflags &= ~POLLRDNORM;
178 }
179 if(type & RB_SELECT_WRITE)
180 {
181 F->write_handler = handler;
182 F->write_data = client_data;
183 if(handler != NULL)
184 F->pflags |= POLLWRNORM;
185 else
186 F->pflags &= ~POLLWRNORM;
187 }
188
189 resize_pollarray(F->fd);
190
191 if(F->pflags <= 0)
192 {
193 pollfd_list.pollfds[F->fd].events = 0;
194 pollfd_list.pollfds[F->fd].fd = -1;
195 if(F->fd == pollfd_list.maxindex)
196 {
94b4fbf9
VY
197 while(pollfd_list.maxindex >= 0
198 && pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
b57f37fb
WP
199 pollfd_list.maxindex--;
200 }
201 }
202 else
203 {
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;
208 }
209
210}
211
212
213
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
225 * events.
226 */
227int
228rb_select_sigio(long delay)
229{
230 int num = 0;
231 int revents = 0;
232 int sig;
233 int fd;
234 int ci;
235 PF *hdl;
236 rb_fde_t *F;
237 void *data;
238 struct siginfo si;
239
240 struct timespec timeout;
241 if(rb_sigio_supports_event() || delay >= 0)
242 {
243 timeout.tv_sec = (delay / 1000);
244 timeout.tv_nsec = (delay % 1000) * 1000000;
245 }
246
94b4fbf9 247 for(;;)
b57f37fb
WP
248 {
249 if(!sigio_is_screwed)
250 {
251 if(can_do_event || delay < 0)
252 {
253 sig = sigwaitinfo(&our_sigset, &si);
254 }
255 else
256 sig = sigtimedwait(&our_sigset, &si, &timeout);
257
258 if(sig > 0)
259 {
260
261 if(sig == SIGIO)
262 {
263 rb_lib_log
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;
266 break;
267 }
268#ifdef SIGIO_SCHED_EVENT
269 if(sig == RTSIGTIM && can_do_event)
270 {
94b4fbf9 271 struct ev_entry *ev = (struct ev_entry *)si.si_ptr;
b57f37fb
WP
272 if(ev == NULL)
273 continue;
274 rb_run_event(ev);
275 continue;
276 }
277#endif
278 fd = si.si_fd;
279 pollfd_list.pollfds[fd].revents |= si.si_band;
280 revents = pollfd_list.pollfds[fd].revents;
281 num++;
282 F = rb_find_fd(fd);
283 if(F == NULL)
284 continue;
285
286 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
287 {
288 hdl = F->read_handler;
289 data = F->read_data;
290 F->read_handler = NULL;
291 F->read_data = NULL;
292 if(hdl)
293 hdl(F, data);
294 }
295
296 if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
297 {
298 hdl = F->write_handler;
299 data = F->write_data;
300 F->write_handler = NULL;
301 F->write_data = NULL;
302 if(hdl)
303 hdl(F, data);
304 }
305 }
306 else
307 break;
308
309 }
310 else
311 break;
312 }
313
314 if(!sigio_is_screwed) /* We don't need to proceed */
315 {
316 rb_set_time();
317 return 0;
318 }
319
320 signal(RTSIGIO, SIG_IGN);
321 signal(RTSIGIO, SIG_DFL);
322 sigio_is_screwed = 0;
323
324
325 num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
326 rb_set_time();
327 if(num < 0)
328 {
329 if(!rb_ignore_errno(errno))
330 return RB_OK;
331 else
332 return RB_ERROR;
333 }
334 if(num == 0)
335 return RB_OK;
336
337 /* XXX we *could* optimise by falling out after doing num fds ... */
94b4fbf9 338 for(ci = 0; ci < pollfd_list.maxindex + 1; ci++)
b57f37fb
WP
339 {
340 if(((revents = pollfd_list.pollfds[ci].revents) == 0)
341 || (pollfd_list.pollfds[ci].fd) == -1)
342 continue;
343 fd = pollfd_list.pollfds[ci].fd;
344 F = rb_find_fd(fd);
345 if(F == NULL)
346 continue;
347 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
348 {
349 hdl = F->read_handler;
350 data = F->read_data;
351 F->read_handler = NULL;
352 F->read_data = NULL;
353 if(hdl)
354 hdl(F, data);
355 }
356
357 if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)))
358 {
359 hdl = F->write_handler;
360 data = F->write_data;
361 F->write_handler = NULL;
362 F->write_data = NULL;
363 if(hdl)
364 hdl(F, data);
365 }
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);
370
371 }
372
373 return 0;
374}
375
376#if defined(SIGIO_SCHED_EVENT)
377void
378rb_sigio_init_event(void)
379{
380 rb_sigio_supports_event();
381}
382
383
384int
385rb_sigio_supports_event(void)
386{
387 timer_t timer;
388 struct sigevent ev;
389 if(can_do_event == 1)
390 return 1;
391 if(can_do_event == -1)
392 return 0;
393
394 ev.sigev_signo = SIGVTALRM;
395 ev.sigev_notify = SIGEV_SIGNAL;
396 if(timer_create(CLOCK_REALTIME, &ev, &timer) != 0)
397 {
398 can_do_event = -1;
399 return 0;
400 }
401 timer_delete(timer);
402 can_do_event = 1;
403 return 1;
404}
405
406int
407rb_sigio_sched_event(struct ev_entry *event, int when)
408{
409 timer_t *id;
410 struct sigevent ev;
411 struct itimerspec ts;
412 if(can_do_event <= 0)
413 return 0;
414
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;
421
422 if(timer_create(CLOCK_REALTIME, &ev, id) < 0)
423 {
424 rb_lib_log("timer_create: %s\n", strerror(errno));
425 return 0;
426 }
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;
432
433 if(timer_settime(*id, 0, &ts, NULL) < 0)
434 {
435 rb_lib_log("timer_settime: %s\n", strerror(errno));
436 return 0;
437 }
438 return 1;
439}
440
441void
442rb_sigio_unsched_event(struct ev_entry *event)
443{
444 if(can_do_event <= 0)
445 return;
446 timer_delete(*((timer_t *) event->comm_ptr));
447 rb_free(event->comm_ptr);
448 event->comm_ptr = NULL;
449}
450#endif /* SIGIO_SCHED_EVENT */
451
452#else
453
454int
455rb_init_netio_sigio(void)
456{
457 return ENOSYS;
458}
459
460void
94b4fbf9 461rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
b57f37fb
WP
462{
463 errno = ENOSYS;
464 return;
465}
466
467int
468rb_select_sigio(long delay)
469{
470 errno = ENOSYS;
471 return -1;
472}
473
474int
94b4fbf9 475rb_setup_fd_sigio(rb_fde_t *F)
b57f37fb
WP
476{
477 errno = ENOSYS;
478 return -1;
479}
480
481#endif
482
483#if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
484void
485rb_sigio_init_event(void)
486{
487 return;
488}
489
490int
491rb_sigio_sched_event(struct ev_entry *event, int when)
492{
493 errno = ENOSYS;
494 return -1;
495}
496
497void
498rb_sigio_unsched_event(struct ev_entry *event)
499{
500 return;
501}
502
503int
504rb_sigio_supports_event(void)
505{
506 errno = ENOSYS;
507 return 0;
508}
509#endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */