]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/cloudabi64/cloudabi64_poll.c
Update libc++ to 3.8.0. Excerpted list of fixes (with upstream revision
[FreeBSD/FreeBSD.git] / sys / compat / cloudabi64 / cloudabi64_poll.c
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/cloudabi64_types.h>
34
35 #include <compat/cloudabi/cloudabi_util.h>
36
37 #include <compat/cloudabi64/cloudabi64_proto.h>
38
39 /* Converts a FreeBSD signal number to a CloudABI signal number. */
40 static cloudabi_signal_t
41 convert_signal(int sig)
42 {
43         static const cloudabi_signal_t signals[] = {
44                 [SIGABRT]       = CLOUDABI_SIGABRT,
45                 [SIGALRM]       = CLOUDABI_SIGALRM,
46                 [SIGBUS]        = CLOUDABI_SIGBUS,
47                 [SIGCHLD]       = CLOUDABI_SIGCHLD,
48                 [SIGCONT]       = CLOUDABI_SIGCONT,
49                 [SIGFPE]        = CLOUDABI_SIGFPE,
50                 [SIGHUP]        = CLOUDABI_SIGHUP,
51                 [SIGILL]        = CLOUDABI_SIGILL,
52                 [SIGINT]        = CLOUDABI_SIGINT,
53                 [SIGKILL]       = CLOUDABI_SIGKILL,
54                 [SIGPIPE]       = CLOUDABI_SIGPIPE,
55                 [SIGQUIT]       = CLOUDABI_SIGQUIT,
56                 [SIGSEGV]       = CLOUDABI_SIGSEGV,
57                 [SIGSTOP]       = CLOUDABI_SIGSTOP,
58                 [SIGSYS]        = CLOUDABI_SIGSYS,
59                 [SIGTERM]       = CLOUDABI_SIGTERM,
60                 [SIGTRAP]       = CLOUDABI_SIGTRAP,
61                 [SIGTSTP]       = CLOUDABI_SIGTSTP,
62                 [SIGTTIN]       = CLOUDABI_SIGTTIN,
63                 [SIGTTOU]       = CLOUDABI_SIGTTOU,
64                 [SIGURG]        = CLOUDABI_SIGURG,
65                 [SIGUSR1]       = CLOUDABI_SIGUSR1,
66                 [SIGUSR2]       = CLOUDABI_SIGUSR2,
67                 [SIGVTALRM]     = CLOUDABI_SIGVTALRM,
68                 [SIGXCPU]       = CLOUDABI_SIGXCPU,
69                 [SIGXFSZ]       = CLOUDABI_SIGXFSZ,
70         };
71
72         /* Convert unknown signals to SIGABRT. */
73         if (sig < 0 || sig >= nitems(signals) || signals[sig] == 0)
74                 return (SIGABRT);
75         return (signals[sig]);
76 }
77
78 struct cloudabi64_kevent_args {
79         const cloudabi64_subscription_t *in;
80         cloudabi64_event_t *out;
81         bool once;
82 };
83
84 /* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
85 static int
86 cloudabi64_kevent_copyin(void *arg, struct kevent *kevp, int count)
87 {
88         cloudabi64_subscription_t sub;
89         struct cloudabi64_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 = (void *)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                         if ((sub.fd_readwrite.flags &
127                             CLOUDABI_SUBSCRIPTION_FD_READWRITE_POLL) != 0)
128                                 kevp->fflags = NOTE_FILE_POLL;
129                         break;
130                 case CLOUDABI_EVENTTYPE_FD_WRITE:
131                         kevp->filter = EVFILT_WRITE;
132                         kevp->ident = sub.fd_readwrite.fd;
133                         break;
134                 case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
135                         kevp->filter = EVFILT_PROCDESC;
136                         kevp->ident = sub.proc_terminate.fd;
137                         kevp->fflags = NOTE_EXIT;
138                         break;
139                 }
140                 if (args->once) {
141                         /* Ignore flags. Simply use oneshot mode. */
142                         kevp->flags = EV_ADD | EV_ONESHOT;
143                 } else {
144                         /* Translate flags. */
145                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ADD) != 0)
146                                 kevp->flags |= EV_ADD;
147                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_CLEAR) != 0)
148                                 kevp->flags |= EV_CLEAR;
149                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_DELETE) != 0)
150                                 kevp->flags |= EV_DELETE;
151                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_DISABLE) != 0)
152                                 kevp->flags |= EV_DISABLE;
153                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ENABLE) != 0)
154                                 kevp->flags |= EV_ENABLE;
155                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ONESHOT) != 0)
156                                 kevp->flags |= EV_ONESHOT;
157                 }
158                 ++kevp;
159         }
160         return (0);
161 }
162
163 /* Converts FreeBSD's struct kevent to CloudABI's event objects. */
164 static int
165 cloudabi64_kevent_copyout(void *arg, struct kevent *kevp, int count)
166 {
167         cloudabi64_event_t ev;
168         struct cloudabi64_kevent_args *args;
169         int error;
170
171         args = arg;
172         while (count-- > 0) {
173                 /* Convert fields that should always be present. */
174                 memset(&ev, 0, sizeof(ev));
175                 ev.userdata = (uintptr_t)kevp->udata;
176                 switch (kevp->filter) {
177                 case EVFILT_TIMER:
178                         ev.type = CLOUDABI_EVENTTYPE_CLOCK;
179                         ev.clock.identifier = kevp->ident;
180                         break;
181                 case EVFILT_READ:
182                         ev.type = CLOUDABI_EVENTTYPE_FD_READ;
183                         ev.fd_readwrite.fd = kevp->ident;
184                         break;
185                 case EVFILT_WRITE:
186                         ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
187                         ev.fd_readwrite.fd = kevp->ident;
188                         break;
189                 case EVFILT_PROCDESC:
190                         ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
191                         ev.proc_terminate.fd = kevp->ident;
192                         break;
193                 }
194
195                 if ((kevp->flags & EV_ERROR) == 0) {
196                         /* Success. */
197                         switch (kevp->filter) {
198                         case EVFILT_READ:
199                         case EVFILT_WRITE:
200                                 ev.fd_readwrite.nbytes = kevp->data;
201                                 if ((kevp->flags & EV_EOF) != 0) {
202                                         ev.fd_readwrite.flags |=
203                                             CLOUDABI_EVENT_FD_READWRITE_HANGUP;
204                                 }
205                                 break;
206                         case EVFILT_PROCDESC:
207                                 if (WIFSIGNALED(kevp->data)) {
208                                         /* Process got signalled. */
209                                         ev.proc_terminate.signal =
210                                            convert_signal(WTERMSIG(kevp->data));
211                                         ev.proc_terminate.exitcode = 0;
212                                 } else {
213                                         /* Process exited. */
214                                         ev.proc_terminate.signal = 0;
215                                         ev.proc_terminate.exitcode =
216                                             WEXITSTATUS(kevp->data);
217                                 }
218                                 break;
219                         }
220                 } else {
221                         /* Error. */
222                         ev.error = cloudabi_convert_errno(kevp->data);
223                 }
224                 ++kevp;
225
226                 /* TODO(ed): Copy out multiple entries at once. */
227                 error = copyout(&ev, args->out++, sizeof(ev));
228                 if (error != 0)
229                         return (error);
230         }
231         return (0);
232 }
233
234 int
235 cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
236 {
237         struct cloudabi64_kevent_args args = {
238                 .in     = uap->in,
239                 .out    = uap->out,
240                 .once   = true,
241         };
242         struct kevent_copyops copyops = {
243                 .k_copyin       = cloudabi64_kevent_copyin,
244                 .k_copyout      = cloudabi64_kevent_copyout,
245                 .arg            = &args,
246         };
247
248         /*
249          * Bandaid to support CloudABI futex constructs that are not
250          * implemented through FreeBSD's kqueue().
251          */
252         if (uap->nsubscriptions == 1) {
253                 cloudabi64_subscription_t sub;
254                 cloudabi64_event_t ev = {};
255                 int error;
256
257                 error = copyin(uap->in, &sub, sizeof(sub));
258                 if (error != 0)
259                         return (error);
260                 ev.userdata = sub.userdata;
261                 ev.type = sub.type;
262                 if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
263                         /* Wait on a condition variable. */
264                         ev.condvar.condvar = sub.condvar.condvar;
265                         ev.error = cloudabi_convert_errno(
266                             cloudabi_futex_condvar_wait(
267                                 td, (cloudabi_condvar_t *)sub.condvar.condvar,
268                                 sub.condvar.condvar_scope,
269                                 (cloudabi_lock_t *)sub.condvar.lock,
270                                 sub.condvar.lock_scope,
271                                 CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0));
272                         td->td_retval[0] = 1;
273                         return (copyout(&ev, uap->out, sizeof(ev)));
274                 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
275                         /* Acquire a read lock. */
276                         ev.lock.lock = sub.lock.lock;
277                         ev.error = cloudabi_convert_errno(
278                             cloudabi_futex_lock_rdlock(
279                                 td, (cloudabi_lock_t *)sub.lock.lock,
280                                 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
281                                 UINT64_MAX, 0));
282                         td->td_retval[0] = 1;
283                         return (copyout(&ev, uap->out, sizeof(ev)));
284                 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
285                         /* Acquire a write lock. */
286                         ev.lock.lock = sub.lock.lock;
287                         ev.error = cloudabi_convert_errno(
288                             cloudabi_futex_lock_wrlock(
289                                 td, (cloudabi_lock_t *)sub.lock.lock,
290                                 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
291                                 UINT64_MAX, 0));
292                         td->td_retval[0] = 1;
293                         return (copyout(&ev, uap->out, sizeof(ev)));
294                 }
295         } else if (uap->nsubscriptions == 2) {
296                 cloudabi64_subscription_t sub[2];
297                 cloudabi64_event_t ev[2] = {};
298                 int error;
299
300                 error = copyin(uap->in, &sub, sizeof(sub));
301                 if (error != 0)
302                         return (error);
303                 ev[0].userdata = sub[0].userdata;
304                 ev[0].type = sub[0].type;
305                 ev[1].userdata = sub[1].userdata;
306                 ev[1].type = sub[1].type;
307                 if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
308                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
309                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
310                         /* Wait for a condition variable with timeout. */
311                         ev[0].condvar.condvar = sub[0].condvar.condvar;
312                         ev[1].clock.identifier = sub[1].clock.identifier;
313                         error = cloudabi_futex_condvar_wait(
314                             td, (cloudabi_condvar_t *)sub[0].condvar.condvar,
315                             sub[0].condvar.condvar_scope,
316                             (cloudabi_lock_t *)sub[0].condvar.lock,
317                             sub[0].condvar.lock_scope, sub[1].clock.clock_id,
318                             sub[1].clock.timeout, sub[1].clock.precision);
319                         if (error == ETIMEDOUT) {
320                                 td->td_retval[0] = 1;
321                                 return (copyout(&ev[1], uap->out,
322                                     sizeof(ev[1])));
323                         }
324
325                         ev[0].error = cloudabi_convert_errno(error);
326                         td->td_retval[0] = 1;
327                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
328                 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
329                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
330                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
331                         /* Acquire a read lock with a timeout. */
332                         ev[0].lock.lock = sub[0].lock.lock;
333                         ev[1].clock.identifier = sub[1].clock.identifier;
334                         error = cloudabi_futex_lock_rdlock(
335                             td, (cloudabi_lock_t *)sub[0].lock.lock,
336                             sub[0].lock.lock_scope, sub[1].clock.clock_id,
337                             sub[1].clock.timeout, sub[1].clock.precision);
338                         if (error == ETIMEDOUT) {
339                                 td->td_retval[0] = 1;
340                                 return (copyout(&ev[1], uap->out,
341                                     sizeof(ev[1])));
342                         }
343
344                         ev[0].error = cloudabi_convert_errno(error);
345                         td->td_retval[0] = 1;
346                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
347                 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
348                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
349                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
350                         /* Acquire a write lock with a timeout. */
351                         ev[0].lock.lock = sub[0].lock.lock;
352                         ev[1].clock.identifier = sub[1].clock.identifier;
353                         error = cloudabi_futex_lock_wrlock(
354                             td, (cloudabi_lock_t *)sub[0].lock.lock,
355                             sub[0].lock.lock_scope, sub[1].clock.clock_id,
356                             sub[1].clock.timeout, sub[1].clock.precision);
357                         if (error == ETIMEDOUT) {
358                                 td->td_retval[0] = 1;
359                                 return (copyout(&ev[1], uap->out,
360                                     sizeof(ev[1])));
361                         }
362
363                         ev[0].error = cloudabi_convert_errno(error);
364                         td->td_retval[0] = 1;
365                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
366                 }
367         }
368
369         return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
370 }
371
372 int
373 cloudabi64_sys_poll_fd(struct thread *td,
374     struct cloudabi64_sys_poll_fd_args *uap)
375 {
376         struct cloudabi64_kevent_args args = {
377                 .in     = uap->in,
378                 .out    = uap->out,
379                 .once   = false,
380         };
381         struct kevent_copyops copyops = {
382                 .k_copyin       = cloudabi64_kevent_copyin,
383                 .k_copyout      = cloudabi64_kevent_copyout,
384                 .arg            = &args,
385         };
386         cloudabi64_subscription_t subtimo;
387         struct timespec timeout;
388         int error;
389
390         if (uap->timeout != NULL) {
391                 /* Poll with a timeout. */
392                 error = copyin(uap->timeout, &subtimo, sizeof(subtimo));
393                 if (error != 0)
394                         return (error);
395                 if (subtimo.type != CLOUDABI_EVENTTYPE_CLOCK ||
396                     subtimo.clock.flags != 0)
397                         return (EINVAL);
398                 timeout.tv_sec = subtimo.clock.timeout / 1000000000;
399                 timeout.tv_nsec = subtimo.clock.timeout % 1000000000;
400                 return (kern_kevent(td, uap->fd, uap->nin, uap->nout, &copyops,
401                     &timeout));
402         } else {
403                 /* Poll without a timeout. */
404                 return (kern_kevent(td, uap->fd, uap->nin, uap->nout, &copyops,
405                     NULL));
406         }
407 }