The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/cloudabi32/cloudabi32_poll.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: f6e0041532918c6add894fb00e7a109d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.