uloop: add back support for overriding signal handlers when signalfd is in use
[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
19 static bool
20 uloop_setup_signalfd(bool add)
21 {
22 return false;
23 }
24
25 int uloop_init(void)
26 {
27 struct timespec timeout = { 0, 0 };
28 struct kevent ev = {};
29
30 if (poll_fd >= 0)
31 return 0;
32
33 poll_fd = kqueue();
34 if (poll_fd < 0)
35 return -1;
36
37 EV_SET(&ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
38 kevent(poll_fd, &ev, 1, NULL, 0, &timeout);
39
40 return 0;
41 }
42
43
44 static uint16_t get_flags(unsigned int flags, unsigned int mask)
45 {
46 uint16_t kflags = 0;
47
48 if (!(flags & mask))
49 return EV_DELETE;
50
51 kflags = EV_ADD;
52 if (flags & ULOOP_EDGE_TRIGGER)
53 kflags |= EV_CLEAR;
54
55 return kflags;
56 }
57
58 static struct kevent events[ULOOP_MAX_EVENTS];
59
60 static int register_kevent(struct uloop_fd *fd, unsigned int flags)
61 {
62 struct timespec timeout = { 0, 0 };
63 struct kevent ev[2];
64 int nev = 0;
65 unsigned int fl = 0;
66 unsigned int changed;
67 uint16_t kflags;
68
69 if (flags & ULOOP_EDGE_DEFER)
70 flags &= ~ULOOP_EDGE_TRIGGER;
71
72 changed = flags ^ fd->flags;
73 if (changed & ULOOP_EDGE_TRIGGER)
74 changed |= flags;
75
76 if (changed & ULOOP_READ) {
77 kflags = get_flags(flags, ULOOP_READ);
78 EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd);
79 }
80
81 if (changed & ULOOP_WRITE) {
82 kflags = get_flags(flags, ULOOP_WRITE);
83 EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd);
84 }
85
86 if (!flags)
87 fl |= EV_DELETE;
88
89 fd->flags = flags;
90 if (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)
91 return -1;
92
93 return 0;
94 }
95
96 static int register_poll(struct uloop_fd *fd, unsigned int flags)
97 {
98 if (flags & ULOOP_EDGE_TRIGGER)
99 flags |= ULOOP_EDGE_DEFER;
100 else
101 flags &= ~ULOOP_EDGE_DEFER;
102
103 return register_kevent(fd, flags);
104 }
105
106 static int __uloop_fd_delete(struct uloop_fd *fd)
107 {
108 return register_poll(fd, 0);
109 }
110
111 static int uloop_fetch_events(int timeout)
112 {
113 struct timespec ts;
114 int nfds, n;
115
116 if (timeout >= 0) {
117 ts.tv_sec = timeout / 1000;
118 ts.tv_nsec = (timeout % 1000) * 1000000;
119 }
120
121 nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL);
122 for (n = 0; n < nfds; n++) {
123 struct uloop_fd_event *cur = &cur_fds[n];
124 struct uloop_fd *u = events[n].udata;
125 unsigned int ev = 0;
126
127 cur->fd = u;
128 if (!u)
129 continue;
130
131 if (events[n].flags & EV_ERROR) {
132 u->error = true;
133 if (!(u->flags & ULOOP_ERROR_CB))
134 uloop_fd_delete(u);
135 }
136
137 if(events[n].filter == EVFILT_READ)
138 ev |= ULOOP_READ;
139 else if (events[n].filter == EVFILT_WRITE)
140 ev |= ULOOP_WRITE;
141
142 if (events[n].flags & EV_EOF)
143 u->eof = true;
144 else if (!ev)
145 cur->fd = NULL;
146
147 cur->events = ev;
148 if (u->flags & ULOOP_EDGE_DEFER) {
149 u->flags &= ~ULOOP_EDGE_DEFER;
150 u->flags |= ULOOP_EDGE_TRIGGER;
151 register_kevent(u, u->flags);
152 }
153 }
154 return nfds;
155 }