Skip to content

Commit 6466e32

Browse files
committed
FreeBSD: Port from epoll(2) to kqueue(2).
Add the last missing piece to make the server build and run on FreeBSD. kqueue and epoll have an almost 1:1 API, so porting involved mostly changing some variable names and using the corresponding kqueue functions. The headers were also sorted according to style(9): sys/types.h before anything else, followed by other sys headers, then the network headers and finally everything else.
1 parent 762eca1 commit 6466e32

File tree

2 files changed

+59
-45
lines changed

2 files changed

+59
-45
lines changed

lwan.c

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,28 @@
1818
*/
1919

2020
#define _GNU_SOURCE
21+
22+
#include <sys/types.h>
23+
#include <sys/event.h>
24+
#include <sys/resource.h>
25+
#include <sys/socket.h>
26+
#include <sys/time.h>
27+
#include <sys/uio.h>
28+
2129
#include <arpa/inet.h>
30+
#include <netinet/in.h>
31+
#include <netinet/tcp.h>
32+
2233
#include <ctype.h>
2334
#include <errno.h>
2435
#include <fcntl.h>
25-
#include <netinet/in.h>
26-
#include <netinet/tcp.h>
2736
#include <pthread.h>
2837
#include <pthread_np.h>
2938
#include <setjmp.h>
3039
#include <signal.h>
3140
#include <stdio.h>
3241
#include <stdlib.h>
3342
#include <string.h>
34-
#include <sys/epoll.h>
35-
#include <sys/resource.h>
36-
#include <sys/socket.h>
37-
#include <sys/time.h>
38-
#include <sys/types.h>
39-
#include <sys/uio.h>
4043
#include <unistd.h>
4144

4245
#include "lwan.h"
@@ -339,24 +342,29 @@ static void *
339342
_thread(void *data)
340343
{
341344
lwan_thread_t *t = data;
342-
struct epoll_event events[t->lwan->thread.max_fd];
343-
int epoll_fd = t->epoll_fd, n_fds, i;
345+
struct kevent events[t->lwan->thread.max_fd];
346+
int kqueue_fd = t->kqueue_fd, n_fds, i;
344347
unsigned int death_time = 0;
345348

346349
lwan_request_t *requests = t->lwan->requests;
347350
int *death_queue = calloc(1, t->lwan->thread.max_fd * sizeof(int));
348351
int death_queue_last = 0, death_queue_first = 0, death_queue_population = 0;
349352

353+
const struct timespec keep_alive_length = {
354+
.tv_sec = 1,
355+
.tv_nsec = 0
356+
};
357+
350358
for (; ; ) {
351-
switch (n_fds = epoll_wait(epoll_fd, events, N_ELEMENTS(events),
352-
death_queue_population ? 1000 : -1)) {
359+
switch (n_fds = kevent(kqueue_fd, NULL, 0, events, N_ELEMENTS(events),
360+
death_queue_population ? &keep_alive_length : NULL)) {
353361
case -1:
354362
switch (errno) {
355363
case EBADF:
356364
case EINVAL:
357-
goto epoll_fd_closed;
365+
goto kqueue_fd_closed;
358366
case EINTR:
359-
perror("epoll_wait");
367+
perror("kevent");
360368
}
361369
continue;
362370
case 0: /* timeout: shutdown waiting sockets */
@@ -381,18 +389,19 @@ _thread(void *data)
381389
break;
382390
default: /* activity in some of this poller's file descriptor */
383391
for (i = 0; i < n_fds; ++i) {
384-
lwan_request_t *request = &requests[events[i].data.fd];
392+
lwan_request_t *request = &requests[events[i].ident];
385393

386-
if (events[i].events & (EPOLLRDHUP | EPOLLHUP)) {
387-
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, &events[i]) < 0)
388-
perror("epoll_ctl");
394+
if (events[i].flags & EV_EOF) {
395+
struct kevent ev;
396+
EV_SET(&ev, events[i].ident, EVFILT_READ, EV_DELETE, 0, 0, NULL);
397+
kevent(kqueue_fd, &ev, 1, NULL, 0, NULL);
389398
goto invalidate_request;
390399
}
391400

392401
if (!request->flags.alive) {
393402
/* Reset the whole thing. */
394403
memset(request, 0, sizeof(*request));
395-
request->fd = events[i].data.fd;
404+
request->fd = events[i].ident;
396405
}
397406

398407
/*
@@ -416,22 +425,22 @@ _thread(void *data)
416425
* socket again. Or not. Mwahahaha.
417426
*/
418427
if (!request->flags.alive) {
419-
death_queue[death_queue_last++] = events[i].data.fd;
428+
death_queue[death_queue_last++] = events[i].ident;
420429
++death_queue_population;
421430
death_queue_last %= t->lwan->thread.max_fd;
422431
request->flags.alive = true;
423432
}
424433
continue;
425434
}
426435

427-
close(events[i].data.fd);
436+
close(events[i].ident);
428437
invalidate_request:
429438
request->flags.alive = false;
430439
}
431440
}
432441
}
433442

434-
epoll_fd_closed:
443+
kqueue_fd_closed:
435444
free(death_queue);
436445

437446
return NULL;
@@ -444,8 +453,8 @@ _create_thread(lwan_t *l, int thread_n)
444453
lwan_thread_t *thread = &l->thread.threads[thread_n];
445454

446455
thread->lwan = l;
447-
if ((thread->epoll_fd = epoll_create1(0)) < 0) {
448-
perror("epoll_create");
456+
if ((thread->kqueue_fd = kqueue()) < 0) {
457+
perror("kqueue (_create_thread)");
449458
exit(-1);
450459
}
451460

@@ -511,7 +520,7 @@ _thread_shutdown(lwan_t *l)
511520
* finalized.
512521
*/
513522
for (i = l->thread.count - 1; i >= 0; i--)
514-
close(l->thread.threads[i].epoll_fd);
523+
close(l->thread.threads[i].kqueue_fd);
515524
for (i = l->thread.count - 1; i >= 0; i--)
516525
pthread_join(l->thread.threads[i].id, NULL);
517526

@@ -719,14 +728,13 @@ _schedule_request(lwan_t *l)
719728
ALWAYS_INLINE static void
720729
_push_request_fd(lwan_t *l, int fd)
721730
{
722-
int epoll_fd = l->thread.threads[_schedule_request(l)].epoll_fd;
723-
struct epoll_event event = {
724-
.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET,
725-
.data.fd = fd
726-
};
731+
int kqueue_fd = l->thread.threads[_schedule_request(l)].kqueue_fd;
732+
struct kevent event;
733+
734+
EV_SET(&event, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, l->thread.count * l->thread.max_fd, NULL);
727735

728-
if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0)) {
729-
perror("epoll_ctl");
736+
if (UNLIKELY(kevent(kqueue_fd, &event, 1, NULL, 0, NULL) < 0)) {
737+
perror("kevent");
730738
exit(-1);
731739
}
732740
}
@@ -746,37 +754,43 @@ lwan_main_loop(lwan_t *l)
746754

747755
signal(SIGINT, _cleanup);
748756

749-
int epoll_fd = epoll_create1(0);
750-
struct epoll_event events[128];
751-
struct epoll_event ev = {
752-
.events = EPOLLIN,
753-
};
754-
755757
if (fcntl(l->main_socket, F_SETFL, O_NONBLOCK) < 0) {
756758
perror("fcntl: main socket");
757759
exit(-1);
758760
}
759-
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, l->main_socket, &ev) < 0) {
760-
perror("epoll_ctl");
761-
exit(-1);
761+
762+
int kqueue_fd = kqueue();
763+
if (kqueue_fd < 0) {
764+
perror("kqueue");
765+
return;
762766
}
763767

768+
struct kevent events[128];
769+
struct kevent ev;
770+
771+
EV_SET(&ev, l->main_socket, EVFILT_READ, EV_ADD, 0, l->thread.count * l->thread.max_fd, NULL);
772+
764773
for (;;) {
765774
int n_fds;
766-
for (n_fds = epoll_wait(epoll_fd, events, N_ELEMENTS(events), -1);
775+
for (n_fds = kevent(kqueue_fd, &ev, 1, events, N_ELEMENTS(events), NULL);
767776
n_fds > 0;
768777
--n_fds) {
769-
int child_fd = accept4(l->main_socket, NULL, NULL, SOCK_NONBLOCK);
778+
int child_fd = accept(l->main_socket, NULL, NULL);
770779
if (UNLIKELY(child_fd < 0)) {
771780
perror("accept");
772781
continue;
773782
}
783+
if (UNLIKELY(fcntl(child_fd, F_SETFL, O_NONBLOCK) < 0)) {
784+
perror("fnctl");
785+
close(child_fd);
786+
continue;
787+
}
774788

775789
_push_request_fd(l, child_fd);
776790
}
777791
}
778792

779-
close(epoll_fd);
793+
close(kqueue_fd);
780794
}
781795

782796
int

lwan.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ struct lwan_url_map_t_ {
143143

144144
struct lwan_thread_t_ {
145145
lwan_t *lwan;
146-
int epoll_fd;
146+
int kqueue_fd;
147147
pthread_t id;
148148
};
149149

0 commit comments

Comments
 (0)