]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/devpoll.c
[svn] - the new plan:
[irc/rqf/shadowircd.git] / libcharybdis / devpoll.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_bsd_devpoll.c: /dev/poll 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-2005 ircd-ratbox development team
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 * $Id: devpoll.c 390 2005-12-07 18:46:56Z nenolod $
26 */
27
28 #include "config.h"
29
30 #include "stdinc.h"
31 #include <sys/devpoll.h>
32
33 #include "libcharybdis.h"
34
35 #define POLL_LENGTH HARD_FDLIMIT
36
37
38 static void devpoll_update_events(int, short, PF *);
39 static int dpfd;
40 static short fdmask[POLL_LENGTH];
41 static void devpoll_update_events(int, short, PF *);
42 static void devpoll_write_update(int, int);
43
44 /* #define NOTYET 1 */
45
46 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
47 /* Private functions */
48
49 /*
50 * Write an update to the devpoll filter.
51 * See, we end up having to do a seperate (?) remove before we do an
52 * add of a new polltype, so we have to have this function seperate from
53 * the others.
54 */
55 static void
56 devpoll_write_update(int fd, int events)
57 {
58 struct pollfd pollfds[1]; /* Just to be careful */
59 int retval;
60
61 /* Build the pollfd entry */
62 pollfds[0].revents = 0;
63 pollfds[0].fd = fd;
64 pollfds[0].events = events;
65
66 /* Write the thing to our poll fd */
67 retval = write(dpfd, &pollfds[0], sizeof(struct pollfd));
68 if(retval != sizeof(struct pollfd))
69 libcharybdis_log("devpoll_write_update: dpfd write failed %d: %s", errno, strerror(errno));
70 /* Done! */
71 }
72
73 void
74 devpoll_update_events(int fd, short filter, PF * handler)
75 {
76 int update_required = 0;
77 int cur_mask = fdmask[fd];
78 PF *cur_handler;
79 fdmask[fd] = 0;
80 switch (filter)
81 {
82 case COMM_SELECT_READ:
83 cur_handler = fd_table[fd].read_handler;
84 if(handler)
85 fdmask[fd] |= POLLRDNORM;
86 else
87 fdmask[fd] &= ~POLLRDNORM;
88 if(fd_table[fd].write_handler)
89 fdmask[fd] |= POLLWRNORM;
90 break;
91 case COMM_SELECT_WRITE:
92 cur_handler = fd_table[fd].write_handler;
93 if(handler)
94 fdmask[fd] |= POLLWRNORM;
95 else
96 fdmask[fd] &= ~POLLWRNORM;
97 if(fd_table[fd].read_handler)
98 fdmask[fd] |= POLLRDNORM;
99 break;
100 default:
101 #ifdef NOTYET
102 libcharybdis_log("devpoll_update_events called with unknown filter: %hd", filter);
103 #endif
104 return;
105 break;
106 }
107
108 if(cur_handler == NULL && handler != NULL)
109 update_required++;
110 else if(cur_handler != NULL && handler == NULL)
111 update_required++;
112 if(cur_mask != fdmask[fd])
113 update_required++;
114 if(update_required)
115 {
116 /*
117 * Ok, we can call devpoll_write_update() here now to re-build the
118 * fd struct. If we end up with nothing on this fd, it won't write
119 * anything.
120 */
121 if(fdmask[fd])
122 {
123 devpoll_write_update(fd, POLLREMOVE);
124 devpoll_write_update(fd, fdmask[fd]);
125 }
126 else
127 devpoll_write_update(fd, POLLREMOVE);
128 }
129 }
130
131
132
133
134
135 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
136 /* Public functions */
137
138
139 /*
140 * init_netio
141 *
142 * This is a needed exported function which will be called to initialise
143 * the network loop code.
144 */
145 void
146 init_netio(void)
147 {
148 memset(&fdmask, 0, sizeof(fdmask));
149 dpfd = open("/dev/poll", O_RDWR);
150 if(dpfd < 0)
151 {
152 fprintf(stderr,
153 "init_netio: Couldn't open /dev/poll - %d: %s\n",
154 errno, strerror(errno));
155 exit(115); /* Whee! */
156 }
157 }
158
159 /*
160 * comm_setselect
161 *
162 * This is a needed exported function which will be called to register
163 * and deregister interest in a pending IO state for a given FD.
164 */
165 void
166 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
167 void *client_data, time_t timeout)
168 {
169 fde_t *F = &fd_table[fd];
170 s_assert(fd >= 0);
171 s_assert(F->flags.open);
172
173 /* Update the list, even though we're not using it .. */
174 F->list = list;
175
176 if(type & COMM_SELECT_READ)
177 {
178 devpoll_update_events(fd, COMM_SELECT_READ, handler);
179 F->read_handler = handler;
180 F->read_data = client_data;
181 }
182 if(type & COMM_SELECT_WRITE)
183 {
184 devpoll_update_events(fd, COMM_SELECT_WRITE, handler);
185 F->write_handler = handler;
186 F->write_data = client_data;
187 }
188 if(timeout)
189 F->timeout = CurrentTime + (timeout / 1000);
190 }
191
192 /*
193 * Check all connections for new connections and input data that is to be
194 * processed. Also check for connections with data queued and whether we can
195 * write it out.
196 */
197
198 /*
199 * comm_select
200 *
201 * Called to do the new-style IO, courtesy of squid (like most of this
202 * new IO code). This routine handles the stuff we've hidden in
203 * comm_setselect and fd_table[] and calls callbacks for IO ready
204 * events.
205 */
206
207 int
208 comm_select(unsigned long delay)
209 {
210 int num, i;
211 struct pollfd pollfds[POLL_LENGTH];
212 struct dvpoll dopoll;
213
214 do
215 {
216 for (;;)
217 {
218 dopoll.dp_timeout = delay;
219 dopoll.dp_nfds = POLL_LENGTH;
220 dopoll.dp_fds = &pollfds[0];
221 num = ioctl(dpfd, DP_POLL, &dopoll);
222 if(num >= 0)
223 break;
224 if(ignoreErrno(errno))
225 break;
226 set_time();
227 return COMM_ERROR;
228 }
229
230 set_time();
231 if(num == 0)
232 continue;
233
234 for (i = 0; i < num; i++)
235 {
236 int fd = dopoll.dp_fds[i].fd;
237 PF *hdl = NULL;
238 fde_t *F = &fd_table[fd];
239 if((dopoll.dp_fds[i].
240 revents & (POLLRDNORM | POLLIN | POLLHUP |
241 POLLERR))
242 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
243 {
244 if((hdl = F->read_handler) != NULL)
245 {
246 F->read_handler = NULL;
247 hdl(fd, F->read_data);
248 /*
249 * this call used to be with a NULL pointer, BUT
250 * in the devpoll case we only want to update the
251 * poll set *if* the handler changes state (active ->
252 * NULL or vice versa.)
253 */
254 devpoll_update_events(fd,
255 COMM_SELECT_READ, F->read_handler);
256 }
257 else
258 libcharybdis_log("comm_select: Unhandled read event: fdmask: %x",
259 fdmask[fd]);
260 }
261
262 if(F->flags.open == 0)
263 continue; /* Read handler closed us..go on to do something more useful */
264 if((dopoll.dp_fds[i].
265 revents & (POLLWRNORM | POLLOUT | POLLHUP |
266 POLLERR))
267 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
268 {
269 if((hdl = F->write_handler) != NULL)
270 {
271 F->write_handler = NULL;
272 hdl(fd, F->write_data);
273 /* See above similar code in the read case */
274 devpoll_update_events(fd,
275 COMM_SELECT_WRITE, F->write_handler);
276 }
277 else
278 libcharybdis_log("comm_select: Unhandled write event: fdmask: %x",
279 fdmask[fd]);
280
281 }
282 if(dopoll.dp_fds[i].revents & POLLNVAL)
283 {
284 libcharybdis_log("revents was Invalid for %d", fd);
285 }
286 }
287 return COMM_OK;
288 }
289 while (0);
290 /* XXX Get here, we broke! */
291 return 0;
292 }
293