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
25 * $Id: poll.c 3354 2007-04-03 09:21:31Z nenolod $
32 #include "libcharybdis.h"
34 /* I hate linux -- adrian */
36 #define POLLRDNORM POLLIN
39 #define POLLWRNORM POLLOUT
44 struct pollfd
*pollfds
;
45 int maxindex
; /* highest FD number */
49 typedef struct _pollfd_list pollfd_list_t
;
51 pollfd_list_t pollfd_list
;
52 static void poll_update_pollfds(int, short, PF
*);
53 static unsigned long last_count
= 0;
54 static unsigned long empty_count
= 0;
59 * This is a needed exported function which will be called to initialise
60 * the network loop code.
66 int maxconn
= comm_get_maxconnections();
68 pollfd_list
.pollfds
= calloc(sizeof(struct pollfd
), maxconn
);
70 for (fd
= 0; fd
< maxconn
; fd
++)
71 pollfd_list
.pollfds
[fd
].fd
= -1;
73 pollfd_list
.maxindex
= 0;
74 pollfd_list
.allocated
= maxconn
;
78 resize_poll_array(int fd
)
80 int i
, old_value
= pollfd_list
.allocated
;
82 if (fd
< pollfd_list
.allocated
)
85 pollfd_list
.allocated
+= 1024;
86 pollfd_list
.pollfds
= MyRealloc(pollfd_list
.pollfds
, pollfd_list
.allocated
* sizeof(struct pollfd
));
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);
91 for (i
= old_value
+ 1; i
<= pollfd_list
.allocated
; i
++)
92 pollfd_list
.pollfds
[i
].fd
= -1;
95 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
96 /* Private functions */
99 * find a spare slot in the fd list. We can optimise this out later!
106 for (i
= 0; i
< pollfd_list
.allocated
; i
++)
108 if(pollfd_list
.pollfds
[i
].fd
== -1)
121 * set and clear entries in the pollfds[] array.
124 poll_update_pollfds(int fd
, short event
, PF
* handler
)
126 fde_t
*F
= comm_locate_fd(fd
);
129 resize_poll_array(fd
);
131 if(F
->comm_index
< 0)
132 F
->comm_index
= poll_findslot();
134 comm_index
= F
->comm_index
;
136 /* Update the events */
139 F
->list
= FDLIST_IDLECLIENT
;
140 pollfd_list
.pollfds
[comm_index
].events
|= event
;
141 pollfd_list
.pollfds
[comm_index
].fd
= fd
;
142 /* update maxindex here */
143 if(comm_index
> pollfd_list
.maxindex
)
144 pollfd_list
.maxindex
= comm_index
;
150 pollfd_list
.pollfds
[comm_index
].events
&= ~event
;
151 if(pollfd_list
.pollfds
[comm_index
].events
== 0)
153 pollfd_list
.pollfds
[comm_index
].fd
= -1;
154 pollfd_list
.pollfds
[comm_index
].revents
= 0;
156 F
->list
= FDLIST_NONE
;
158 /* update pollfd_list.maxindex here */
159 if(comm_index
== pollfd_list
.maxindex
)
160 while (pollfd_list
.maxindex
>= 0 &&
161 pollfd_list
.pollfds
[pollfd_list
.maxindex
].fd
== -1)
162 pollfd_list
.maxindex
--;
169 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
170 /* Public functions */
175 * This is a needed exported function which will be called to register
176 * and deregister interest in a pending IO state for a given FD.
179 comm_setselect(int fd
, fdlist_t list
, unsigned int type
, PF
* handler
,
180 void *client_data
, time_t timeout
)
182 fde_t
*F
= comm_locate_fd(fd
);
184 s_assert(F
->flags
.open
);
186 if(type
& COMM_SELECT_READ
)
188 F
->read_handler
= handler
;
189 F
->read_data
= client_data
;
190 poll_update_pollfds(fd
, POLLRDNORM
, handler
);
192 if(type
& COMM_SELECT_WRITE
)
194 F
->write_handler
= handler
;
195 F
->write_data
= client_data
;
196 poll_update_pollfds(fd
, POLLWRNORM
, handler
);
199 F
->timeout
= CurrentTime
+ (timeout
/ 1000);
203 irc_sleep(unsigned long useconds
)
205 #ifdef HAVE_NANOSLEEP
207 t
.tv_sec
= useconds
/ (unsigned long) 1000000;
208 t
.tv_nsec
= (useconds
% (unsigned long) 1000000) * 1000;
209 nanosleep(&t
, (struct timespec
*) NULL
);
213 t
.tv_usec
= useconds
;
214 select(0, NULL
, NULL
, NULL
, &t
);
219 /* int comm_select_fdlist(unsigned long delay)
220 * Input: The maximum time to delay.
221 * Output: Returns -1 on error, 0 on success.
222 * Side-effects: Deregisters future interest in IO and calls the handlers
223 * if an event occurs for an FD.
224 * Comments: Check all connections for new connections and input data
225 * that is to be processed. Also check for connections with data queued
226 * and whether we can write it out.
227 * Called to do the new-style IO, courtesy of squid (like most of this
228 * new IO code). This routine handles the stuff we've hidden in
229 * comm_setselect and fd_table[] and calls callbacks for IO ready
233 comm_select(unsigned long delay
)
238 unsigned long ndelay
;
247 ndelay
= ++empty_count
* 15000 ;
248 if(ndelay
> delay
* 1000)
249 ndelay
= delay
* 1000;
254 /* XXX kill that +1 later ! -- adrian */
257 last_count
= num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, 0);
260 if(ignoreErrno(errno
))
268 /* update current time again, eww.. */
273 /* XXX we *could* optimise by falling out after doing num fds ... */
274 for (ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
278 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0) ||
279 (pollfd_list
.pollfds
[ci
].fd
) == -1)
281 fd
= pollfd_list
.pollfds
[ci
].fd
;
282 F
= comm_locate_fd(fd
);
283 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
285 hdl
= F
->read_handler
;
286 F
->read_handler
= NULL
;
287 poll_update_pollfds(fd
, POLLRDNORM
, NULL
);
289 hdl(fd
, F
->read_data
);
291 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
293 hdl
= F
->write_handler
;
294 F
->write_handler
= NULL
;
295 poll_update_pollfds(fd
, POLLWRNORM
, NULL
);
297 hdl(fd
, F
->write_data
);