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 3528 2007-07-07 08:08:23Z 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
);
134 if(F
->comm_index
< 0)
135 F
->comm_index
= poll_findslot();
137 comm_index
= F
->comm_index
;
139 /* Update the events */
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
;
153 pollfd_list
.pollfds
[comm_index
].events
&= ~event
;
154 if(pollfd_list
.pollfds
[comm_index
].events
== 0)
156 pollfd_list
.pollfds
[comm_index
].fd
= -1;
157 pollfd_list
.pollfds
[comm_index
].revents
= 0;
159 F
->list
= FDLIST_NONE
;
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
--;
172 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
173 /* Public functions */
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.
182 comm_setselect(int fd
, fdlist_t list
, unsigned int type
, PF
* handler
,
183 void *client_data
, time_t timeout
)
185 fde_t
*F
= comm_locate_fd(fd
);
187 s_assert(F
->flags
.open
);
189 if(type
& COMM_SELECT_READ
)
191 F
->read_handler
= handler
;
192 F
->read_data
= client_data
;
193 poll_update_pollfds(fd
, POLLRDNORM
, handler
);
195 if(type
& COMM_SELECT_WRITE
)
197 F
->write_handler
= handler
;
198 F
->write_data
= client_data
;
199 poll_update_pollfds(fd
, POLLWRNORM
, handler
);
202 F
->timeout
= CurrentTime
+ (timeout
/ 1000);
206 irc_sleep(unsigned long useconds
)
208 #ifdef HAVE_NANOSLEEP
210 t
.tv_sec
= useconds
/ (unsigned long) 1000000;
211 t
.tv_nsec
= (useconds
% (unsigned long) 1000000) * 1000;
212 nanosleep(&t
, (struct timespec
*) NULL
);
216 t
.tv_usec
= useconds
;
217 select(0, NULL
, NULL
, NULL
, &t
);
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
236 comm_select(unsigned long delay
)
241 unsigned long ndelay
;
250 ndelay
= ++empty_count
* 15000 ;
251 if(ndelay
> delay
* 1000)
252 ndelay
= delay
* 1000;
257 /* XXX kill that +1 later ! -- adrian */
260 last_count
= num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, 0);
263 if(ignoreErrno(errno
))
271 /* update current time again, eww.. */
276 /* XXX we *could* optimise by falling out after doing num fds ... */
277 for (ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
281 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0) ||
282 (pollfd_list
.pollfds
[ci
].fd
) == -1)
284 fd
= pollfd_list
.pollfds
[ci
].fd
;
285 F
= comm_locate_fd(fd
);
286 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
288 hdl
= F
->read_handler
;
289 F
->read_handler
= NULL
;
290 poll_update_pollfds(fd
, POLLRDNORM
, NULL
);
292 hdl(fd
, F
->read_data
);
294 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
296 hdl
= F
->write_handler
;
297 F
->write_handler
= NULL
;
298 poll_update_pollfds(fd
, POLLWRNORM
, NULL
);
300 hdl(fd
, F
->write_data
);