]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/cloudabi32/cloudabi32_poll.c
/etc/services: attempt to bring the database to this century 2/2.
[FreeBSD/FreeBSD.git] / sys / compat / cloudabi32 / cloudabi32_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/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, &copyops));
340 }