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 fl = 0; 59 unsigned int changed; 60 uint16_t kflags; 61 62 if (flags & ULOOP_EDGE_DEFER) 63 flags &= ~ULOOP_EDGE_TRIGGER; 64 65 changed = flags ^ fd->flags; 66 if (changed & ULOOP_EDGE_TRIGGER) 67 changed |= flags; 68 69 if (!changed) 70 return 0; 71 72 if (changed & ULOOP_READ) { 73 kflags = get_flags(flags, ULOOP_READ); 74 EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd); 75 } 76 77 if (changed & ULOOP_WRITE) { 78 kflags = get_flags(flags, ULOOP_WRITE); 79 EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd); 80 } 81 82 if (!flags) 83 fl |= EV_DELETE; 84 85 if (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1) 86 return -1; 87 88 return 0; 89 } 90 91 static int register_poll(struct uloop_fd *fd, unsigned int flags) 92 { 93 if (flags & ULOOP_EDGE_TRIGGER) 94 flags |= ULOOP_EDGE_DEFER; 95 else 96 flags &= ~ULOOP_EDGE_DEFER; 97 98 return register_kevent(fd, flags); 99 } 100 101 static int __uloop_fd_delete(struct uloop_fd *fd) 102 { 103 return register_poll(fd, 0); 104 } 105 106 static int64_t get_timestamp_us(void) 107 { 108 #ifdef CLOCK_MONOTONIC 109 struct timespec ts = { 0, 0 }; 110 111 clock_gettime(CLOCK_MONOTONIC, &ts); 112 113 return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; 114 #else 115 struct timeval tv = { 0, 0 }; 116 117 gettimeofday(&tv, NULL); 118 119 return tv.tv_sec * 1000000 + tv.tv_usec; 120 #endif 121 } 122 123 static int uloop_fetch_events(int timeout) 124 { 125 struct timespec ts; 126 int nfds, n; 127 128 if (timeout >= 0) { 129 ts.tv_sec = timeout / 1000; 130 ts.tv_nsec = (timeout % 1000) * 1000000; 131 } 132 133 nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL); 134 for (n = 0; n < nfds; n++) { 135 if (events[n].filter == EVFILT_TIMER) { 136 struct uloop_interval *tm = events[n].udata; 137 138 tm->priv.time.fired = get_timestamp_us(); 139 tm->expirations += events[n].data; 140 tm->cb(tm); 141 142 continue; 143 } 144 145 struct uloop_fd_event *cur = &cur_fds[n]; 146 struct uloop_fd *u = events[n].udata; 147 unsigned int ev = 0; 148 149 cur->fd = u; 150 if (!u) 151 continue; 152 153 if (events[n].flags & EV_ERROR) { 154 u->error = true; 155 if (!(u->flags & ULOOP_ERROR_CB)) 156 uloop_fd_delete(u); 157 } 158 159 if(events[n].filter == EVFILT_READ) 160 ev |= ULOOP_READ; 161 else if (events[n].filter == EVFILT_WRITE) 162 ev |= ULOOP_WRITE; 163 164 if (events[n].flags & EV_EOF) 165 u->eof = true; 166 else if (!ev) 167 cur->fd = NULL; 168 169 cur->events = ev; 170 if (u->flags & ULOOP_EDGE_DEFER) { 171 u->flags &= ~ULOOP_EDGE_DEFER; 172 u->flags |= ULOOP_EDGE_TRIGGER; 173 register_kevent(u, u->flags); 174 } 175 } 176 return nfds; 177 } 178 179 static int timer_register(struct uloop_interval *tm, unsigned int msecs) 180 { 181 struct kevent ev; 182 183 tm->priv.time.msecs = msecs; 184 tm->priv.time.fired = get_timestamp_us(); 185 186 EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, msecs * 1000, tm); 187 188 return kevent(poll_fd, &ev, 1, NULL, 0, NULL); 189 } 190 191 static int timer_remove(struct uloop_interval *tm) 192 { 193 struct kevent ev; 194 195 EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); 196 197 return kevent(poll_fd, &ev, 1, NULL, 0, NULL); 198 } 199 200 static int64_t timer_next(struct uloop_interval *tm) 201 { 202 int64_t t1 = tm->priv.time.fired; 203 int64_t t2 = get_timestamp_us(); 204 205 while (t1 < t2) 206 t1 += tm->priv.time.msecs * 1000; 207 208 return (t1 - t2) / 1000; 209 } 210
This page was automatically generated by LXR 0.3.1. • OpenWrt