]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/epoll.c
Remove silly a2client_p, entirely pointless since User.server removal.
[irc/rqf/shadowircd.git] / libcharybdis / epoll.c
1 /*
2 * charybdis: A slightly useful ircd.
3 * epoll.c: Linux epoll compatible network routines.
4 *
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
9 * Copyright (C) 2002 Aaron Sethman <androsyn@ratbox.org>
10 * Copyright (C) 2008 William Pitcock <nenolod@sacredspiral.co.uk>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25 * USA
26 *
27 * $Id: epoll.c 3444 2007-05-09 00:32:08Z nenolod $
28 */
29
30 #include "config.h"
31 #include "stdinc.h"
32 #include <sys/epoll.h>
33
34 #include "libcharybdis.h"
35
36 static int ep; /* epoll file descriptor */
37 static struct epoll_event *pfd;
38 static int pfd_size;
39
40
41 #ifndef HAVE_EPOLL_CTL /* bah..glibc doesn't support epoll yet.. */
42 #include <sys/epoll.h>
43 #include <sys/syscall.h>
44
45 _syscall1(int, epoll_create, int, maxfds);
46 _syscall4(int, epoll_ctl, int, epfd, int, op, int, fd, struct epoll_event *, events);
47 _syscall4(int, epoll_wait, int, epfd, struct epoll_event *, pevents,
48 int, maxevents, int, timeout);
49
50 #endif /* HAVE_EPOLL_CTL */
51
52
53 /*
54 * init_netio
55 *
56 * This is a needed exported function which will be called to initialise
57 * the network loop code.
58 */
59 void
60 init_netio(void)
61 {
62 pfd_size = getdtablesize();
63 ep = epoll_create(pfd_size);
64 pfd = MyMalloc(sizeof(struct epoll_event) * pfd_size);
65 if(ep < 0)
66 {
67 fprintf(stderr, "init_netio: Couldn't open epoll fd!\n");
68 exit(115); /* Whee! */
69 }
70 comm_note(ep, "epoll file descriptor");
71 }
72
73 /*
74 * comm_setselect
75 *
76 * This is a needed exported function which will be called to register
77 * and deregister interest in a pending IO state for a given FD.
78 */
79 void
80 comm_setselect(int fd, fdlist_t list, unsigned int type, PF * handler,
81 void *client_data, time_t timeout)
82 {
83 struct epoll_event ep_event;
84 fde_t *F = comm_locate_fd(fd);
85 int old_flags = F->pflags;
86 int op = -1;
87
88 s_assert(fd >= 0);
89 s_assert(F->flags.open);
90
91 /* Update the list, even though we're not using it .. */
92 F->list = list;
93 if(type & COMM_SELECT_READ)
94 {
95 if(handler != NULL)
96 F->pflags |= EPOLLIN;
97 else
98 F->pflags &= ~EPOLLIN;
99 F->read_handler = handler;
100 F->read_data = client_data;
101 }
102
103 if(type & COMM_SELECT_WRITE)
104 {
105 if(handler != NULL)
106 F->pflags |= EPOLLOUT;
107 else
108 F->pflags &= ~EPOLLOUT;
109 F->write_handler = handler;
110 F->write_data = client_data;
111 }
112
113 if(timeout)
114 F->timeout = CurrentTime + (timeout / 1000);
115
116 if(old_flags == 0 && F->pflags == 0)
117 return;
118 else if(F->pflags <= 0)
119 op = EPOLL_CTL_DEL;
120 else if(old_flags == 0 && F->pflags > 0)
121 op = EPOLL_CTL_ADD;
122 else if(F->pflags != old_flags)
123 op = EPOLL_CTL_MOD;
124
125 if(op == -1)
126 return;
127
128
129 ep_event.events = F->pflags;
130 ep_event.data.ptr = F;
131
132 if(epoll_ctl(ep, op, fd, &ep_event) != 0)
133 {
134 libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
135 abort();
136 }
137 }
138
139 /*
140 * comm_select
141 *
142 * Called to do the new-style IO, courtesy of squid (like most of this
143 * new IO code). This routine handles the stuff we've hidden in
144 * comm_setselect and fd_table[] and calls callbacks for IO ready
145 * events.
146 */
147
148 int
149 comm_select(unsigned long delay)
150 {
151 int num, i, flags, old_flags, op;
152 struct epoll_event ep_event;
153 void *data;
154
155 num = epoll_wait(ep, pfd, pfd_size, delay);
156 set_time();
157 if(num < 0 && !ignoreErrno(errno))
158 {
159 return COMM_ERROR;
160 }
161
162 if(num == 0)
163 return COMM_OK;
164 for (i = 0; i < num; i++)
165 {
166 PF *hdl;
167 fde_t *F = pfd[i].data.ptr;
168 old_flags = F->pflags;
169 if(pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
170 {
171 hdl = F->read_handler;
172 data = F->read_data;
173 F->read_handler = NULL;
174 F->read_data = NULL;
175 if(hdl) {
176 hdl(F->fd, data);
177 }
178 else
179 libcharybdis_log("epoll.c: NULL read handler called");
180 }
181
182
183 if(F->flags.open == 0 && F->pflags == 0)
184 continue;
185 else if (F->flags.open == 0)
186 {
187 F->pflags = ep_event.events = flags;
188 ep_event.data.ptr = F;
189
190 if(epoll_ctl(ep, EPOLL_CTL_DEL, F->fd, &ep_event) != 0) {
191 /* XXX: we assume this is because close(2) has been called here. */
192 if (errno == EBADF)
193 continue;
194
195 libcharybdis_log("comm_select(): epoll_ctl failed while trying to delete an FD marked as closed: %s", strerror(errno));
196 abort();
197 }
198
199 continue;
200 }
201
202 if(pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))
203 {
204 hdl = F->write_handler;
205 data = F->write_data;
206 F->write_handler = NULL;
207 F->write_data = NULL;
208
209 if(hdl) {
210 hdl(F->fd, data);
211 }
212 else
213 libcharybdis_log("epoll.c: NULL write handler called");
214 }
215
216 if(F->flags.open == 0 && F->pflags == 0)
217 continue;
218 else if (F->flags.open == 0)
219 {
220 F->pflags = ep_event.events = flags;
221 ep_event.data.ptr = F;
222
223 if(epoll_ctl(ep, EPOLL_CTL_DEL, F->fd, &ep_event) != 0) {
224 /* XXX: we assume this is because close(2) has been called here. */
225 if (errno == EBADF)
226 continue;
227
228 libcharybdis_log("comm_select(): epoll_ctl failed while trying to delete an FD marked as closed: %s", strerror(errno));
229 abort();
230 }
231
232 continue;
233 }
234
235 flags = 0;
236
237 if(F->read_handler != NULL)
238 flags |= EPOLLIN;
239 else
240 flags &= ~EPOLLIN;
241
242 if(F->write_handler != NULL)
243 flags |= EPOLLOUT;
244 else
245 flags &= ~EPOLLOUT;
246
247 if(old_flags != flags)
248 {
249 if(flags == 0)
250 op = EPOLL_CTL_DEL;
251 else
252 op = EPOLL_CTL_MOD;
253
254 F->pflags = ep_event.events = flags;
255 ep_event.data.ptr = F;
256
257 if(epoll_ctl(ep, op, F->fd, &ep_event) != 0)
258 libcharybdis_log("comm_select(): epoll_ctl failed: %s", strerror(errno));
259 }
260
261 }
262 return COMM_OK;
263 }