11a78ce8eSRon #include <stdio.h>
21a78ce8eSRon #include <stdint.h>
31a78ce8eSRon #include <string.h>
41a78ce8eSRon #include <stdlib.h>
51a78ce8eSRon #include <stdarg.h>
61a78ce8eSRon #include <sched.h>
71a78ce8eSRon #include <fcntl.h>
81a78ce8eSRon #include <errno.h>
91a78ce8eSRon #include <assert.h>
101a78ce8eSRon #include <unistd.h>
11a9643ea8Slogwang #include <netinet/in.h>
121a78ce8eSRon #include <sys/types.h>
131a78ce8eSRon #include <sys/socket.h>
141a78ce8eSRon #include <sys/time.h>
151a78ce8eSRon #include <sys/select.h>
161a78ce8eSRon #include <sys/syscall.h>
171a78ce8eSRon #include <arpa/inet.h>
181a78ce8eSRon #include <sys/epoll.h>
19a9643ea8Slogwang
20a9643ea8Slogwang #include "ff_api.h"
21a9643ea8Slogwang #include "ff_errno.h"
22a9643ea8Slogwang
23a9643ea8Slogwang
24a9643ea8Slogwang int
ff_epoll_create(int size)25a9643ea8Slogwang ff_epoll_create(int size __attribute__((__unused__)))
26a9643ea8Slogwang {
27a9643ea8Slogwang return ff_kqueue();
28a9643ea8Slogwang }
29a9643ea8Slogwang
30a9643ea8Slogwang int
ff_epoll_ctl(int epfd,int op,int fd,struct epoll_event * event)31a9643ea8Slogwang ff_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
32a9643ea8Slogwang {
334ca4a487Slogwang /*
344ca4a487Slogwang * Since kqueue uses EVFILT_READ and EVFILT_WRITE filters to
354ca4a487Slogwang * handle read/write events, so we need two kevents.
364ca4a487Slogwang */
374ca4a487Slogwang const int changes = 2;
384ca4a487Slogwang struct kevent kev[changes];
394ca4a487Slogwang int flags = 0;
404ca4a487Slogwang int read_flags, write_flags;
411a78ce8eSRon
424ca4a487Slogwang if ((!event && op != EPOLL_CTL_DEL) ||
434ca4a487Slogwang (op != EPOLL_CTL_ADD &&
444ca4a487Slogwang op != EPOLL_CTL_MOD &&
454ca4a487Slogwang op != EPOLL_CTL_DEL)) {
461a78ce8eSRon errno = EINVAL;
47a9643ea8Slogwang return -1;
48a9643ea8Slogwang }
49a9643ea8Slogwang
504ca4a487Slogwang /*
514ca4a487Slogwang * EPOLL_CTL_DEL doesn't need to care for event->events.
524ca4a487Slogwang */
534ca4a487Slogwang if (op == EPOLL_CTL_DEL) {
544ca4a487Slogwang EV_SET(&kev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
554ca4a487Slogwang EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
564ca4a487Slogwang
574ca4a487Slogwang return ff_kevent(epfd, kev, changes, NULL, 0, NULL);
584ca4a487Slogwang }
594ca4a487Slogwang
604ca4a487Slogwang /*
614ca4a487Slogwang * FIXME:
624ca4a487Slogwang *
634ca4a487Slogwang * Kqueue doesn't have edge-triggered mode that exactly
644ca4a487Slogwang * same with epoll, the most similar way is setting EV_CLEAR
654ca4a487Slogwang * or EV_DISPATCH flag, but there are still some differences.
664ca4a487Slogwang *
674ca4a487Slogwang * EV_CLEAR:after the event is retrieved by the user,
684ca4a487Slogwang * its state is reset.
694ca4a487Slogwang * EV_DISPATCH: disable the event source immediately
704ca4a487Slogwang * after delivery of an event.
714ca4a487Slogwang *
724ca4a487Slogwang * Here we use EV_CLEAR temporarily.
734ca4a487Slogwang *
744ca4a487Slogwang */
754ca4a487Slogwang if (event->events & EPOLLET) {
764ca4a487Slogwang flags |= EV_CLEAR;
774ca4a487Slogwang }
784ca4a487Slogwang
794ca4a487Slogwang if (event->events & EPOLLONESHOT) {
804ca4a487Slogwang flags |= EV_ONESHOT;
814ca4a487Slogwang }
824ca4a487Slogwang
83a9643ea8Slogwang if (op == EPOLL_CTL_ADD) {
844ca4a487Slogwang flags |= EV_ADD;
85794317abSlogwang }
86794317abSlogwang
874ca4a487Slogwang read_flags = write_flags = flags | EV_DISABLE;
884ca4a487Slogwang
894ca4a487Slogwang if (event->events & EPOLLIN) {
904ca4a487Slogwang read_flags &= ~EV_DISABLE;
914ca4a487Slogwang read_flags |= EV_ENABLE;
92794317abSlogwang }
93794317abSlogwang
944ca4a487Slogwang if (event->events & EPOLLOUT) {
954ca4a487Slogwang write_flags &= ~EV_DISABLE;
964ca4a487Slogwang write_flags |= EV_ENABLE;
97a9643ea8Slogwang }
98a9643ea8Slogwang
99*8d6a4447Sdaovanhuy // Fix #124: set user data
100*8d6a4447Sdaovanhuy EV_SET(&kev[0], fd, EVFILT_READ, read_flags, 0, 0, event->data.ptr);
101*8d6a4447Sdaovanhuy EV_SET(&kev[1], fd, EVFILT_WRITE, write_flags, 0, 0, event->data.ptr);
1024ca4a487Slogwang
1034ca4a487Slogwang return ff_kevent(epfd, kev, changes, NULL, 0, NULL);
104a9643ea8Slogwang }
105a9643ea8Slogwang
1061a78ce8eSRon static void
ff_event_to_epoll(void ** ev,struct kevent * kev)1071a78ce8eSRon ff_event_to_epoll(void **ev, struct kevent *kev)
108a9643ea8Slogwang {
109a9643ea8Slogwang unsigned int event_one = 0;
1101a78ce8eSRon struct epoll_event **ppev = (struct epoll_event **)ev;
1111a78ce8eSRon
1128c317b22Slogwang if (kev->filter == EVFILT_READ) {
1138c317b22Slogwang if (kev->data || !(kev->flags & EV_EOF)) {
114a9643ea8Slogwang event_one |= EPOLLIN;
115a9643ea8Slogwang }
1168c317b22Slogwang } else if (kev->filter == EVFILT_WRITE) {
117a9643ea8Slogwang event_one |= EPOLLOUT;
118a9643ea8Slogwang }
119a9643ea8Slogwang
1201a78ce8eSRon if (kev->flags & EV_ERROR) {
121a9643ea8Slogwang event_one |= EPOLLERR;
122a9643ea8Slogwang }
123a9643ea8Slogwang
1241a78ce8eSRon if (kev->flags & EV_EOF) {
1258c317b22Slogwang event_one |= EPOLLHUP;
1268c317b22Slogwang
1278c317b22Slogwang if (kev->fflags) {
1288c317b22Slogwang event_one |= EPOLLERR;
1298c317b22Slogwang }
1308c317b22Slogwang
1318c317b22Slogwang if (kev->filter == EVFILT_READ) {
132a9643ea8Slogwang event_one |= EPOLLIN;
1338c317b22Slogwang } else if (kev->filter == EVFILT_WRITE) {
1348c317b22Slogwang event_one |= EPOLLERR;
1358c317b22Slogwang }
136a9643ea8Slogwang }
137a9643ea8Slogwang
1381a78ce8eSRon (*ppev)->events = event_one;
139*8d6a4447Sdaovanhuy // Fix #124: get user data
140*8d6a4447Sdaovanhuy if (kev->udata != NULL)
141*8d6a4447Sdaovanhuy (*ppev)->data.ptr = kev->udata;
142*8d6a4447Sdaovanhuy else
1431a78ce8eSRon (*ppev)->data.fd = kev->ident;
1441a78ce8eSRon (*ppev)++;
145a9643ea8Slogwang }
146a9643ea8Slogwang
147a9643ea8Slogwang int
ff_epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)1481a78ce8eSRon ff_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
149a9643ea8Slogwang {
1501a78ce8eSRon int i, ret;
1511a78ce8eSRon if (!events || maxevents < 1) {
1521a78ce8eSRon errno = EINVAL;
1531a78ce8eSRon return -1;
1541a78ce8eSRon }
1551a78ce8eSRon
1561a78ce8eSRon return ff_kevent_do_each(epfd, NULL, 0, events, maxevents, NULL, ff_event_to_epoll);
157a9643ea8Slogwang }
158a9643ea8Slogwang
159