1 /*-
2 * Copyright (c) 2015 Nuxi, https://nuxi.nl/
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/proc.h>
31 #include <sys/syscallsubr.h>
32
33 #include <contrib/cloudabi/cloudabi32_types.h>
34
35 #include <compat/cloudabi/cloudabi_util.h>
36
37 #include <compat/cloudabi32/cloudabi32_proto.h>
38 #include <compat/cloudabi32/cloudabi32_util.h>
39
40 /* Converts a FreeBSD signal number to a CloudABI signal number. */
41 static cloudabi_signal_t
42 convert_signal(int sig)
43 {
44 static const cloudabi_signal_t signals[] = {
45 [SIGABRT] = CLOUDABI_SIGABRT,
46 [SIGALRM] = CLOUDABI_SIGALRM,
47 [SIGBUS] = CLOUDABI_SIGBUS,
48 [SIGCHLD] = CLOUDABI_SIGCHLD,
49 [SIGCONT] = CLOUDABI_SIGCONT,
50 [SIGFPE] = CLOUDABI_SIGFPE,
51 [SIGHUP] = CLOUDABI_SIGHUP,
52 [SIGILL] = CLOUDABI_SIGILL,
53 [SIGINT] = CLOUDABI_SIGINT,
54 [SIGKILL] = CLOUDABI_SIGKILL,
55 [SIGPIPE] = CLOUDABI_SIGPIPE,
56 [SIGQUIT] = CLOUDABI_SIGQUIT,
57 [SIGSEGV] = CLOUDABI_SIGSEGV,
58 [SIGSTOP] = CLOUDABI_SIGSTOP,
59 [SIGSYS] = CLOUDABI_SIGSYS,
60 [SIGTERM] = CLOUDABI_SIGTERM,
61 [SIGTRAP] = CLOUDABI_SIGTRAP,
62 [SIGTSTP] = CLOUDABI_SIGTSTP,
63 [SIGTTIN] = CLOUDABI_SIGTTIN,
64 [SIGTTOU] = CLOUDABI_SIGTTOU,
65 [SIGURG] = CLOUDABI_SIGURG,
66 [SIGUSR1] = CLOUDABI_SIGUSR1,
67 [SIGUSR2] = CLOUDABI_SIGUSR2,
68 [SIGVTALRM] = CLOUDABI_SIGVTALRM,
69 [SIGXCPU] = CLOUDABI_SIGXCPU,
70 [SIGXFSZ] = CLOUDABI_SIGXFSZ,
71 };
72
73 /* Convert unknown signals to SIGABRT. */
74 if (sig < 0 || sig >= nitems(signals) || signals[sig] == 0)
75 return (SIGABRT);
76 return (signals[sig]);
77 }
78
79 struct cloudabi32_kevent_args {
80 const cloudabi32_subscription_t *in;
81 cloudabi_event_t *out;
82 };
83
84 /* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
85 static int
86 cloudabi32_kevent_copyin(void *arg, struct kevent *kevp, int count)
87 {
88 cloudabi32_subscription_t sub;
89 struct cloudabi32_kevent_args *args;
90 cloudabi_timestamp_t ts;
91 int error;
92
93 args = arg;
94 while (count-- > 0) {
95 /* TODO(ed): Copy in multiple entries at once. */
96 error = copyin(args->in++, &sub, sizeof(sub));
97 if (error != 0)
98 return (error);
99
100 memset(kevp, 0, sizeof(*kevp));
101 kevp->udata = TO_PTR(sub.userdata);
102 switch (sub.type) {
103 case CLOUDABI_EVENTTYPE_CLOCK:
104 kevp->filter = EVFILT_TIMER;
105 kevp->ident = sub.clock.identifier;
106 kevp->fflags = NOTE_NSECONDS;
107 if ((sub.clock.flags &
108 CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 &&
109 sub.clock.timeout > 0) {
110 /* Convert absolute timestamp to a relative. */
111 error = cloudabi_clock_time_get(curthread,
112 sub.clock.clock_id, &ts);
113 if (error != 0)
114 return (error);
115 ts = ts > sub.clock.timeout ? 0 :
116 sub.clock.timeout - ts;
117 } else {
118 /* Relative timestamp. */
119 ts = sub.clock.timeout;
120 }
121 kevp->data = ts > INTPTR_MAX ? INTPTR_MAX : ts;
122 break;
123 case CLOUDABI_EVENTTYPE_FD_READ:
124 kevp->filter = EVFILT_READ;
125 kevp->ident = sub.fd_readwrite.fd;
126 kevp->fflags = NOTE_FILE_POLL;
127 break;
128 case CLOUDABI_EVENTTYPE_FD_WRITE:
129 kevp->filter = EVFILT_WRITE;
130 kevp->ident = sub.fd_readwrite.fd;
131 break;
132 case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
133 kevp->filter = EVFILT_PROCDESC;
134 kevp->ident = sub.proc_terminate.fd;
135 kevp->fflags = NOTE_EXIT;
136 break;
137 }
138 kevp->flags = EV_ADD | EV_ONESHOT;
139 ++kevp;
140 }
141 return (0);
142 }
143
144 /* Converts FreeBSD's struct kevent to CloudABI's event objects. */
145 static int
146 cloudabi32_kevent_copyout(void *arg, struct kevent *kevp, int count)
147 {
148 cloudabi_event_t ev;
149 struct cloudabi32_kevent_args *args;
150 int error;
151
152 args = arg;
153 while (count-- > 0) {
154 /* Convert fields that should always be present. */
155 memset(&ev, 0, sizeof(ev));
156 ev.userdata = (uintptr_t)kevp->udata;
157 switch (kevp->filter) {
158 case EVFILT_TIMER:
159 ev.type = CLOUDABI_EVENTTYPE_CLOCK;
160 break;
161 case EVFILT_READ:
162 ev.type = CLOUDABI_EVENTTYPE_FD_READ;
163 break;
164 case EVFILT_WRITE:
165 ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
166 break;
167 case EVFILT_PROCDESC:
168 ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
169 break;
170 }
171
172 if ((kevp->flags & EV_ERROR) == 0) {
173 /* Success. */
174 switch (kevp->filter) {
175 case EVFILT_READ:
176 case EVFILT_WRITE:
177 ev.fd_readwrite.nbytes = kevp->data;
178 if ((kevp->flags & EV_EOF) != 0) {
179 ev.fd_readwrite.flags |=
180 CLOUDABI_EVENT_FD_READWRITE_HANGUP;
181 }
182 break;
183 case EVFILT_PROCDESC:
184 if (WIFSIGNALED(kevp->data)) {
185 /* Process got signalled. */
186 ev.proc_terminate.signal =
187 convert_signal(WTERMSIG(kevp->data));
188 ev.proc_terminate.exitcode = 0;
189 } else {
190 /* Process exited. */
191 ev.proc_terminate.signal = 0;
192 ev.proc_terminate.exitcode =
193 WEXITSTATUS(kevp->data);
194 }
195 break;
196 }
197 } else {
198 /* Error. */
199 ev.error = cloudabi_convert_errno(kevp->data);
200 }
201 ++kevp;
202
203 /* TODO(ed): Copy out multiple entries at once. */
204 error = copyout(&ev, args->out++, sizeof(ev));
205 if (error != 0)
206 return (error);
207 }
208 return (0);
209 }
210
211 int
212 cloudabi32_sys_poll(struct thread *td, struct cloudabi32_sys_poll_args *uap)
213 {
214 struct cloudabi32_kevent_args args = {
215 .in = uap->in,
216 .out = uap->out,
217 };
218 struct kevent_copyops copyops = {
219 .k_copyin = cloudabi32_kevent_copyin,
220 .k_copyout = cloudabi32_kevent_copyout,
221 .arg = &args,
222 };
223
224 /*
225 * Bandaid to support CloudABI futex constructs that are not
226 * implemented through FreeBSD's kqueue().
227 */
228 if (uap->nsubscriptions == 1) {
229 cloudabi32_subscription_t sub;
230 cloudabi_event_t ev = {};
231 int error;
232
233 error = copyin(uap->in, &sub, sizeof(sub));
234 if (error != 0)
235 return (error);
236 ev.userdata = sub.userdata;
237 ev.type = sub.type;
238 if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
239 /* Wait on a condition variable. */
240 ev.error = cloudabi_convert_errno(
241 cloudabi_futex_condvar_wait(
242 td, TO_PTR(sub.condvar.condvar),
243 sub.condvar.condvar_scope,
244 TO_PTR(sub.condvar.lock),
245 sub.condvar.lock_scope,
246 CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0, true));
247 td->td_retval[0] = 1;
248 return (copyout(&ev, uap->out, sizeof(ev)));
249 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
250 /* Acquire a read lock. */
251 ev.error = cloudabi_convert_errno(
252 cloudabi_futex_lock_rdlock(
253 td, TO_PTR(sub.lock.lock),
254 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
255 UINT64_MAX, 0, true));
256 td->td_retval[0] = 1;
257 return (copyout(&ev, uap->out, sizeof(ev)));
258 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
259 /* Acquire a write lock. */
260 ev.error = cloudabi_convert_errno(
261 cloudabi_futex_lock_wrlock(
262 td, TO_PTR(sub.lock.lock),
263 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
264 UINT64_MAX, 0, true));
265 td->td_retval[0] = 1;
266 return (copyout(&ev, uap->out, sizeof(ev)));
267 }
268 } else if (uap->nsubscriptions == 2) {
269 cloudabi32_subscription_t sub[2];
270 cloudabi_event_t ev[2] = {};
271 int error;
272
273 error = copyin(uap->in, &sub, sizeof(sub));
274 if (error != 0)
275 return (error);
276 ev[0].userdata = sub[0].userdata;
277 ev[0].type = sub[0].type;
278 ev[1].userdata = sub[1].userdata;
279 ev[1].type = sub[1].type;
280 if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
281 sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
282 /* Wait for a condition variable with timeout. */
283 error = cloudabi_futex_condvar_wait(
284 td, TO_PTR(sub[0].condvar.condvar),
285 sub[0].condvar.condvar_scope,
286 TO_PTR(sub[0].condvar.lock),
287 sub[0].condvar.lock_scope, sub[1].clock.clock_id,
288 sub[1].clock.timeout, sub[1].clock.precision,
289 (sub[1].clock.flags &
290 CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
291 if (error == ETIMEDOUT) {
292 td->td_retval[0] = 1;
293 return (copyout(&ev[1], uap->out,
294 sizeof(ev[1])));
295 }
296
297 ev[0].error = cloudabi_convert_errno(error);
298 td->td_retval[0] = 1;
299 return (copyout(&ev[0], uap->out, sizeof(ev[0])));
300 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
301 sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
302 /* Acquire a read lock with a timeout. */
303 error = cloudabi_futex_lock_rdlock(
304 td, TO_PTR(sub[0].lock.lock),
305 sub[0].lock.lock_scope, sub[1].clock.clock_id,
306 sub[1].clock.timeout, sub[1].clock.precision,
307 (sub[1].clock.flags &
308 CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
309 if (error == ETIMEDOUT) {
310 td->td_retval[0] = 1;
311 return (copyout(&ev[1], uap->out,
312 sizeof(ev[1])));
313 }
314
315 ev[0].error = cloudabi_convert_errno(error);
316 td->td_retval[0] = 1;
317 return (copyout(&ev[0], uap->out, sizeof(ev[0])));
318 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
319 sub[1].type == CLOUDABI_EVENTTYPE_CLOCK) {
320 /* Acquire a write lock with a timeout. */
321 error = cloudabi_futex_lock_wrlock(
322 td, TO_PTR(sub[0].lock.lock),
323 sub[0].lock.lock_scope, sub[1].clock.clock_id,
324 sub[1].clock.timeout, sub[1].clock.precision,
325 (sub[1].clock.flags &
326 CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0);
327 if (error == ETIMEDOUT) {
328 td->td_retval[0] = 1;
329 return (copyout(&ev[1], uap->out,
330 sizeof(ev[1])));
331 }
332
333 ev[0].error = cloudabi_convert_errno(error);
334 td->td_retval[0] = 1;
335 return (copyout(&ev[0], uap->out, sizeof(ev[0])));
336 }
337 }
338
339 return (kern_kevent_anonymous(td, uap->nsubscriptions, ©ops));
340 }
Cache object: f6e0041532918c6add894fb00e7a109d
|