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/cloudabi64/cloudabi64_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: releng/11.1/sys/compat/cloudabi64/cloudabi64_poll.c 316574 2017-04-06 15:10:36Z ed $");
   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 #include <compat/cloudabi64/cloudabi64_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 cloudabi64_kevent_args {
   80         const cloudabi64_subscription_t *in;
   81         cloudabi64_event_t *out;
   82         bool once;
   83 };
   84 
   85 /* Converts CloudABI's subscription objects to FreeBSD's struct kevent. */
   86 static int
   87 cloudabi64_kevent_copyin(void *arg, struct kevent *kevp, int count)
   88 {
   89         cloudabi64_subscription_t sub;
   90         struct cloudabi64_kevent_args *args;
   91         cloudabi_timestamp_t ts;
   92         int error;
   93 
   94         args = arg;
   95         while (count-- > 0) {
   96                 /* TODO(ed): Copy in multiple entries at once. */
   97                 error = copyin(args->in++, &sub, sizeof(sub));
   98                 if (error != 0)
   99                         return (error);
  100 
  101                 memset(kevp, 0, sizeof(*kevp));
  102                 kevp->udata = TO_PTR(sub.userdata);
  103                 switch (sub.type) {
  104                 case CLOUDABI_EVENTTYPE_CLOCK:
  105                         kevp->filter = EVFILT_TIMER;
  106                         kevp->ident = sub.clock.identifier;
  107                         kevp->fflags = NOTE_NSECONDS;
  108                         if ((sub.clock.flags &
  109                             CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) != 0 &&
  110                             sub.clock.timeout > 0) {
  111                                 /* Convert absolute timestamp to a relative. */
  112                                 error = cloudabi_clock_time_get(curthread,
  113                                     sub.clock.clock_id, &ts);
  114                                 if (error != 0)
  115                                         return (error);
  116                                 ts = ts > sub.clock.timeout ? 0 :
  117                                     sub.clock.timeout - ts;
  118                         } else {
  119                                 /* Relative timestamp. */
  120                                 ts = sub.clock.timeout;
  121                         }
  122                         kevp->data = ts > INTPTR_MAX ? INTPTR_MAX : ts;
  123                         break;
  124                 case CLOUDABI_EVENTTYPE_FD_READ:
  125                         kevp->filter = EVFILT_READ;
  126                         kevp->ident = sub.fd_readwrite.fd;
  127                         if ((sub.fd_readwrite.flags &
  128                             CLOUDABI_SUBSCRIPTION_FD_READWRITE_POLL) != 0)
  129                                 kevp->fflags = NOTE_FILE_POLL;
  130                         break;
  131                 case CLOUDABI_EVENTTYPE_FD_WRITE:
  132                         kevp->filter = EVFILT_WRITE;
  133                         kevp->ident = sub.fd_readwrite.fd;
  134                         break;
  135                 case CLOUDABI_EVENTTYPE_PROC_TERMINATE:
  136                         kevp->filter = EVFILT_PROCDESC;
  137                         kevp->ident = sub.proc_terminate.fd;
  138                         kevp->fflags = NOTE_EXIT;
  139                         break;
  140                 }
  141                 if (args->once) {
  142                         /* Ignore flags. Simply use oneshot mode. */
  143                         kevp->flags = EV_ADD | EV_ONESHOT;
  144                 } else {
  145                         /* Translate flags. */
  146                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ADD) != 0)
  147                                 kevp->flags |= EV_ADD;
  148                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_CLEAR) != 0)
  149                                 kevp->flags |= EV_CLEAR;
  150                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_DELETE) != 0)
  151                                 kevp->flags |= EV_DELETE;
  152                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_DISABLE) != 0)
  153                                 kevp->flags |= EV_DISABLE;
  154                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ENABLE) != 0)
  155                                 kevp->flags |= EV_ENABLE;
  156                         if ((sub.flags & CLOUDABI_SUBSCRIPTION_ONESHOT) != 0)
  157                                 kevp->flags |= EV_ONESHOT;
  158                 }
  159                 ++kevp;
  160         }
  161         return (0);
  162 }
  163 
  164 /* Converts FreeBSD's struct kevent to CloudABI's event objects. */
  165 static int
  166 cloudabi64_kevent_copyout(void *arg, struct kevent *kevp, int count)
  167 {
  168         cloudabi64_event_t ev;
  169         struct cloudabi64_kevent_args *args;
  170         int error;
  171 
  172         args = arg;
  173         while (count-- > 0) {
  174                 /* Convert fields that should always be present. */
  175                 memset(&ev, 0, sizeof(ev));
  176                 ev.userdata = (uintptr_t)kevp->udata;
  177                 switch (kevp->filter) {
  178                 case EVFILT_TIMER:
  179                         ev.type = CLOUDABI_EVENTTYPE_CLOCK;
  180                         ev.clock.identifier = kevp->ident;
  181                         break;
  182                 case EVFILT_READ:
  183                         ev.type = CLOUDABI_EVENTTYPE_FD_READ;
  184                         ev.fd_readwrite.fd = kevp->ident;
  185                         break;
  186                 case EVFILT_WRITE:
  187                         ev.type = CLOUDABI_EVENTTYPE_FD_WRITE;
  188                         ev.fd_readwrite.fd = kevp->ident;
  189                         break;
  190                 case EVFILT_PROCDESC:
  191                         ev.type = CLOUDABI_EVENTTYPE_PROC_TERMINATE;
  192                         ev.proc_terminate.fd = kevp->ident;
  193                         break;
  194                 }
  195 
  196                 if ((kevp->flags & EV_ERROR) == 0) {
  197                         /* Success. */
  198                         switch (kevp->filter) {
  199                         case EVFILT_READ:
  200                         case EVFILT_WRITE:
  201                                 ev.fd_readwrite.nbytes = kevp->data;
  202                                 if ((kevp->flags & EV_EOF) != 0) {
  203                                         ev.fd_readwrite.flags |=
  204                                             CLOUDABI_EVENT_FD_READWRITE_HANGUP;
  205                                 }
  206                                 break;
  207                         case EVFILT_PROCDESC:
  208                                 if (WIFSIGNALED(kevp->data)) {
  209                                         /* Process got signalled. */
  210                                         ev.proc_terminate.signal =
  211                                            convert_signal(WTERMSIG(kevp->data));
  212                                         ev.proc_terminate.exitcode = 0;
  213                                 } else {
  214                                         /* Process exited. */
  215                                         ev.proc_terminate.signal = 0;
  216                                         ev.proc_terminate.exitcode =
  217                                             WEXITSTATUS(kevp->data);
  218                                 }
  219                                 break;
  220                         }
  221                 } else {
  222                         /* Error. */
  223                         ev.error = cloudabi_convert_errno(kevp->data);
  224                 }
  225                 ++kevp;
  226 
  227                 /* TODO(ed): Copy out multiple entries at once. */
  228                 error = copyout(&ev, args->out++, sizeof(ev));
  229                 if (error != 0)
  230                         return (error);
  231         }
  232         return (0);
  233 }
  234 
  235 int
  236 cloudabi64_sys_poll(struct thread *td, struct cloudabi64_sys_poll_args *uap)
  237 {
  238         struct cloudabi64_kevent_args args = {
  239                 .in     = uap->in,
  240                 .out    = uap->out,
  241                 .once   = true,
  242         };
  243         struct kevent_copyops copyops = {
  244                 .k_copyin       = cloudabi64_kevent_copyin,
  245                 .k_copyout      = cloudabi64_kevent_copyout,
  246                 .arg            = &args,
  247         };
  248 
  249         /*
  250          * Bandaid to support CloudABI futex constructs that are not
  251          * implemented through FreeBSD's kqueue().
  252          */
  253         if (uap->nsubscriptions == 1) {
  254                 cloudabi64_subscription_t sub;
  255                 cloudabi64_event_t ev = {};
  256                 int error;
  257 
  258                 error = copyin(uap->in, &sub, sizeof(sub));
  259                 if (error != 0)
  260                         return (error);
  261                 ev.userdata = sub.userdata;
  262                 ev.type = sub.type;
  263                 if (sub.type == CLOUDABI_EVENTTYPE_CONDVAR) {
  264                         /* Wait on a condition variable. */
  265                         ev.condvar.condvar = sub.condvar.condvar;
  266                         ev.error = cloudabi_convert_errno(
  267                             cloudabi_futex_condvar_wait(
  268                                 td, TO_PTR(sub.condvar.condvar),
  269                                 sub.condvar.condvar_scope,
  270                                 TO_PTR(sub.condvar.lock),
  271                                 sub.condvar.lock_scope,
  272                                 CLOUDABI_CLOCK_MONOTONIC, UINT64_MAX, 0));
  273                         td->td_retval[0] = 1;
  274                         return (copyout(&ev, uap->out, sizeof(ev)));
  275                 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK) {
  276                         /* Acquire a read lock. */
  277                         ev.lock.lock = sub.lock.lock;
  278                         ev.error = cloudabi_convert_errno(
  279                             cloudabi_futex_lock_rdlock(
  280                                 td, TO_PTR(sub.lock.lock),
  281                                 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
  282                                 UINT64_MAX, 0));
  283                         td->td_retval[0] = 1;
  284                         return (copyout(&ev, uap->out, sizeof(ev)));
  285                 } else if (sub.type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK) {
  286                         /* Acquire a write lock. */
  287                         ev.lock.lock = sub.lock.lock;
  288                         ev.error = cloudabi_convert_errno(
  289                             cloudabi_futex_lock_wrlock(
  290                                 td, TO_PTR(sub.lock.lock),
  291                                 sub.lock.lock_scope, CLOUDABI_CLOCK_MONOTONIC,
  292                                 UINT64_MAX, 0));
  293                         td->td_retval[0] = 1;
  294                         return (copyout(&ev, uap->out, sizeof(ev)));
  295                 }
  296         } else if (uap->nsubscriptions == 2) {
  297                 cloudabi64_subscription_t sub[2];
  298                 cloudabi64_event_t ev[2] = {};
  299                 int error;
  300 
  301                 error = copyin(uap->in, &sub, sizeof(sub));
  302                 if (error != 0)
  303                         return (error);
  304                 ev[0].userdata = sub[0].userdata;
  305                 ev[0].type = sub[0].type;
  306                 ev[1].userdata = sub[1].userdata;
  307                 ev[1].type = sub[1].type;
  308                 if (sub[0].type == CLOUDABI_EVENTTYPE_CONDVAR &&
  309                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
  310                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
  311                         /* Wait for a condition variable with timeout. */
  312                         ev[0].condvar.condvar = sub[0].condvar.condvar;
  313                         ev[1].clock.identifier = sub[1].clock.identifier;
  314                         error = cloudabi_futex_condvar_wait(
  315                             td, TO_PTR(sub[0].condvar.condvar),
  316                             sub[0].condvar.condvar_scope,
  317                             TO_PTR(sub[0].condvar.lock),
  318                             sub[0].condvar.lock_scope, sub[1].clock.clock_id,
  319                             sub[1].clock.timeout, sub[1].clock.precision);
  320                         if (error == ETIMEDOUT) {
  321                                 td->td_retval[0] = 1;
  322                                 return (copyout(&ev[1], uap->out,
  323                                     sizeof(ev[1])));
  324                         }
  325 
  326                         ev[0].error = cloudabi_convert_errno(error);
  327                         td->td_retval[0] = 1;
  328                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
  329                 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_RDLOCK &&
  330                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
  331                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
  332                         /* Acquire a read lock with a timeout. */
  333                         ev[0].lock.lock = sub[0].lock.lock;
  334                         ev[1].clock.identifier = sub[1].clock.identifier;
  335                         error = cloudabi_futex_lock_rdlock(
  336                             td, TO_PTR(sub[0].lock.lock),
  337                             sub[0].lock.lock_scope, sub[1].clock.clock_id,
  338                             sub[1].clock.timeout, sub[1].clock.precision);
  339                         if (error == ETIMEDOUT) {
  340                                 td->td_retval[0] = 1;
  341                                 return (copyout(&ev[1], uap->out,
  342                                     sizeof(ev[1])));
  343                         }
  344 
  345                         ev[0].error = cloudabi_convert_errno(error);
  346                         td->td_retval[0] = 1;
  347                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
  348                 } else if (sub[0].type == CLOUDABI_EVENTTYPE_LOCK_WRLOCK &&
  349                     sub[1].type == CLOUDABI_EVENTTYPE_CLOCK &&
  350                     sub[1].clock.flags == CLOUDABI_SUBSCRIPTION_CLOCK_ABSTIME) {
  351                         /* Acquire a write lock with a timeout. */
  352                         ev[0].lock.lock = sub[0].lock.lock;
  353                         ev[1].clock.identifier = sub[1].clock.identifier;
  354                         error = cloudabi_futex_lock_wrlock(
  355                             td, TO_PTR(sub[0].lock.lock),
  356                             sub[0].lock.lock_scope, sub[1].clock.clock_id,
  357                             sub[1].clock.timeout, sub[1].clock.precision);
  358                         if (error == ETIMEDOUT) {
  359                                 td->td_retval[0] = 1;
  360                                 return (copyout(&ev[1], uap->out,
  361                                     sizeof(ev[1])));
  362                         }
  363 
  364                         ev[0].error = cloudabi_convert_errno(error);
  365                         td->td_retval[0] = 1;
  366                         return (copyout(&ev[0], uap->out, sizeof(ev[0])));
  367                 }
  368         }
  369 
  370         return (kern_kevent_anonymous(td, uap->nsubscriptions, &copyops));
  371 }
  372 
  373 int
  374 cloudabi64_sys_poll_fd(struct thread *td,
  375     struct cloudabi64_sys_poll_fd_args *uap)
  376 {
  377         struct cloudabi64_kevent_args args = {
  378                 .in     = uap->in,
  379                 .out    = uap->out,
  380                 .once   = false,
  381         };
  382         struct kevent_copyops copyops = {
  383                 .k_copyin       = cloudabi64_kevent_copyin,
  384                 .k_copyout      = cloudabi64_kevent_copyout,
  385                 .arg            = &args,
  386         };
  387         cloudabi64_subscription_t subtimo;
  388         struct timespec timeout;
  389         int error;
  390 
  391         if (uap->timeout != NULL) {
  392                 /* Poll with a timeout. */
  393                 error = copyin(uap->timeout, &subtimo, sizeof(subtimo));
  394                 if (error != 0)
  395                         return (error);
  396                 if (subtimo.type != CLOUDABI_EVENTTYPE_CLOCK ||
  397                     subtimo.clock.flags != 0)
  398                         return (EINVAL);
  399                 timeout.tv_sec = subtimo.clock.timeout / 1000000000;
  400                 timeout.tv_nsec = subtimo.clock.timeout % 1000000000;
  401                 return (kern_kevent(td, uap->fd, uap->in_len, uap->out_len,
  402                     &copyops, &timeout));
  403         } else {
  404                 /* Poll without a timeout. */
  405                 return (kern_kevent(td, uap->fd, uap->in_len, uap->out_len,
  406                     &copyops, NULL));
  407         }
  408 }

Cache object: f01ee3789b89c25f85c8d3943ac94195


[ 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.