]> jfr.im git - irc/rqf/shadowircd.git/blob - libcharybdis/epoll.c
[svn] - the new plan:
[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 390 2005-12-07 18:46:56Z 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 = &fd_table[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(old_flags == 0 && F->pflags == 0)
116 return;
117 else if(F->pflags <= 0)
118 op = EPOLL_CTL_DEL;
119 else if(old_flags == 0 && F->pflags > 0)
120 op = EPOLL_CTL_ADD;
121 else if(F->pflags != old_flags)
122 op = EPOLL_CTL_MOD;
123
124 if(op == -1)
125 return;
126
127
128 ep_event.events = F->pflags;
129 ep_event.data.ptr = F;
130
131 if(epoll_ctl(ep, op, fd, &ep_event) != 0)
132 {
133 libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
134 abort();
135 }
136
137
138 }
139
140 /*
141 * comm_select
142 *
143 * Called to do the new-style IO, courtesy of squid (like most of this
144 * new IO code). This routine handles the stuff we've hidden in
145 * comm_setselect and fd_table[] and calls callbacks for IO ready
146 * events.
147 */
148
149 int
150 comm_select(unsigned long delay)
151 {
152 int num, i, flags, old_flags, op;
153 struct epoll_event ep_event;
154 void *data;
155
156 num = epoll_wait(ep, pfd, pfd_size, delay);
157 set_time();
158 if(num < 0 && !ignoreErrno(errno))
159 {
160 return COMM_ERROR;
161 }
162
163 if(num == 0)
164 return COMM_OK;
165 for (i = 0; i < num; i++)
166 {
167 PF *hdl;
168 fde_t *F = pfd[i].data.ptr;
169 old_flags = F->pflags;
170 if(pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
171 {
172 hdl = F->read_handler;
173 data = F->read_data;
174 F->read_handler = NULL;
175 F->read_data = NULL;
176 if(hdl) {
177 hdl(F->fd, data);
178 }
179 else
180 libcharybdis_log("epoll.c: NULL read handler called");
181
182 }
183
184
185 if(F->flags.open == 0)
186 continue;
187 if(pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))
188 {
189 hdl = F->write_handler;
190 data = F->write_data;
191 F->write_handler = NULL;
192 F->write_data = NULL;
193
194 if(hdl) {
195 hdl(F->fd, data);
196 }
197 else
198 libcharybdis_log("epoll.c: NULL write handler called");
199 }
200
201 if(F->flags.open == 0)
202 continue;
203
204 flags = 0;
205
206 if(F->read_handler != NULL)
207 flags |= EPOLLIN;
208 if(F->write_handler != NULL)
209 flags |= EPOLLOUT;
210
211 if(old_flags != flags)
212 {
213 if(flags == 0)
214 op = EPOLL_CTL_DEL;
215 else
216 op = EPOLL_CTL_MOD;
217 F->pflags = ep_event.events = flags;
218 ep_event.data.ptr = F;
219 if(epoll_ctl(ep, op, F->fd, &ep_event) != 0)
220 {
221 libcharybdis_log("comm_setselect(): epoll_ctl failed: %s", strerror(errno));
222 }
223 }
224
225 }
226 return COMM_OK;
227 }
228