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 EV_SET(&kev[0], fd, EVFILT_READ, read_flags, 0, 0, NULL); 100 EV_SET(&kev[1], fd, EVFILT_WRITE, write_flags, 0, 0, NULL); 101 102 return ff_kevent(epfd, kev, changes, NULL, 0, NULL); 103 } 104 105 static void 106 ff_event_to_epoll(void **ev, struct kevent *kev) 107 { 108 unsigned int event_one = 0; 109 struct epoll_event **ppev = (struct epoll_event **)ev; 110 111 if (kev->filter == EVFILT_READ) { 112 if (kev->data || !(kev->flags & EV_EOF)) { 113 event_one |= EPOLLIN; 114 } 115 } else if (kev->filter == EVFILT_WRITE) { 116 event_one |= EPOLLOUT; 117 } 118 119 if (kev->flags & EV_ERROR) { 120 event_one |= EPOLLERR; 121 } 122 123 if (kev->flags & EV_EOF) { 124 event_one |= EPOLLHUP; 125 126 if (kev->fflags) { 127 event_one |= EPOLLERR; 128 } 129 130 if (kev->filter == EVFILT_READ) { 131 event_one |= EPOLLIN; 132 } else if (kev->filter == EVFILT_WRITE) { 133 event_one |= EPOLLERR; 134 } 135 } 136 137 (*ppev)->events = event_one; 138 (*ppev)->data.fd = kev->ident; 139 (*ppev)++; 140 } 141 142 int 143 ff_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) 144 { 145 int i, ret; 146 if (!events || maxevents < 1) { 147 errno = EINVAL; 148 return -1; 149 } 150 151 return ff_kevent_do_each(epfd, NULL, 0, events, maxevents, NULL, ff_event_to_epoll); 152 } 153 154