Skip to content

Commit 1ccbed7

Browse files
committed
Move epoll implementation to its own file
This should help with #363.
1 parent 88ade5f commit 1ccbed7

File tree

3 files changed

+178
-147
lines changed

3 files changed

+178
-147
lines changed

src/lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ set(SOURCES
3838
lwan-pubsub.c
3939
missing.c
4040
missing-pthread.c
41+
missing-epoll.c
4142
murmur3.c
4243
patterns.c
4344
realpathat.c

src/lib/missing-epoll.c

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* lwan - web server
3+
* Copyright (c) 2012 L. A. F. Pereira <[email protected]>
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU General Public License
7+
* as published by the Free Software Foundation; either version 2
8+
* of the License, or any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18+
* USA.
19+
*/
20+
21+
#include <errno.h>
22+
#include <fcntl.h>
23+
#include <limits.h>
24+
#include <stdint.h>
25+
#include <stdlib.h>
26+
#include <sys/epoll.h>
27+
#include <sys/types.h>
28+
#include <unistd.h>
29+
30+
#include "lwan.h"
31+
32+
#if !defined(LWAN_HAVE_EPOLL) && defined(LWAN_HAVE_KQUEUE)
33+
#include <sys/event.h>
34+
#include <sys/time.h>
35+
#include <sys/types.h>
36+
37+
#include "hash.h"
38+
39+
int epoll_create1(int flags)
40+
{
41+
#if defined(LWAN_HAVE_KQUEUE1)
42+
return kqueue1(flags & EPOLL_CLOEXEC ? O_CLOEXEC : 0);
43+
#else
44+
int fd = kqueue();
45+
46+
if (flags & EPOLL_CLOEXEC) {
47+
int flags;
48+
49+
flags = fcntl(fd, F_GETFD);
50+
if (flags < 0)
51+
return -1;
52+
53+
if (fcntl(fd, F_SETFD, flags | O_CLOEXEC) < 0)
54+
return -1;
55+
}
56+
57+
return fd;
58+
#endif
59+
}
60+
61+
static int epoll_no_event_marker;
62+
63+
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
64+
{
65+
struct kevent ev;
66+
67+
switch (op) {
68+
case EPOLL_CTL_ADD:
69+
case EPOLL_CTL_MOD: {
70+
int events = 0;
71+
void *udata = event->data.ptr;
72+
int flags = EV_ADD;
73+
74+
if (event->events & EPOLLIN) {
75+
events = EVFILT_READ;
76+
} else if (event->events & EPOLLOUT) {
77+
events = EVFILT_WRITE;
78+
} else {
79+
events = EVFILT_WRITE;
80+
udata = &epoll_no_event_marker;
81+
}
82+
83+
if (event->events & EPOLLONESHOT)
84+
flags |= EV_ONESHOT;
85+
if (event->events & EPOLLET)
86+
flags |= EV_CLEAR;
87+
88+
flags |= EV_ERROR; /* EPOLLERR is always set. */
89+
flags |= EV_EOF; /* EPOLLHUP is always set. */
90+
91+
EV_SET(&ev, fd, events, flags, 0, 0, udata);
92+
break;
93+
}
94+
95+
case EPOLL_CTL_DEL:
96+
EV_SET(&ev, fd, 0, EV_DELETE, 0, 0, 0);
97+
break;
98+
99+
default:
100+
errno = EINVAL;
101+
return -1;
102+
}
103+
104+
return kevent(epfd, &ev, 1, NULL, 0, NULL);
105+
}
106+
107+
static struct timespec *to_timespec(struct timespec *t, int ms)
108+
{
109+
if (ms < 0)
110+
return NULL;
111+
112+
t->tv_sec = ms / 1000;
113+
t->tv_nsec = (ms % 1000) * 1000000;
114+
115+
return t;
116+
}
117+
118+
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
119+
{
120+
struct epoll_event *ev = events;
121+
struct kevent evs[maxevents];
122+
struct timespec tmspec;
123+
struct hash *coalesce;
124+
int i, r;
125+
126+
coalesce = hash_int_new(NULL, NULL);
127+
if (UNLIKELY(!coalesce))
128+
return -1;
129+
130+
r = kevent(epfd, NULL, 0, evs, maxevents, to_timespec(&tmspec, timeout));
131+
if (UNLIKELY(r < 0)) {
132+
hash_free(coalesce);
133+
return -1;
134+
}
135+
136+
for (i = 0; i < r; i++) {
137+
struct kevent *kev = &evs[i];
138+
uint32_t mask = (uint32_t)(uintptr_t)hash_find(
139+
coalesce, (void *)(intptr_t)evs[i].ident);
140+
141+
if (kev->flags & EV_ERROR)
142+
mask |= EPOLLERR;
143+
if (kev->flags & EV_EOF)
144+
mask |= EPOLLRDHUP;
145+
146+
if (kev->filter == EVFILT_READ)
147+
mask |= EPOLLIN;
148+
else if (kev->filter == EVFILT_WRITE && evs[i].udata != &epoll_no_event_marker)
149+
mask |= EPOLLOUT;
150+
151+
hash_add(coalesce, (void *)(intptr_t)evs[i].ident,
152+
(void *)(uintptr_t)mask);
153+
}
154+
155+
for (i = 0; i < r; i++) {
156+
void *maskptr;
157+
158+
maskptr = hash_find(coalesce, (void *)(intptr_t)evs[i].ident);
159+
if (maskptr) {
160+
struct kevent *kev = &evs[i];
161+
162+
if (kev->udata == &epoll_no_event_marker)
163+
continue;
164+
165+
ev->data.ptr = kev->udata;
166+
ev->events = (uint32_t)(uintptr_t)maskptr;
167+
ev++;
168+
}
169+
}
170+
171+
hash_free(coalesce);
172+
return (int)(intptr_t)(ev - events);
173+
}
174+
#elif !defined(LWAN_HAVE_EPOLL)
175+
#error epoll() not implemented for this platform
176+
#endif
177+

src/lib/missing.c

-147
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include <stdint.h>
2828
#include <stdlib.h>
2929
#include <string.h>
30-
#include <sys/epoll.h>
3130
#include <sys/socket.h>
3231
#include <sys/types.h>
3332
#include <sys/vfs.h>
@@ -135,152 +134,6 @@ int clock_gettime(clockid_t clk_id, struct timespec *ts)
135134
}
136135
#endif
137136

138-
#if !defined(LWAN_HAVE_EPOLL) && defined(LWAN_HAVE_KQUEUE)
139-
#include <sys/event.h>
140-
#include <sys/time.h>
141-
#include <sys/types.h>
142-
143-
#include "hash.h"
144-
145-
int epoll_create1(int flags)
146-
{
147-
#if defined(LWAN_HAVE_KQUEUE1)
148-
return kqueue1(flags & EPOLL_CLOEXEC ? O_CLOEXEC : 0);
149-
#else
150-
int fd = kqueue();
151-
152-
if (flags & EPOLL_CLOEXEC) {
153-
int flags;
154-
155-
flags = fcntl(fd, F_GETFD);
156-
if (flags < 0)
157-
return -1;
158-
159-
if (fcntl(fd, F_SETFD, flags | O_CLOEXEC) < 0)
160-
return -1;
161-
}
162-
163-
return fd;
164-
#endif
165-
}
166-
167-
static int epoll_no_event_marker;
168-
169-
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
170-
{
171-
struct kevent ev;
172-
173-
switch (op) {
174-
case EPOLL_CTL_ADD:
175-
case EPOLL_CTL_MOD: {
176-
int events = 0;
177-
void *udata = event->data.ptr;
178-
int flags = EV_ADD;
179-
180-
if (event->events & EPOLLIN) {
181-
events = EVFILT_READ;
182-
} else if (event->events & EPOLLOUT) {
183-
events = EVFILT_WRITE;
184-
} else {
185-
events = EVFILT_WRITE;
186-
udata = &epoll_no_event_marker;
187-
}
188-
189-
if (event->events & EPOLLONESHOT)
190-
flags |= EV_ONESHOT;
191-
if (event->events & EPOLLET)
192-
flags |= EV_CLEAR;
193-
194-
flags |= EV_ERROR; /* EPOLLERR is always set. */
195-
flags |= EV_EOF; /* EPOLLHUP is always set. */
196-
197-
EV_SET(&ev, fd, events, flags, 0, 0, udata);
198-
break;
199-
}
200-
201-
case EPOLL_CTL_DEL:
202-
EV_SET(&ev, fd, 0, EV_DELETE, 0, 0, 0);
203-
break;
204-
205-
default:
206-
errno = EINVAL;
207-
return -1;
208-
}
209-
210-
return kevent(epfd, &ev, 1, NULL, 0, NULL);
211-
}
212-
213-
static struct timespec *to_timespec(struct timespec *t, int ms)
214-
{
215-
if (ms < 0)
216-
return NULL;
217-
218-
t->tv_sec = ms / 1000;
219-
t->tv_nsec = (ms % 1000) * 1000000;
220-
221-
return t;
222-
}
223-
224-
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
225-
{
226-
struct epoll_event *ev = events;
227-
struct kevent evs[maxevents];
228-
struct timespec tmspec;
229-
struct hash *coalesce;
230-
int i, r;
231-
232-
coalesce = hash_int_new(NULL, NULL);
233-
if (UNLIKELY(!coalesce))
234-
return -1;
235-
236-
r = kevent(epfd, NULL, 0, evs, maxevents, to_timespec(&tmspec, timeout));
237-
if (UNLIKELY(r < 0)) {
238-
hash_free(coalesce);
239-
return -1;
240-
}
241-
242-
for (i = 0; i < r; i++) {
243-
struct kevent *kev = &evs[i];
244-
uint32_t mask = (uint32_t)(uintptr_t)hash_find(
245-
coalesce, (void *)(intptr_t)evs[i].ident);
246-
247-
if (kev->flags & EV_ERROR)
248-
mask |= EPOLLERR;
249-
if (kev->flags & EV_EOF)
250-
mask |= EPOLLRDHUP;
251-
252-
if (kev->filter == EVFILT_READ)
253-
mask |= EPOLLIN;
254-
else if (kev->filter == EVFILT_WRITE && evs[i].udata != &epoll_no_event_marker)
255-
mask |= EPOLLOUT;
256-
257-
hash_add(coalesce, (void *)(intptr_t)evs[i].ident,
258-
(void *)(uintptr_t)mask);
259-
}
260-
261-
for (i = 0; i < r; i++) {
262-
void *maskptr;
263-
264-
maskptr = hash_find(coalesce, (void *)(intptr_t)evs[i].ident);
265-
if (maskptr) {
266-
struct kevent *kev = &evs[i];
267-
268-
if (kev->udata == &epoll_no_event_marker)
269-
continue;
270-
271-
ev->data.ptr = kev->udata;
272-
ev->events = (uint32_t)(uintptr_t)maskptr;
273-
ev++;
274-
}
275-
}
276-
277-
hash_free(coalesce);
278-
return (int)(intptr_t)(ev - events);
279-
}
280-
#elif !defined(LWAN_HAVE_EPOLL)
281-
#error epoll() not implemented for this platform
282-
#endif
283-
284137
#if defined(__linux__) || defined(__CYGWIN__)
285138
#if defined(LWAN_HAVE_GETAUXVAL)
286139
#include <sys/auxv.h>

0 commit comments

Comments
 (0)