Clean a bit - to be continued...
[seven-1.x.git] / libseven / poll.c
blob799f4acd056282dcb5a31a4e87d7a380f1b23d04
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * s_bsd_poll.c: POSIX poll() compatible network routines.
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
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.
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.
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
27 #include "config.h"
28 #include "stdinc.h"
29 #include <sys/poll.h>
31 #include "libseven.h"
33 /* I hate linux -- adrian */
34 #ifndef POLLRDNORM
35 #define POLLRDNORM POLLIN
36 #endif
37 #ifndef POLLWRNORM
38 #define POLLWRNORM POLLOUT
39 #endif
41 struct _pollfd_list
43 struct pollfd pollfds[MAXCONNECTIONS];
44 int maxindex; /* highest FD number */
47 typedef struct _pollfd_list pollfd_list_t;
49 pollfd_list_t pollfd_list;
50 static void poll_update_pollfds(int, short, PF *);
51 static unsigned long last_count = 0;
52 static unsigned long empty_count = 0;
53 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
54 /* Private functions */
57 * find a spare slot in the fd list. We can optimise this out later!
58 * -- adrian
60 static inline int
61 poll_findslot(void)
63 int i;
64 for (i = 0; i < MAXCONNECTIONS; i++)
66 if(pollfd_list.pollfds[i].fd == -1)
68 /* MATCH!!#$*&$ */
69 return i;
72 s_assert(1 == 0);
73 /* NOTREACHED */
74 return -1;
78 * set and clear entries in the pollfds[] array.
80 static void
81 poll_update_pollfds(int fd, short event, PF * handler)
83 fde_t *F = &fd_table[fd];
84 int comm_index;
86 if(F->comm_index < 0)
88 F->comm_index = poll_findslot();
90 comm_index = F->comm_index;
92 /* Update the events */
93 if(handler)
95 F->list = FDLIST_IDLECLIENT;
96 pollfd_list.pollfds[comm_index].events |= event;
97 pollfd_list.pollfds[comm_index].fd = fd;
98 /* update maxindex here */
99 if(comm_index > pollfd_list.maxindex)
100 pollfd_list.maxindex = comm_index;
102 else
104 if(comm_index >= 0)
106 pollfd_list.pollfds[comm_index].events &= ~event;
107 if(pollfd_list.pollfds[comm_index].events == 0)
109 pollfd_list.pollfds[comm_index].fd = -1;
110 pollfd_list.pollfds[comm_index].revents = 0;
111 F->comm_index = -1;
112 F->list = FDLIST_NONE;
114 /* update pollfd_list.maxindex here */
115 if(comm_index == pollfd_list.maxindex)
116 while (pollfd_list.maxindex >= 0 &&
117 pollfd_list.pollfds[pollfd_list.maxindex].fd == -1)
118 pollfd_list.maxindex--;
125 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
126 /* Public functions */
130 * init_netio
132 * This is a needed exported function which will be called to initialise
133 * the network loop code.
135 void
136 init_netio(void)
138 int fd;
140 for (fd = 0; fd < MAXCONNECTIONS; fd++)
142 pollfd_list.pollfds[fd].fd = -1;
144 pollfd_list.maxindex = 0;
148 * comm_setselect
150 * This is a needed exported function which will be called to register
151 * and deregister interest in a pending IO state for a given FD.
153 void
154 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
155 void *client_data, time_t timeout)
157 fde_t *F = &fd_table[fd];
158 s_assert(fd >= 0);
159 s_assert(F->flags.open);
161 if(type & COMM_SELECT_READ)
163 F->read_handler = handler;
164 F->read_data = client_data;
165 poll_update_pollfds(fd, POLLRDNORM, handler);
167 if(type & COMM_SELECT_WRITE)
169 F->write_handler = handler;
170 F->write_data = client_data;
171 poll_update_pollfds(fd, POLLWRNORM, handler);
173 if(timeout)
174 F->timeout = CurrentTime + (timeout / 1000);
177 static void
178 irc_sleep(unsigned long useconds)
180 #ifdef HAVE_NANOSLEEP
181 struct timespec t;
182 t.tv_sec = useconds / (unsigned long) 1000000;
183 t.tv_nsec = (useconds % (unsigned long) 1000000) * 1000;
184 nanosleep(&t, (struct timespec *) NULL);
185 #else
186 struct timeval t;
187 t.tv_sec = 0;
188 t.tv_usec = useconds;
189 select(0, NULL, NULL, NULL, &t);
190 #endif
191 return;
194 /* int comm_select_fdlist(unsigned long delay)
195 * Input: The maximum time to delay.
196 * Output: Returns -1 on error, 0 on success.
197 * Side-effects: Deregisters future interest in IO and calls the handlers
198 * if an event occurs for an FD.
199 * Comments: Check all connections for new connections and input data
200 * that is to be processed. Also check for connections with data queued
201 * and whether we can write it out.
202 * Called to do the new-style IO, courtesy of squid (like most of this
203 * new IO code). This routine handles the stuff we've hidden in
204 * comm_setselect and fd_table[] and calls callbacks for IO ready
205 * events.
208 comm_select(unsigned long delay)
210 int num;
211 int fd;
212 int ci;
213 unsigned long ndelay;
214 PF *hdl;
216 if(last_count > 0)
218 empty_count = 0;
219 ndelay = 0;
221 else {
222 ndelay = ++empty_count * 15000 ;
223 if(ndelay > delay * 1000)
224 ndelay = delay * 1000;
227 for (;;)
229 /* XXX kill that +1 later ! -- adrian */
230 if(ndelay > 0)
231 irc_sleep(ndelay);
232 last_count = num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, 0);
233 if(num >= 0)
234 break;
235 if(ignoreErrno(errno))
236 continue;
237 /* error! */
238 set_time();
239 return -1;
240 /* NOTREACHED */
243 /* update current time again, eww.. */
244 set_time();
246 if(num == 0)
247 return 0;
248 /* XXX we *could* optimise by falling out after doing num fds ... */
249 for (ci = 0; ci < pollfd_list.maxindex + 1; ci++)
251 fde_t *F;
252 int revents;
253 if(((revents = pollfd_list.pollfds[ci].revents) == 0) ||
254 (pollfd_list.pollfds[ci].fd) == -1)
255 continue;
256 fd = pollfd_list.pollfds[ci].fd;
257 F = &fd_table[fd];
258 if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR))
260 hdl = F->read_handler;
261 F->read_handler = NULL;
262 poll_update_pollfds(fd, POLLRDNORM, NULL);
263 if(hdl)
264 hdl(fd, F->read_data);
266 if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))
268 hdl = F->write_handler;
269 F->write_handler = NULL;
270 poll_update_pollfds(fd, POLLWRNORM, NULL);
271 if(hdl)
272 hdl(fd, F->write_data);
275 return 0;