]> jfr.im git - irc/rqf/shadowircd.git/blame - libcharybdis/devpoll.c
[svn] - use a hashtable for fdlist storage. first step to making the amount of allowe...
[irc/rqf/shadowircd.git] / libcharybdis / devpoll.c
CommitLineData
212380e3 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 *
e70f8e92 25 * $Id: devpoll.c 3229 2007-03-05 17:23:07Z nenolod $
212380e3 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
38static void devpoll_update_events(int, short, PF *);
39static int dpfd;
40static short fdmask[POLL_LENGTH];
41static void devpoll_update_events(int, short, PF *);
42static 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 */
55static void
56devpoll_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
73void
74devpoll_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;
e70f8e92 80 fde_t *F = comm_locate_fd(fd);
81
212380e3 82 switch (filter)
83 {
84 case COMM_SELECT_READ:
e70f8e92 85 cur_handler = F->read_handler;
212380e3 86 if(handler)
87 fdmask[fd] |= POLLRDNORM;
88 else
89 fdmask[fd] &= ~POLLRDNORM;
e70f8e92 90 if(F->write_handler)
212380e3 91 fdmask[fd] |= POLLWRNORM;
92 break;
93 case COMM_SELECT_WRITE:
e70f8e92 94 cur_handler = F->write_handler;
212380e3 95 if(handler)
96 fdmask[fd] |= POLLWRNORM;
97 else
98 fdmask[fd] &= ~POLLWRNORM;
e70f8e92 99 if(F->read_handler)
212380e3 100 fdmask[fd] |= POLLRDNORM;
101 break;
102 default:
103#ifdef NOTYET
104 libcharybdis_log("devpoll_update_events called with unknown filter: %hd", filter);
105#endif
106 return;
107 break;
108 }
109
110 if(cur_handler == NULL && handler != NULL)
111 update_required++;
112 else if(cur_handler != NULL && handler == NULL)
113 update_required++;
114 if(cur_mask != fdmask[fd])
115 update_required++;
116 if(update_required)
117 {
118 /*
119 * Ok, we can call devpoll_write_update() here now to re-build the
120 * fd struct. If we end up with nothing on this fd, it won't write
121 * anything.
122 */
123 if(fdmask[fd])
124 {
125 devpoll_write_update(fd, POLLREMOVE);
126 devpoll_write_update(fd, fdmask[fd]);
127 }
128 else
129 devpoll_write_update(fd, POLLREMOVE);
130 }
131}
132
133
134
135
136
137/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
138/* Public functions */
139
140
141/*
142 * init_netio
143 *
144 * This is a needed exported function which will be called to initialise
145 * the network loop code.
146 */
147void
148init_netio(void)
149{
150 memset(&fdmask, 0, sizeof(fdmask));
151 dpfd = open("/dev/poll", O_RDWR);
152 if(dpfd < 0)
153 {
154 fprintf(stderr,
155 "init_netio: Couldn't open /dev/poll - %d: %s\n",
156 errno, strerror(errno));
157 exit(115); /* Whee! */
158 }
159}
160
161/*
162 * comm_setselect
163 *
164 * This is a needed exported function which will be called to register
165 * and deregister interest in a pending IO state for a given FD.
166 */
167void
168comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
169 void *client_data, time_t timeout)
170{
e70f8e92 171 fde_t *F = comm_locate_fd(fd);
212380e3 172 s_assert(fd >= 0);
173 s_assert(F->flags.open);
174
175 /* Update the list, even though we're not using it .. */
176 F->list = list;
177
178 if(type & COMM_SELECT_READ)
179 {
180 devpoll_update_events(fd, COMM_SELECT_READ, handler);
181 F->read_handler = handler;
182 F->read_data = client_data;
183 }
184 if(type & COMM_SELECT_WRITE)
185 {
186 devpoll_update_events(fd, COMM_SELECT_WRITE, handler);
187 F->write_handler = handler;
188 F->write_data = client_data;
189 }
190 if(timeout)
191 F->timeout = CurrentTime + (timeout / 1000);
192}
193
194/*
195 * Check all connections for new connections and input data that is to be
196 * processed. Also check for connections with data queued and whether we can
197 * write it out.
198 */
199
200/*
201 * comm_select
202 *
203 * Called to do the new-style IO, courtesy of squid (like most of this
204 * new IO code). This routine handles the stuff we've hidden in
205 * comm_setselect and fd_table[] and calls callbacks for IO ready
206 * events.
207 */
208
209int
210comm_select(unsigned long delay)
211{
212 int num, i;
213 struct pollfd pollfds[POLL_LENGTH];
214 struct dvpoll dopoll;
215
216 do
217 {
218 for (;;)
219 {
220 dopoll.dp_timeout = delay;
221 dopoll.dp_nfds = POLL_LENGTH;
222 dopoll.dp_fds = &pollfds[0];
223 num = ioctl(dpfd, DP_POLL, &dopoll);
224 if(num >= 0)
225 break;
226 if(ignoreErrno(errno))
227 break;
228 set_time();
229 return COMM_ERROR;
230 }
231
232 set_time();
233 if(num == 0)
234 continue;
235
236 for (i = 0; i < num; i++)
237 {
238 int fd = dopoll.dp_fds[i].fd;
239 PF *hdl = NULL;
e70f8e92 240 fde_t *F = comm_locate_fd(fd);
212380e3 241 if((dopoll.dp_fds[i].
242 revents & (POLLRDNORM | POLLIN | POLLHUP |
243 POLLERR))
244 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
245 {
246 if((hdl = F->read_handler) != NULL)
247 {
248 F->read_handler = NULL;
249 hdl(fd, F->read_data);
250 /*
251 * this call used to be with a NULL pointer, BUT
252 * in the devpoll case we only want to update the
253 * poll set *if* the handler changes state (active ->
254 * NULL or vice versa.)
255 */
256 devpoll_update_events(fd,
257 COMM_SELECT_READ, F->read_handler);
258 }
259 else
260 libcharybdis_log("comm_select: Unhandled read event: fdmask: %x",
261 fdmask[fd]);
262 }
263
264 if(F->flags.open == 0)
265 continue; /* Read handler closed us..go on to do something more useful */
266 if((dopoll.dp_fds[i].
267 revents & (POLLWRNORM | POLLOUT | POLLHUP |
268 POLLERR))
269 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
270 {
271 if((hdl = F->write_handler) != NULL)
272 {
273 F->write_handler = NULL;
274 hdl(fd, F->write_data);
275 /* See above similar code in the read case */
276 devpoll_update_events(fd,
277 COMM_SELECT_WRITE, F->write_handler);
278 }
279 else
280 libcharybdis_log("comm_select: Unhandled write event: fdmask: %x",
281 fdmask[fd]);
282
283 }
284 if(dopoll.dp_fds[i].revents & POLLNVAL)
285 {
286 libcharybdis_log("revents was Invalid for %d", fd);
287 }
288 }
289 return COMM_OK;
290 }
291 while (0);
292 /* XXX Get here, we broke! */
293 return 0;
294}
295