1 /* 2 * uloop - event loop implementation 3 * 4 * Copyright (C) 2010-2016 Felix Fietkau <nbd@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 static int uloop_init_pollfd(void) 19 { 20 struct timespec timeout = { 0, 0 }; 21 struct kevent ev = {}; 22 23 if (poll_fd >= 0) 24 return 0; 25 26 poll_fd = kqueue(); 27 if (poll_fd < 0) 28 return -1; 29 30 EV_SET(&ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); 31 kevent(poll_fd, &ev, 1, NULL, 0, &timeout); 32 33 return 0; 34 } 35 36 37 static uint16_t get_flags(unsigned int flags, unsigned int mask) 38 { 39 uint16_t kflags = 0; 40 41 if (!(flags & mask)) 42 return EV_DELETE; 43 44 kflags = EV_ADD; 45 if (flags & ULOOP_EDGE_TRIGGER) 46 kflags |= EV_CLEAR; 47 48 return kflags; 49 } 50 51 static struct kevent events[ULOOP_MAX_EVENTS]; 52 53 static int register_kevent(struct uloop_fd *fd, unsigned int flags) 54 { 55 struct timespec timeout = { 0, 0 }; 56 struct kevent ev[2]; 57 int nev = 0; 58 unsigned int changed; 59 uint16_t kflags; 60 61 if (flags & ULOOP_EDGE_DEFER) 62 flags &= ~ULOOP_EDGE_TRIGGER; 63 64 changed = flags ^ fd->flags; 65 if (changed & ULOOP_EDGE_TRIGGER) 66 changed |= flags; 67 68 if (!changed) 69 return 0; 70 71 if (changed & ULOOP_READ) { 72 kflags = get_flags(flags, ULOOP_READ); 73 EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd); 74 } 75 76 if (changed & ULOOP_WRITE) { 77 kflags = get_flags(flags, ULOOP_WRITE); 78 EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd); 79 } 80 81 if (kevent(poll_fd, ev, nev, NULL, 0, &timeout) == -1) 82 return -1; 83 84 return 0; 85 } 86 87 static int register_poll(struct uloop_fd *fd, unsigned int flags) 88 { 89 if (flags & ULOOP_EDGE_TRIGGER) 90 flags |= ULOOP_EDGE_DEFER; 91 else 92 flags &= ~ULOOP_EDGE_DEFER; 93 94 return register_kevent(fd, flags); 95 } 96 97 static int __uloop_fd_delete(struct uloop_fd *fd) 98 { 99 return register_poll(fd, 0); 100 } 101 102 static int64_t get_timestamp_us(void) 103 { 104 #ifdef CLOCK_MONOTONIC 105 struct timespec ts = { 0, 0 }; 106 107 clock_gettime(CLOCK_MONOTONIC, &ts); 108 109 return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 110 #else 111 struct timeval tv = { 0, 0 }; 112 113 gettimeofday(&tv, NULL); 114 115 return tv.tv_sec * 1000000 + tv.tv_usec; 116 #endif 117 } 118 119 static int uloop_fetch_events(int timeout) 120 { 121 struct timespec ts; 122 int nfds, n; 123 124 if (timeout >= 0) { 125 ts.tv_sec = timeout / 1000; 126 ts.tv_nsec = (timeout % 1000) * 1000000; 127 } 128 129 nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL); 130 for (n = 0; n < nfds; n++) { 131 if (events[n].filter == EVFILT_TIMER) { 132 struct uloop_interval *tm = events[n].udata; 133 134 tm->priv.time.fired = get_timestamp_us(); 135 tm->expirations += events[n].data; 136 tm->cb(tm); 137 138 continue; 139 } 140 141 struct uloop_fd_event *cur = &cur_fds[n]; 142 struct uloop_fd *u = events[n].udata; 143 unsigned int ev = 0; 144 145 cur->fd = u; 146 if (!u) 147 continue; 148 149 if (events[n].flags & EV_ERROR) { 150 u->error = true; 151 if (!(u->flags & ULOOP_ERROR_CB)) 152 uloop_fd_delete(u); 153 } 154 155 if(events[n].filter == EVFILT_READ) 156 ev |= ULOOP_READ; 157 else if (events[n].filter == EVFILT_WRITE) 158 ev |= ULOOP_WRITE; 159 160 if (events[n].flags & EV_EOF) 161 u->eof = true; 162 else if (!ev) 163 cur->fd = NULL; 164 165 cur->events = ev; 166 if (u->flags & ULOOP_EDGE_DEFER) { 167 u->flags &= ~ULOOP_EDGE_DEFER; 168 u->flags |= ULOOP_EDGE_TRIGGER; 169 register_kevent(u, u->flags); 170 } 171 } 172 return nfds; 173 } 174 175 static int timer_register(struct uloop_interval *tm, unsigned int msecs) 176 { 177 struct kevent ev; 178 179 tm->priv.time.msecs = msecs; 180 tm->priv.time.fired = get_timestamp_us(); 181 182 EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, 183 (int64_t)msecs * 1000, tm); 184 185 return kevent(poll_fd, &ev, 1, NULL, 0, NULL); 186 } 187 188 static int timer_remove(struct uloop_interval *tm) 189 { 190 struct kevent ev; 191 192 EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 193 194 return kevent(poll_fd, &ev, 1, NULL, 0, NULL); 195 } 196 197 static int64_t timer_next(struct uloop_interval *tm) 198 { 199 int64_t t1 = tm->priv.time.fired; 200 int64_t t2 = get_timestamp_us(); 201 int64_t step = (int64_t)tm->priv.time.msecs * 1000; 202 203 if (step <= 0) 204 return 0; 205 206 while (t1 < t2) 207 t1 += step; 208 209 return (t1 - t2) / 1000; 210 } 211
This page was automatically generated by LXR 0.3.1. • OpenWrt