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 3245 2007-03-05 18:41:14Z 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.
67 pollfd_list
.pollfds
= calloc(sizeof(struct pollfd
), MAXCONNECTIONS
);
69 for (fd
= 0; fd
< MAXCONNECTIONS
; fd
++)
70 pollfd_list
.pollfds
[fd
].fd
= -1;
72 pollfd_list
.maxindex
= 0;
73 pollfd_list
.allocated
= MAXCONNECTIONS
;
77 resize_poll_array(int fd
)
79 int i
, old_value
= pollfd_list
.allocated
;
81 if (fd
< pollfd_list
.allocated
)
84 pollfd_list
.allocated
+= 1024;
85 pollfd_list
.pollfds
= MyRealloc(pollfd_list
.pollfds
, pollfd_list
.allocated
* sizeof(struct pollfd
));
87 /* because realloced memory can contain junk, we have to zero it out. */
88 memset(&pollfd_list
.pollfds
[old_value
+1], 0, sizeof(struct pollfd
) * 1024);
90 for (i
= old_value
+ 1; i
<= pollfd_list
.allocated
; i
++)
91 pollfd_list
.pollfds
[i
].fd
= -1;
94 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
95 /* Private functions */
98 * find a spare slot in the fd list. We can optimise this out later!
105 for (i
= 0; i
< pollfd_list
.allocated
; i
++)
107 if(pollfd_list
.pollfds
[i
].fd
== -1)
120 * set and clear entries in the pollfds[] array.
123 poll_update_pollfds(int fd
, short event
, PF
* handler
)
125 fde_t
*F
= comm_locate_fd(fd
);
128 resize_poll_array(fd
);
130 if(F
->comm_index
< 0)
131 F
->comm_index
= poll_findslot();
133 comm_index
= F
->comm_index
;
135 /* Update the events */
138 F
->list
= FDLIST_IDLECLIENT
;
139 pollfd_list
.pollfds
[comm_index
].events
|= event
;
140 pollfd_list
.pollfds
[comm_index
].fd
= fd
;
141 /* update maxindex here */
142 if(comm_index
> pollfd_list
.maxindex
)
143 pollfd_list
.maxindex
= comm_index
;
149 pollfd_list
.pollfds
[comm_index
].events
&= ~event
;
150 if(pollfd_list
.pollfds
[comm_index
].events
== 0)
152 pollfd_list
.pollfds
[comm_index
].fd
= -1;
153 pollfd_list
.pollfds
[comm_index
].revents
= 0;
155 F
->list
= FDLIST_NONE
;
157 /* update pollfd_list.maxindex here */
158 if(comm_index
== pollfd_list
.maxindex
)
159 while (pollfd_list
.maxindex
>= 0 &&
160 pollfd_list
.pollfds
[pollfd_list
.maxindex
].fd
== -1)
161 pollfd_list
.maxindex
--;
168 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
169 /* Public functions */
174 * This is a needed exported function which will be called to register
175 * and deregister interest in a pending IO state for a given FD.
178 comm_setselect(int fd
, fdlist_t list
, unsigned int type
, PF
* handler
,
179 void *client_data
, time_t timeout
)
181 fde_t
*F
= comm_locate_fd(fd
);
183 s_assert(F
->flags
.open
);
185 if(type
& COMM_SELECT_READ
)
187 F
->read_handler
= handler
;
188 F
->read_data
= client_data
;
189 poll_update_pollfds(fd
, POLLRDNORM
, handler
);
191 if(type
& COMM_SELECT_WRITE
)
193 F
->write_handler
= handler
;
194 F
->write_data
= client_data
;
195 poll_update_pollfds(fd
, POLLWRNORM
, handler
);
198 F
->timeout
= CurrentTime
+ (timeout
/ 1000);
202 irc_sleep(unsigned long useconds
)
204 #ifdef HAVE_NANOSLEEP
206 t
.tv_sec
= useconds
/ (unsigned long) 1000000;
207 t
.tv_nsec
= (useconds
% (unsigned long) 1000000) * 1000;
208 nanosleep(&t
, (struct timespec
*) NULL
);
212 t
.tv_usec
= useconds
;
213 select(0, NULL
, NULL
, NULL
, &t
);
218 /* int comm_select_fdlist(unsigned long delay)
219 * Input: The maximum time to delay.
220 * Output: Returns -1 on error, 0 on success.
221 * Side-effects: Deregisters future interest in IO and calls the handlers
222 * if an event occurs for an FD.
223 * Comments: Check all connections for new connections and input data
224 * that is to be processed. Also check for connections with data queued
225 * and whether we can write it out.
226 * Called to do the new-style IO, courtesy of squid (like most of this
227 * new IO code). This routine handles the stuff we've hidden in
228 * comm_setselect and fd_table[] and calls callbacks for IO ready
232 comm_select(unsigned long delay
)
237 unsigned long ndelay
;
246 ndelay
= ++empty_count
* 15000 ;
247 if(ndelay
> delay
* 1000)
248 ndelay
= delay
* 1000;
253 /* XXX kill that +1 later ! -- adrian */
256 last_count
= num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, 0);
259 if(ignoreErrno(errno
))
267 /* update current time again, eww.. */
272 /* XXX we *could* optimise by falling out after doing num fds ... */
273 for (ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
277 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0) ||
278 (pollfd_list
.pollfds
[ci
].fd
) == -1)
280 fd
= pollfd_list
.pollfds
[ci
].fd
;
281 F
= comm_locate_fd(fd
);
282 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
284 hdl
= F
->read_handler
;
285 F
->read_handler
= NULL
;
286 poll_update_pollfds(fd
, POLLRDNORM
, NULL
);
288 hdl(fd
, F
->read_data
);
290 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
292 hdl
= F
->write_handler
;
293 F
->write_handler
= NULL
;
294 poll_update_pollfds(fd
, POLLWRNORM
, NULL
);
296 hdl(fd
, F
->write_data
);