xref: /f-stack/lib/ff_epoll.c (revision 8d6a4447)
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