]> jfr.im git - irc/rqf/shadowircd.git/blame - libcharybdis/poll.c
Remove silly a2client_p, entirely pointless since User.server removal.
[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 *
efb1d086 25 * $Id: poll.c 3528 2007-07-07 08:08:23Z 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
efb1d086 131 if (F == NULL)
132 F = comm_add_fd(fd);
133
212380e3 134 if(F->comm_index < 0)
212380e3 135 F->comm_index = poll_findslot();
ce439f51 136
212380e3 137 comm_index = F->comm_index;
138
139 /* Update the events */
140 if(handler)
141 {
142 F->list = FDLIST_IDLECLIENT;
143 pollfd_list.pollfds[comm_index].events |= event;
144 pollfd_list.pollfds[comm_index].fd = fd;
145 /* update maxindex here */
146 if(comm_index > pollfd_list.maxindex)
147 pollfd_list.maxindex = comm_index;
148 }
149 else
150 {
151 if(comm_index >= 0)
152 {
153 pollfd_list.pollfds[comm_index].events &= ~event;
154 if(pollfd_list.pollfds[comm_index].events == 0)
155 {
156 pollfd_list.pollfds[comm_index].fd = -1;
157 pollfd_list.pollfds[comm_index].revents = 0;
158 F->comm_index = -1;
159 F->list = FDLIST_NONE;
160
161 /* update pollfd_list.maxindex here */
162 if(comm_index == pollfd_list.maxindex)
163 while (pollfd_list.maxindex >= 0 &&
164 pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
165 pollfd_list.maxindex--;
166 }
167 }
168 }
169}
170
171
172/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
173/* Public functions */
174
212380e3 175/*
176 * comm_setselect
177 *
178 * This is a needed exported function which will be called to register
179 * and deregister interest in a pending IO state for a given FD.
180 */
181void
182comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
183 void *client_data, time_t timeout)
184{
e70f8e92 185 fde_t *F = comm_locate_fd(fd);
212380e3 186 s_assert(fd >= 0);
187 s_assert(F->flags.open);
188
189 if(type & COMM_SELECT_READ)
190 {
191 F->read_handler = handler;
192 F->read_data = client_data;
193 poll_update_pollfds(fd, POLLRDNORM, handler);
194 }
195 if(type & COMM_SELECT_WRITE)
196 {
197 F->write_handler = handler;
198 F->write_data = client_data;
199 poll_update_pollfds(fd, POLLWRNORM, handler);
200 }
201 if(timeout)
202 F->timeout = CurrentTime + (timeout / 1000);
203}
204
205static void
206irc_sleep(unsigned long useconds)
207{
208#ifdef HAVE_NANOSLEEP
209 struct timespec t;
210 t.tv_sec = useconds / (unsigned long) 1000000;
211 t.tv_nsec = (useconds % (unsigned long) 1000000) * 1000;
212 nanosleep(&t, (struct timespec *) NULL);
213#else
214 struct timeval t;
215 t.tv_sec = 0;
216 t.tv_usec = useconds;
217 select(0, NULL, NULL, NULL, &t);
218#endif
219 return;
220}
221
222/* int comm_select_fdlist(unsigned long delay)
223 * Input: The maximum time to delay.
224 * Output: Returns -1 on error, 0 on success.
225 * Side-effects: Deregisters future interest in IO and calls the handlers
226 * if an event occurs for an FD.
227 * Comments: Check all connections for new connections and input data
228 * that is to be processed. Also check for connections with data queued
229 * and whether we can write it out.
230 * Called to do the new-style IO, courtesy of squid (like most of this
231 * new IO code). This routine handles the stuff we've hidden in
232 * comm_setselect and fd_table[] and calls callbacks for IO ready
233 * events.
234 */
235int
236comm_select(unsigned long delay)
237{
238 int num;
239 int fd;
240 int ci;
241 unsigned long ndelay;
242 PF *hdl;
243
244 if(last_count > 0)
245 {
246 empty_count = 0;
247 ndelay = 0;
248 }
249 else {
250 ndelay = ++empty_count * 15000 ;
251 if(ndelay > delay * 1000)
252 ndelay = delay * 1000;
253 }
254
255 for (;;)
256 {
257 /* XXX kill that +1 later ! -- adrian */
258 if(ndelay > 0)
259 irc_sleep(ndelay);
260 last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0);
261 if(num >= 0)
262 break;
263 if(ignoreErrno(errno))
264 continue;
265 /* error! */
266 set_time();
267 return -1;
268 /* NOTREACHED */
269 }
270
271 /* update current time again, eww.. */
272 set_time();
273
274 if(num == 0)
275 return 0;
276 /* XXX we *could* optimise by falling out after doing num fds ... */
277 for (ci = 0; ci < pollfd_list.maxindex + 1; ci++)
278 {
279 fde_t *F;
280 int revents;
281 if(((revents = pollfd_list.pollfds[ci].revents) == 0) ||
282 (pollfd_list.pollfds[ci].fd) == -1)
283 continue;
284 fd = pollfd_list.pollfds[ci].fd;
e70f8e92 285 F = comm_locate_fd(fd);
212380e3 286 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
287 {
288 hdl = F->read_handler;
289 F->read_handler = NULL;
290 poll_update_pollfds(fd, POLLRDNORM, NULL);
291 if(hdl)
292 hdl(fd, F->read_data);
293 }
294 if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
295 {
296 hdl = F->write_handler;
297 F->write_handler = NULL;
298 poll_update_pollfds(fd, POLLWRNORM, NULL);
299 if(hdl)
300 hdl(fd, F->write_data);
301 }
302 }
303 return 0;
304}
305