1 #include <stdio.h> 2 #include <stdint.h> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <stdarg.h> 6 #include <sched.h> 7 #include <fcntl.h> 8 #include <errno.h> 9 #include <assert.h> 10 #include <unistd.h> 11 #include <netinet/in.h> 12 #include <sys/types.h> 13 #include <sys/socket.h> 14 #include <sys/time.h> 15 #include <sys/select.h> 16 #include <sys/syscall.h> 17 #include <arpa/inet.h> 18 #include <sys/epoll.h> 19 20 #include "ff_api.h" 21 #include "ff_errno.h" 22 23 24 int 25 ff_epoll_create(int size __attribute__((__unused__))) 26 { 27 return ff_kqueue(); 28 } 29 30 int 31 ff_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 32 { 33 /* 34 * Since kqueue uses EVFILT_READ and EVFILT_WRITE filters to 35 * handle read/write events, so we need two kevents. 36 */ 37 const int changes = 2; 38 struct kevent kev[changes]; 39 int flags = 0; 40 int read_flags, write_flags; 41 42 if ((!event && op != EPOLL_CTL_DEL) || 43 (op != EPOLL_CTL_ADD && 44 op != EPOLL_CTL_MOD && 45 op != EPOLL_CTL_DEL)) { 46 errno = EINVAL; 47 return -1; 48 } 49 50 /* 51 * EPOLL_CTL_DEL doesn't need to care for event->events. 52 */ 53 if (op == EPOLL_CTL_DEL) { 54 EV_SET(&kev[0], fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); 55 EV_SET(&kev[1], fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); 56 57 return ff_kevent(epfd, kev, changes, NULL, 0, NULL); 58 } 59 60 /* 61 * FIXME: 62 * 63 * Kqueue doesn't have edge-triggered mode that exactly 64 * same with epoll, the most similar way is setting EV_CLEAR 65 * or EV_DISPATCH flag, but there are still some differences. 66 * 67 * EV_CLEAR:after the event is retrieved by the user, 68 * its state is reset. 69 * EV_DISPATCH: disable the event source immediately 70 * after delivery of an event. 71 * 72 * Here we use EV_CLEAR temporarily. 73 * 74 */ 75 if (event->events & EPOLLET) { 76 flags |= EV_CLEAR; 77 } 78 79 if (event->events & EPOLLONESHOT) { 80 flags |= EV_ONESHOT; 81 } 82 83 if (op == EPOLL_CTL_ADD) { 84 flags |= EV_ADD; 85 } 86 87 read_flags = write_flags = flags | EV_DISABLE; 88 89 if (event->events & EPOLLIN) { 90 read_flags &= ~EV_DISABLE; 91 read_flags |= EV_ENABLE; 92 } 93 94 if (event->events & EPOLLOUT) { 95 write_flags &= ~EV_DISABLE; 96 write_flags |= EV_ENABLE; 97 } 98 99 // Fix #124: set user data 100 EV_SET(&kev[0], fd, EVFILT_READ, read_flags, 0, 0, event->data.ptr); 101 EV_SET(&kev[1], fd, EVFILT_WRITE, write_flags, 0, 0, event->data.ptr); 102 103 return ff_kevent(epfd, kev, changes, NULL, 0, NULL); 104 } 105 106 static void 107 ff_event_to_epoll(void **ev, struct kevent *kev) 108 { 109 unsigned int event_one = 0; 110 struct epoll_event **ppev = (struct epoll_event **)ev; 111 112 if (kev->filter == EVFILT_READ) { 113 if (kev->data || !(kev->flags & EV_EOF)) { 114 event_one |= EPOLLIN; 115 } 116 } else if (kev->filter == EVFILT_WRITE) { 117 event_one |= EPOLLOUT; 118 } 119 120 if (kev->flags & EV_ERROR) { 121 event_one |= EPOLLERR; 122 } 123 124 if (kev->flags & EV_EOF) { 125 event_one |= EPOLLHUP; 126 127 if (kev->fflags) { 128 event_one |= EPOLLERR; 129 } 130 131 if (kev->filter == EVFILT_READ) { 132 event_one |= EPOLLIN; 133 } else if (kev->filter == EVFILT_WRITE) { 134 event_one |= EPOLLERR; 135 } 136 } 137 138 (*ppev)->events = event_one; 139 // Fix #124: get user data 140 if (kev->udata != NULL) 141 (*ppev)->data.ptr = kev->udata; 142 else 143 (*ppev)->data.fd = kev->ident; 144 (*ppev)++; 145 } 146 147 int 148 ff_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 149 { 150 int i, ret; 151 if (!events || maxevents < 1) { 152 errno = EINVAL; 153 return -1; 154 } 155 156 return ff_kevent_do_each(epfd, NULL, 0, events, maxevents, NULL, ff_event_to_epoll); 157 } 158 159