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