]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/devpoll.c
162130fedd6f06843b1c47467412300d5ab79c1c
[irc/rqf/shadowircd.git] / libratbox / src / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
23 * USA
24 *
25 * $Id: devpoll.c 25038 2008-01-23 16:03:08Z androsyn $
26 */
27 #include <libratbox_config.h>
28 #include <ratbox_lib.h>
29 #include <commio-int.h>
30 #include <fcntl.h>
31
32 #if defined(HAVE_DEVPOLL) && (HAVE_DEVPOLL_H)
33 #include <sys/devpoll.h>
34
35
36 static void devpoll_update_events(int, short, PF *);
37 static int dpfd;
38 static int maxfd;
39 static short *fdmask;
40 static void devpoll_update_events(int, short, PF *);
41 static void devpoll_write_update(int, int);
42
43
44 int
45 rb_setup_fd_devpoll(rb_fde_t *F)
46 {
47 return 0;
48 }
49
50
51 /*
52 * Write an update to the devpoll filter.
53 * See, we end up having to do a seperate (?) remove before we do an
54 * add of a new polltype, so we have to have this function seperate from
55 * the others.
56 */
57 static void
58 devpoll_write_update(int fd, int events)
59 {
60 struct pollfd pollfds[1]; /* Just to be careful */
61 int retval;
62
63 /* Build the pollfd entry */
64 pollfds[0].revents = 0;
65 pollfds[0].fd = fd;
66 pollfds[0].events = events;
67
68 /* Write the thing to our poll fd */
69 retval = write(dpfd, &pollfds[0], sizeof(struct pollfd));
70 if(retval != sizeof(struct pollfd))
71 rb_lib_log("devpoll_write_update: dpfd write failed %d: %s", errno, strerror(errno));
72 /* Done! */
73 }
74
75 static void
76 devpoll_update_events(int fd, short filter, PF * handler)
77 {
78 int update_required = 0;
79 int cur_mask = fdmask[fd];
80 PF *cur_handler;
81
82 fdmask[fd] = 0;
83 switch (filter)
84 {
85 case RB_SELECT_READ:
86 cur_handler = F->read_handler;
87 if(handler)
88 fdmask[fd] |= POLLRDNORM;
89 else
90 fdmask[fd] &= ~POLLRDNORM;
91 if(F->write_handler)
92 fdmask[fd] |= POLLWRNORM;
93 break;
94 case RB_SELECT_WRITE:
95 cur_handler = F->write_handler;
96 if(handler)
97 fdmask[fd] |= POLLWRNORM;
98 else
99 fdmask[fd] &= ~POLLWRNORM;
100 if(F->read_handler)
101 fdmask[fd] |= POLLRDNORM;
102 break;
103 default:
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 * rb_init_netio
141 *
142 * This is a needed exported function which will be called to initialise
143 * the network loop code.
144 */
145 int
146 rb_init_netio_devpoll(void)
147 {
148 dpfd = open("/dev/poll", O_RDWR);
149 if(dpfd < 0)
150 {
151 return errno;
152 }
153 maxfd = getdtablesize() - 2; /* This makes more sense than HARD_FDLIMIT */
154 fdmask = rb_malloc(sizeof(fdmask) * maxfd + 1);
155 rb_open(dpfd, RB_FD_UNKNOWN, "/dev/poll file descriptor");
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_devpoll(rb_fde_t *F, unsigned int type, PF * handler,
166 void *client_data)
167 {
168 lrb_assert(IsFDOpen(F));
169
170 if(type & RB_SELECT_READ)
171 {
172 devpoll_update_events(fd, RB_SELECT_READ, handler);
173 F->read_handler = handler;
174 F->read_data = client_data;
175 }
176 if(type & RB_SELECT_WRITE)
177 {
178 devpoll_update_events(fd, RB_SELECT_WRITE, handler);
179 F->write_handler = handler;
180 F->write_data = client_data;
181 }
182 }
183
184 /*
185 * Check all connections for new connections and input data that is to be
186 * processed. Also check for connections with data queued and whether we can
187 * write it out.
188 */
189
190 /*
191 * rb_select
192 *
193 * Called to do the new-style IO, courtesy of squid (like most of this
194 * new IO code). This routine handles the stuff we've hidden in
195 * rb_setselect and fd_table[] and calls callbacks for IO ready
196 * events.
197 */
198
199 int
200 rb_select_devpoll(long delay)
201 {
202 int num, i;
203 struct pollfd pollfds[maxfd];
204 struct dvpoll dopoll;
205
206 do
207 {
208 for (;;)
209 {
210 dopoll.dp_timeout = delay;
211 dopoll.dp_nfds = maxfd;
212 dopoll.dp_fds = &pollfds[0];
213 num = ioctl(dpfd, DP_POLL, &dopoll);
214 if(num >= 0)
215 break;
216 if(rb_ignore_errno(errno))
217 break;
218 rb_set_time();
219 return RB_ERROR;
220 }
221
222 rb_set_time();
223 if(num == 0)
224 continue;
225
226 for (i = 0; i < num; i++)
227 {
228 int fd = dopoll.dp_fds[i].fd;
229 PF *hdl = NULL;
230 rb_fde_t *F = rb_find_fd(fd);
231 if((dopoll.dp_fds[i].
232 revents & (POLLRDNORM | POLLIN | POLLHUP |
233 POLLERR))
234 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
235 {
236 if((hdl = F->read_handler) != NULL)
237 {
238 F->read_handler = NULL;
239 hdl(F, F->read_data);
240 /*
241 * this call used to be with a NULL pointer, BUT
242 * in the devpoll case we only want to update the
243 * poll set *if* the handler changes state (active ->
244 * NULL or vice versa.)
245 */
246 devpoll_update_events(fd,
247 RB_SELECT_READ, F->read_handler);
248 }
249 }
250
251 if(!IsFDOpen(F))
252 continue; /* Read handler closed us..go on to do something more useful */
253 if((dopoll.dp_fds[i].
254 revents & (POLLWRNORM | POLLOUT | POLLHUP |
255 POLLERR))
256 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
257 {
258 if((hdl = F->write_handler) != NULL)
259 {
260 F->write_handler = NULL;
261 hdl(F, F->write_data);
262 /* See above similar code in the read case */
263 devpoll_update_events(fd,
264 RB_SELECT_WRITE, F->write_handler);
265 }
266
267 }
268 }
269 return RB_OK;
270 }
271 while (0);
272 /* XXX Get here, we broke! */
273 return 0;
274 }
275
276 #else /* /dev/poll not supported */
277 int
278 rb_init_netio_devpoll(void)
279 {
280 return ENOSYS;
281 }
282
283 void
284 rb_setselect_devpoll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
285 {
286 errno = ENOSYS;
287 return;
288 }
289
290 int
291 rb_select_devpoll(long delay)
292 {
293 errno = ENOSYS;
294 return -1;
295 }
296
297 int
298 rb_setup_fd_devpoll(rb_fde_t *F)
299 {
300 errno = ENOSYS;
301 return -1;
302 }
303 #endif
304