]> jfr.im git - irc/rqf/shadowircd.git/blame - libcharybdis/poll.c
[svn] - remove ALL braindead 2.8 I/O artifacts: MASTER_MAX, HARD_FDLIMIT, HARD_FDLIMI...
[irc/rqf/shadowircd.git] / libcharybdis / poll.c
CommitLineData
212380e3 1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_bsd_poll.c: POSIX 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 *
6fcb8629 25 * $Id: poll.c 3354 2007-04-03 09:21:31Z nenolod $
212380e3 26 */
27
28#include "config.h"
29#include "stdinc.h"
30#include <sys/poll.h>
31
32#include "libcharybdis.h"
33
34/* I hate linux -- adrian */
35#ifndef POLLRDNORM
36#define POLLRDNORM POLLIN
37#endif
38#ifndef POLLWRNORM
39#define POLLWRNORM POLLOUT
40#endif
41
42struct _pollfd_list
43{
ce439f51 44 struct pollfd *pollfds;
212380e3 45 int maxindex; /* highest FD number */
ce439f51 46 int allocated;
212380e3 47};
48
49typedef struct _pollfd_list pollfd_list_t;
50
51pollfd_list_t pollfd_list;
52static void poll_update_pollfds(int, short, PF *);
53static unsigned long last_count = 0;
54static unsigned long empty_count = 0;
ce439f51 55
56/*
57 * init_netio
58 *
59 * This is a needed exported function which will be called to initialise
60 * the network loop code.
61 */
62void
63init_netio(void)
64{
65 int fd;
6fcb8629 66 int maxconn = comm_get_maxconnections();
ce439f51 67
6fcb8629 68 pollfd_list.pollfds = calloc(sizeof(struct pollfd), maxconn);
ce439f51 69
6fcb8629 70 for (fd = 0; fd < maxconn; fd++)
ce439f51 71 pollfd_list.pollfds[fd].fd = -1;
72
73 pollfd_list.maxindex = 0;
6fcb8629 74 pollfd_list.allocated = maxconn;
ce439f51 75}
76
77static inline void
78resize_poll_array(int fd)
79{
80 int i, old_value = pollfd_list.allocated;
81
82 if (fd < pollfd_list.allocated)
83 return;
84
85 pollfd_list.allocated += 1024;
86 pollfd_list.pollfds = MyRealloc(pollfd_list.pollfds, pollfd_list.allocated * sizeof(struct pollfd));
87
88 /* because realloced memory can contain junk, we have to zero it out. */
89 memset(&pollfd_list.pollfds[old_value+1], 0, sizeof(struct pollfd) * 1024);
90
91 for (i = old_value + 1; i <= pollfd_list.allocated; i++)
92 pollfd_list.pollfds[i].fd = -1;
93}
94
212380e3 95/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
96/* Private functions */
97
98/*
99 * find a spare slot in the fd list. We can optimise this out later!
100 * -- adrian
101 */
102static inline int
103poll_findslot(void)
104{
105 int i;
ce439f51 106 for (i = 0; i < pollfd_list.allocated; i++)
212380e3 107 {
108 if(pollfd_list.pollfds[i].fd == -1)
109 {
110 /* MATCH!!#$*&$ */
111 return i;
112 }
113 }
ce439f51 114
212380e3 115 s_assert(1 == 0);
116 /* NOTREACHED */
117 return -1;
118}
119
120/*
121 * set and clear entries in the pollfds[] array.
122 */
123static void
124poll_update_pollfds(int fd, short event, PF * handler)
125{
c18de29d 126 fde_t *F = comm_locate_fd(fd);
212380e3 127 int comm_index;
128
ce439f51 129 resize_poll_array(fd);
130
212380e3 131 if(F->comm_index < 0)
212380e3 132 F->comm_index = poll_findslot();
ce439f51 133
212380e3 134 comm_index = F->comm_index;
135
136 /* Update the events */
137 if(handler)
138 {
139 F->list = FDLIST_IDLECLIENT;
140 pollfd_list.pollfds[comm_index].events |= event;
141 pollfd_list.pollfds[comm_index].fd = fd;
142 /* update maxindex here */
143 if(comm_index > pollfd_list.maxindex)
144 pollfd_list.maxindex = comm_index;
145 }
146 else
147 {
148 if(comm_index >= 0)
149 {
150 pollfd_list.pollfds[comm_index].events &= ~event;
151 if(pollfd_list.pollfds[comm_index].events == 0)
152 {
153 pollfd_list.pollfds[comm_index].fd = -1;
154 pollfd_list.pollfds[comm_index].revents = 0;
155 F->comm_index = -1;
156 F->list = FDLIST_NONE;
157
158 /* update pollfd_list.maxindex here */
159 if(comm_index == pollfd_list.maxindex)
160 while (pollfd_list.maxindex >= 0 &&
161 pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
162 pollfd_list.maxindex--;
163 }
164 }
165 }
166}
167
168
169/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
170/* Public functions */
171
212380e3 172/*
173 * comm_setselect
174 *
175 * This is a needed exported function which will be called to register
176 * and deregister interest in a pending IO state for a given FD.
177 */
178void
179comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
180 void *client_data, time_t timeout)
181{
e70f8e92 182 fde_t *F = comm_locate_fd(fd);
212380e3 183 s_assert(fd >= 0);
184 s_assert(F->flags.open);
185
186 if(type & COMM_SELECT_READ)
187 {
188 F->read_handler = handler;
189 F->read_data = client_data;
190 poll_update_pollfds(fd, POLLRDNORM, handler);
191 }
192 if(type & COMM_SELECT_WRITE)
193 {
194 F->write_handler = handler;
195 F->write_data = client_data;
196 poll_update_pollfds(fd, POLLWRNORM, handler);
197 }
198 if(timeout)
199 F->timeout = CurrentTime + (timeout / 1000);
200}
201
202static void
203irc_sleep(unsigned long useconds)
204{
205#ifdef HAVE_NANOSLEEP
206 struct timespec t;
207 t.tv_sec = useconds / (unsigned long) 1000000;
208 t.tv_nsec = (useconds % (unsigned long) 1000000) * 1000;
209 nanosleep(&t, (struct timespec *) NULL);
210#else
211 struct timeval t;
212 t.tv_sec = 0;
213 t.tv_usec = useconds;
214 select(0, NULL, NULL, NULL, &t);
215#endif
216 return;
217}
218
219/* int comm_select_fdlist(unsigned long delay)
220 * Input: The maximum time to delay.
221 * Output: Returns -1 on error, 0 on success.
222 * Side-effects: Deregisters future interest in IO and calls the handlers
223 * if an event occurs for an FD.
224 * Comments: Check all connections for new connections and input data
225 * that is to be processed. Also check for connections with data queued
226 * and whether we can write it out.
227 * Called to do the new-style IO, courtesy of squid (like most of this
228 * new IO code). This routine handles the stuff we've hidden in
229 * comm_setselect and fd_table[] and calls callbacks for IO ready
230 * events.
231 */
232int
233comm_select(unsigned long delay)
234{
235 int num;
236 int fd;
237 int ci;
238 unsigned long ndelay;
239 PF *hdl;
240
241 if(last_count > 0)
242 {
243 empty_count = 0;
244 ndelay = 0;
245 }
246 else {
247 ndelay = ++empty_count * 15000 ;
248 if(ndelay > delay * 1000)
249 ndelay = delay * 1000;
250 }
251
252 for (;;)
253 {
254 /* XXX kill that +1 later ! -- adrian */
255 if(ndelay > 0)
256 irc_sleep(ndelay);
257 last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0);
258 if(num >= 0)
259 break;
260 if(ignoreErrno(errno))
261 continue;
262 /* error! */
263 set_time();
264 return -1;
265 /* NOTREACHED */
266 }
267
268 /* update current time again, eww.. */
269 set_time();
270
271 if(num == 0)
272 return 0;
273 /* XXX we *could* optimise by falling out after doing num fds ... */
274 for (ci = 0; ci < pollfd_list.maxindex + 1; ci++)
275 {
276 fde_t *F;
277 int revents;
278 if(((revents = pollfd_list.pollfds[ci].revents) == 0) ||
279 (pollfd_list.pollfds[ci].fd) == -1)
280 continue;
281 fd = pollfd_list.pollfds[ci].fd;
e70f8e92 282 F = comm_locate_fd(fd);
212380e3 283 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
284 {
285 hdl = F->read_handler;
286 F->read_handler = NULL;
287 poll_update_pollfds(fd, POLLRDNORM, NULL);
288 if(hdl)
289 hdl(fd, F->read_data);
290 }
291 if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
292 {
293 hdl = F->write_handler;
294 F->write_handler = NULL;
295 poll_update_pollfds(fd, POLLWRNORM, NULL);
296 if(hdl)
297 hdl(fd, F->write_data);
298 }
299 }
300 return 0;
301}
302