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 3229 2007-03-05 17:23:07Z nenolod $
32 #include "libcharybdis.h"
34 /* I hate linux -- adrian */
36 #define POLLRDNORM POLLIN
39 #define POLLWRNORM POLLOUT
44 struct pollfd pollfds
[MAXCONNECTIONS
];
45 int maxindex
; /* highest FD number */
48 typedef struct _pollfd_list pollfd_list_t
;
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 */
58 * find a spare slot in the fd list. We can optimise this out later!
65 for (i
= 0; i
< MAXCONNECTIONS
; i
++)
67 if(pollfd_list
.pollfds
[i
].fd
== -1)
79 * set and clear entries in the pollfds[] array.
82 poll_update_pollfds(int fd
, short event
, PF
* handler
)
84 fde_t
*F
= comm_locate_table(fd
);
89 F
->comm_index
= poll_findslot();
91 comm_index
= F
->comm_index
;
93 /* Update the events */
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
;
107 pollfd_list
.pollfds
[comm_index
].events
&= ~event
;
108 if(pollfd_list
.pollfds
[comm_index
].events
== 0)
110 pollfd_list
.pollfds
[comm_index
].fd
= -1;
111 pollfd_list
.pollfds
[comm_index
].revents
= 0;
113 F
->list
= FDLIST_NONE
;
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
--;
126 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
127 /* Public functions */
133 * This is a needed exported function which will be called to initialise
134 * the network loop code.
141 for (fd
= 0; fd
< MAXCONNECTIONS
; fd
++)
143 pollfd_list
.pollfds
[fd
].fd
= -1;
145 pollfd_list
.maxindex
= 0;
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.
155 comm_setselect(int fd
, fdlist_t list
, unsigned int type
, PF
* handler
,
156 void *client_data
, time_t timeout
)
158 fde_t
*F
= comm_locate_fd(fd
);
160 s_assert(F
->flags
.open
);
162 if(type
& COMM_SELECT_READ
)
164 F
->read_handler
= handler
;
165 F
->read_data
= client_data
;
166 poll_update_pollfds(fd
, POLLRDNORM
, handler
);
168 if(type
& COMM_SELECT_WRITE
)
170 F
->write_handler
= handler
;
171 F
->write_data
= client_data
;
172 poll_update_pollfds(fd
, POLLWRNORM
, handler
);
175 F
->timeout
= CurrentTime
+ (timeout
/ 1000);
179 irc_sleep(unsigned long useconds
)
181 #ifdef HAVE_NANOSLEEP
183 t
.tv_sec
= useconds
/ (unsigned long) 1000000;
184 t
.tv_nsec
= (useconds
% (unsigned long) 1000000) * 1000;
185 nanosleep(&t
, (struct timespec
*) NULL
);
189 t
.tv_usec
= useconds
;
190 select(0, NULL
, NULL
, NULL
, &t
);
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
209 comm_select(unsigned long delay
)
214 unsigned long ndelay
;
223 ndelay
= ++empty_count
* 15000 ;
224 if(ndelay
> delay
* 1000)
225 ndelay
= delay
* 1000;
230 /* XXX kill that +1 later ! -- adrian */
233 last_count
= num
= poll(pollfd_list
.pollfds
, pollfd_list
.maxindex
+ 1, 0);
236 if(ignoreErrno(errno
))
244 /* update current time again, eww.. */
249 /* XXX we *could* optimise by falling out after doing num fds ... */
250 for (ci
= 0; ci
< pollfd_list
.maxindex
+ 1; ci
++)
254 if(((revents
= pollfd_list
.pollfds
[ci
].revents
) == 0) ||
255 (pollfd_list
.pollfds
[ci
].fd
) == -1)
257 fd
= pollfd_list
.pollfds
[ci
].fd
;
258 F
= comm_locate_fd(fd
);
259 if(revents
& (POLLRDNORM
| POLLIN
| POLLHUP
| POLLERR
))
261 hdl
= F
->read_handler
;
262 F
->read_handler
= NULL
;
263 poll_update_pollfds(fd
, POLLRDNORM
, NULL
);
265 hdl(fd
, F
->read_data
);
267 if(revents
& (POLLWRNORM
| POLLOUT
| POLLHUP
| POLLERR
))
269 hdl
= F
->write_handler
;
270 F
->write_handler
= NULL
;
271 poll_update_pollfds(fd
, POLLWRNORM
, NULL
);
273 hdl(fd
, F
->write_data
);