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