ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/s_bsd_sigio.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 7061 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * s_bsd_sigio.c: Linux Realtime SIGIO compatible network routines.
4 *
5 * Originally by Aaron Sethman <androsyn@ratbox.org>
6 * based upon: s_bsd_poll.c by Adrian Chadd <adrian@creative.net.au>
7 * Copyright (C) 2001-2002 Hybrid Development Team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id$
25 */
26
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE 1 /* Needed for F_SETSIG */
29 #endif
30
31 #include "stdinc.h"
32 #include <sys/poll.h>
33 #include "fdlist.h"
34 #include "hook.h"
35 #include "ircd.h"
36 #include "s_bsd.h"
37 #include "s_log.h"
38
39 #define SIGIO_SIGNAL SIGRTMIN
40
41 static pid_t my_pid;
42 static sigset_t our_sigset;
43 static struct pollfd *pollfds;
44 static int pollmax = -1; /* highest FD number */
45 static dlink_node *fdlim_hook, *setupfd_hook;
46
47 /*
48 * static void mask_our_signal(int s)
49 *
50 * Input: None
51 * Output: None
52 * Side Effects: Block our signal
53 */
54 static void
55 mask_our_signal()
56 {
57 sigemptyset(&our_sigset);
58 sigaddset(&our_sigset, SIGIO_SIGNAL);
59 sigaddset(&our_sigset, SIGIO);
60 sigprocmask(SIG_BLOCK, &our_sigset, NULL);
61 }
62
63 /*
64 * void setup_sigio_fd(int fd)
65 *
66 * Input: File descriptor
67 * Output: None
68 * Side Effect: Sets the FD up for SIGIO
69 */
70 static void *
71 setup_sigio_fd(va_list args)
72 {
73 int fd = va_arg(args, int);
74
75 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC);
76 fcntl(fd, F_SETSIG, SIGIO_SIGNAL);
77 fcntl(fd, F_SETOWN, my_pid);
78
79 return pass_callback(setupfd_hook, fd);
80 }
81
82 /*
83 * changing_fdlimit
84 *
85 * Resize pollfds array if necessary.
86 */
87 static void *
88 changing_fdlimit(va_list args)
89 {
90 int old_fdlimit = hard_fdlimit;
91
92 pass_callback(fdlim_hook, va_arg(args, int));
93
94 if (hard_fdlimit != old_fdlimit)
95 pollfds = MyRealloc(pollfds, sizeof(struct pollfd) * hard_fdlimit);
96
97 return NULL;
98 }
99
100 /*
101 * void init_netio(void)
102 *
103 * Input: None
104 * Output: None
105 * Side Effects: This is a needed exported function which will
106 * be called to initialise the network loop code.
107 */
108 void
109 init_netio(void)
110 {
111 int fd;
112
113 pollfds = MyMalloc(sizeof(struct pollfd) * hard_fdlimit);
114
115 for (fd = 0; fd < hard_fdlimit; fd++)
116 pollfds[fd].fd = -1;
117
118 setupfd_hook = install_hook(setup_socket_cb, setup_sigio_fd);
119 fdlim_hook = install_hook(fdlimit_cb, changing_fdlimit);
120
121 my_pid = getpid();
122 mask_our_signal(SIGIO_SIGNAL);
123 }
124
125 /*
126 * find a spare slot in the fd list. We can optimise this out later!
127 * -- adrian
128 */
129 static inline int
130 poll_findslot(void)
131 {
132 int i;
133
134 for (i = 0; i < hard_fdlimit; i++)
135 {
136 if (pollfds[i].fd == -1)
137 {
138 /* MATCH!!#$*&$ */
139 return i;
140 }
141 }
142
143 assert(1 == 0);
144 /* NOTREACHED */
145 return -1;
146 }
147
148 /*
149 * comm_setselect
150 *
151 * This is a needed exported function which will be called to register
152 * and deregister interest in a pending IO state for a given FD.
153 */
154 void
155 comm_setselect(fde_t *F, unsigned int type, PF *handler,
156 void *client_data, time_t timeout)
157 {
158 int new_events;
159
160 if ((type & COMM_SELECT_READ))
161 {
162 F->read_handler = handler;
163 F->read_data = client_data;
164 }
165
166 if ((type & COMM_SELECT_WRITE))
167 {
168 F->write_handler = handler;
169 F->write_data = client_data;
170 }
171
172 new_events = (F->read_handler ? POLLRDNORM : 0) |
173 (F->write_handler ? POLLWRNORM : 0);
174
175 if (timeout != 0)
176 F->timeout = CurrentTime + (timeout / 1000);
177
178 if (new_events != F->evcache)
179 {
180 if (new_events == 0)
181 {
182 pollfds[F->comm_index].fd = -1;
183 pollfds[F->comm_index].revents = 0;
184
185 if (pollmax == F->comm_index)
186 while (pollmax >= 0 && pollfds[pollmax].fd == -1)
187 pollmax--;
188 }
189 else
190 {
191 if (F->evcache == 0)
192 {
193 F->comm_index = poll_findslot();
194 if (F->comm_index > pollmax)
195 pollmax = F->comm_index;
196
197 pollfds[F->comm_index].fd = F->fd;
198 }
199 pollfds[F->comm_index].events = new_events;
200 pollfds[F->comm_index].revents = 0;
201 }
202
203 F->evcache = new_events;
204 }
205 }
206
207 /*
208 * comm_select
209 *
210 * Called to do the new-style IO, courtesy of squid (like most of this
211 * new IO code). This routine handles the stuff we've hidden in
212 * comm_setselect and fd_table[] and calls callbacks for IO ready
213 * events.
214 */
215 void
216 comm_select(void)
217 {
218 static time_t last_rtsigqo_warning = 0;
219 struct timespec timeout;
220 struct siginfo si;
221 int i, revents, num;
222 fde_t *F;
223 PF *hdl;
224
225 timeout.tv_sec = 0;
226 timeout.tv_nsec = 1000000 * SELECT_DELAY;
227 i = sigtimedwait(&our_sigset, &si, &timeout);
228
229 set_time();
230
231 if (i != SIGIO)
232 {
233 if (i > 0)
234 {
235 F = lookup_fd(si.si_fd);
236 if (F == NULL || !F->flags.open)
237 return;
238
239 if (si.si_band & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
240 if ((hdl = F->read_handler) != NULL)
241 {
242 F->read_handler = NULL;
243 hdl(F, F->read_data);
244 if (!F->flags.open)
245 return;
246 }
247
248 if (si.si_band & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
249 if ((hdl = F->write_handler) != NULL)
250 {
251 F->write_handler = NULL;
252 hdl(F, F->write_data);
253 if (!F->flags.open)
254 return;
255 }
256
257 comm_setselect(F, 0, NULL, NULL, 0);
258 }
259
260 return;
261 }
262
263 /* RT signal queue overflowed.. */
264
265 if (CurrentTime - last_rtsigqo_warning >= 30)
266 {
267 ilog(L_WARN, "Kernel RT Signal queue overflowed. "
268 "Is /proc/sys/kernel/rtsig-max too small?");
269 last_rtsigqo_warning = CurrentTime;
270 }
271
272 signal(SIGIO_SIGNAL, SIG_IGN);
273 signal(SIGIO_SIGNAL, SIG_DFL);
274
275 /* ..try polling instead */
276
277 while ((num = poll(pollfds, pollmax + 1, 0)) < 0 && ignoreErrno(errno))
278 ;
279
280 /* update current time again, eww.. */
281 set_time();
282
283 for (i = 0; i <= pollmax && num > 0; i++)
284 {
285 if ((revents = pollfds[i].revents) == 0 || pollfds[i].fd == -1)
286 continue;
287 num--;
288
289 F = lookup_fd(pollfds[i].fd);
290 if (F == NULL || !F->flags.open)
291 continue;
292
293 if (revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
294 if ((hdl = F->read_handler) != NULL)
295 {
296 F->read_handler = NULL;
297 hdl(F, F->read_data);
298 if (!F->flags.open)
299 continue;
300 }
301
302 if (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
303 if ((hdl = F->write_handler) != NULL)
304 {
305 F->write_handler = NULL;
306 hdl(F, F->write_data);
307 if (!F->flags.open)
308 continue;
309 }
310
311 comm_setselect(F, 0, NULL, NULL, 0);
312 }
313
314 mask_our_signal(SIGIO_SIGNAL);
315 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision