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