ustream: prevent recursive calls to the read callback
[project/libubox.git] / uloop-kqueue.c
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 }