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