]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/sigio.c
Copied libratbox and related stuff from shadowircd upstream.
[irc/rqf/shadowircd.git] / libratbox / src / sigio.c
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 *
26 * $Id: sigio.c 26092 2008-09-19 15:13:52Z androsyn $
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
57 struct _pollfd_list
58 {
59 struct pollfd *pollfds;
60 int maxindex; /* highest FD number */
61 int allocated;
62 };
63
64 typedef struct _pollfd_list pollfd_list_t;
65
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;
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 */
78 int
79 rb_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();
84 for(fd = 0; fd < rb_getmaxconnect(); fd++)
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
103 static inline void
104 resize_pollarray(int fd)
105 {
106 if(rb_unlikely(fd >= pollfd_list.allocated))
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);
114 for(x = old_value + 1; x < pollfd_list.allocated; x++)
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
130 int
131 rb_setup_fd_sigio(rb_fde_t *F)
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 */
164 void
165 rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
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 {
197 while(pollfd_list.maxindex >= 0
198 && pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
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 */
227 int
228 rb_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
247 for(;;)
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 {
271 struct ev_entry *ev = (struct ev_entry *)si.si_ptr;
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 ... */
338 for(ci = 0; ci < pollfd_list.maxindex + 1; ci++)
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)
377 void
378 rb_sigio_init_event(void)
379 {
380 rb_sigio_supports_event();
381 }
382
383
384 int
385 rb_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
406 int
407 rb_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
441 void
442 rb_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
454 int
455 rb_init_netio_sigio(void)
456 {
457 return ENOSYS;
458 }
459
460 void
461 rb_setselect_sigio(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
462 {
463 errno = ENOSYS;
464 return;
465 }
466
467 int
468 rb_select_sigio(long delay)
469 {
470 errno = ENOSYS;
471 return -1;
472 }
473
474 int
475 rb_setup_fd_sigio(rb_fde_t *F)
476 {
477 errno = ENOSYS;
478 return -1;
479 }
480
481 #endif
482
483 #if !defined(USING_SIGIO) || !defined(SIGIO_SCHED_EVENT)
484 void
485 rb_sigio_init_event(void)
486 {
487 return;
488 }
489
490 int
491 rb_sigio_sched_event(struct ev_entry *event, int when)
492 {
493 errno = ENOSYS;
494 return -1;
495 }
496
497 void
498 rb_sigio_unsched_event(struct ev_entry *event)
499 {
500 return;
501 }
502
503 int
504 rb_sigio_supports_event(void)
505 {
506 errno = ENOSYS;
507 return 0;
508 }
509 #endif /* !USING_SIGIO || !SIGIO_SCHED_EVENT */