]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/poll.c
[svn] - the new plan:
[irc/rqf/shadowircd.git] / libcharybdis / poll.c
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 *
25 * $Id: poll.c 390 2005-12-07 18:46:56Z nenolod $
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
42 struct _pollfd_list
43 {
44 struct pollfd pollfds[MAXCONNECTIONS];
45 int maxindex; /* highest FD number */
46 };
47
48 typedef struct _pollfd_list pollfd_list_t;
49
50 pollfd_list_t pollfd_list;
51 static void poll_update_pollfds(int, short, PF *);
52 static unsigned long last_count = 0;
53 static 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 */
61 static inline int
62 poll_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 */
81 static void
82 poll_update_pollfds(int fd, short event, PF * handler)
83 {
84 fde_t *F = &fd_table[fd];
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 */
136 void
137 init_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 */
154 void
155 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
156 void *client_data, time_t timeout)
157 {
158 fde_t *F = &fd_table[fd];
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
178 static void
179 irc_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 */
208 int
209 comm_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;
258 F = &fd_table[fd];
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