]> jfr.im git - irc/rqf/shadowircd.git/blob - libratbox/src/devpoll.c
Copied libratbox and related stuff from shadowircd upstream.
[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 26092 2008-09-19 15:13:52Z 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,
72 strerror(errno));
73 /* Done! */
74 }
75
76 static void
77 devpoll_update_events(int fd, short filter, PF * handler)
78 {
79 int update_required = 0;
80 int cur_mask = fdmask[fd];
81 PF *cur_handler;
82
83 fdmask[fd] = 0;
84 switch (filter)
85 {
86 case RB_SELECT_READ:
87 cur_handler = F->read_handler;
88 if(handler)
89 fdmask[fd] |= POLLRDNORM;
90 else
91 fdmask[fd] &= ~POLLRDNORM;
92 if(F->write_handler)
93 fdmask[fd] |= POLLWRNORM;
94 break;
95 case RB_SELECT_WRITE:
96 cur_handler = F->write_handler;
97 if(handler)
98 fdmask[fd] |= POLLWRNORM;
99 else
100 fdmask[fd] &= ~POLLWRNORM;
101 if(F->read_handler)
102 fdmask[fd] |= POLLRDNORM;
103 break;
104 default:
105 return;
106 break;
107 }
108
109 if(cur_handler == NULL && handler != NULL)
110 update_required++;
111 else if(cur_handler != NULL && handler == NULL)
112 update_required++;
113 if(cur_mask != fdmask[fd])
114 update_required++;
115 if(update_required)
116 {
117 /*
118 * Ok, we can call devpoll_write_update() here now to re-build the
119 * fd struct. If we end up with nothing on this fd, it won't write
120 * anything.
121 */
122 if(fdmask[fd])
123 {
124 devpoll_write_update(fd, POLLREMOVE);
125 devpoll_write_update(fd, fdmask[fd]);
126 }
127 else
128 devpoll_write_update(fd, POLLREMOVE);
129 }
130 }
131
132
133
134
135
136 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
137 /* Public functions */
138
139
140 /*
141 * rb_init_netio
142 *
143 * This is a needed exported function which will be called to initialise
144 * the network loop code.
145 */
146 int
147 rb_init_netio_devpoll(void)
148 {
149 dpfd = open("/dev/poll", O_RDWR);
150 if(dpfd < 0)
151 {
152 return errno;
153 }
154 maxfd = getdtablesize() - 2; /* This makes more sense than HARD_FDLIMIT */
155 fdmask = rb_malloc(sizeof(fdmask) * maxfd + 1);
156 rb_open(dpfd, RB_FD_UNKNOWN, "/dev/poll file descriptor");
157 }
158
159 /*
160 * rb_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 rb_setselect_devpoll(rb_fde_t *F, unsigned int type, PF * handler, 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].revents & (POLLRDNORM | POLLIN | POLLHUP |
232 POLLERR))
233 && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
234 {
235 if((hdl = F->read_handler) != NULL)
236 {
237 F->read_handler = NULL;
238 hdl(F, F->read_data);
239 /*
240 * this call used to be with a NULL pointer, BUT
241 * in the devpoll case we only want to update the
242 * poll set *if* the handler changes state (active ->
243 * NULL or vice versa.)
244 */
245 devpoll_update_events(fd, RB_SELECT_READ, F->read_handler);
246 }
247 }
248
249 if(!IsFDOpen(F))
250 continue; /* Read handler closed us..go on to do something more useful */
251 if((dopoll.dp_fds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP |
252 POLLERR))
253 && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
254 {
255 if((hdl = F->write_handler) != NULL)
256 {
257 F->write_handler = NULL;
258 hdl(F, F->write_data);
259 /* See above similar code in the read case */
260 devpoll_update_events(fd,
261 RB_SELECT_WRITE, F->write_handler);
262 }
263
264 }
265 }
266 return RB_OK;
267 }
268 while(0);
269 /* XXX Get here, we broke! */
270 return 0;
271 }
272
273 #else /* /dev/poll not supported */
274 int
275 rb_init_netio_devpoll(void)
276 {
277 return ENOSYS;
278 }
279
280 void
281 rb_setselect_devpoll(rb_fde_t *F, unsigned int type, PF * handler, void *client_data)
282 {
283 errno = ENOSYS;
284 return;
285 }
286
287 int
288 rb_select_devpoll(long delay)
289 {
290 errno = ENOSYS;
291 return -1;
292 }
293
294 int
295 rb_setup_fd_devpoll(rb_fde_t *F)
296 {
297 errno = ENOSYS;
298 return -1;
299 }
300 #endif