1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright (c) 2015 Joyent, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Support for the eventfd facility, a Linux-borne facility for user-generated
  18  * file descriptor-based events.
  19  */
  20 
  21 #include <sys/ddi.h>
  22 #include <sys/sunddi.h>
  23 #include <sys/eventfd.h>
  24 #include <sys/conf.h>
  25 #include <sys/vmem.h>
  26 #include <sys/sysmacros.h>
  27 #include <sys/filio.h>
  28 #include <sys/stat.h>
  29 #include <sys/file.h>
  30 
  31 struct eventfd_state;
  32 typedef struct eventfd_state eventfd_state_t;
  33 
  34 struct eventfd_state {
  35         kmutex_t efd_lock;                      /* lock protecting state */
  36         boolean_t efd_semaphore;                /* boolean: sema. semantics */
  37         kcondvar_t efd_cv;                      /* condvar */
  38         pollhead_t efd_pollhd;                  /* poll head */
  39         uint64_t efd_value;                     /* value */
  40         eventfd_state_t *efd_next;              /* next state on global list */
  41 };
  42 
  43 /*
  44  * Internal global variables.
  45  */
  46 static kmutex_t         eventfd_lock;           /* lock protecting state */
  47 static dev_info_t       *eventfd_devi;          /* device info */
  48 static vmem_t           *eventfd_minor;         /* minor number arena */
  49 static void             *eventfd_softstate;     /* softstate pointer */
  50 static eventfd_state_t  *eventfd_state;         /* global list of state */
  51 
  52 /*ARGSUSED*/
  53 static int
  54 eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
  55 {
  56         eventfd_state_t *state;
  57         major_t major = getemajor(*devp);
  58         minor_t minor = getminor(*devp);
  59 
 
 109                         return (EINTR);
 110                 }
 111         }
 112 
 113         /*
 114          * We have a non-zero value and we own the lock; our behavior now
 115          * depends on whether or not EFD_SEMAPHORE was set when the eventfd
 116          * was created.
 117          */
 118         val = oval = state->efd_value;
 119 
 120         if (state->efd_semaphore) {
 121                 state->efd_value--;
 122                 val = 1;
 123         } else {
 124                 state->efd_value = 0;
 125         }
 126 
 127         err = uiomove(&val, sizeof (val), UIO_READ, uio);
 128 
 129         mutex_exit(&state->efd_lock);
 130 
 131         if (oval == EVENTFD_VALMAX) {
 132                 cv_broadcast(&state->efd_cv);
 133                 pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
 134         }
 135 
 136         return (err);
 137 }
 138 
 139 /*ARGSUSED*/
 140 static int
 141 eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
 142 {
 143         eventfd_state_t *state;
 144         minor_t minor = getminor(dev);
 145         uint64_t val, oval;
 146         int err;
 147 
 148         if (uio->uio_resid < sizeof (val))
 149                 return (EINVAL);
 150 
 151         if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
 152                 return (err);
 153 
 154         if (val > EVENTFD_VALMAX)
 155                 return (EINVAL);
 156 
 157         state = ddi_get_soft_state(eventfd_softstate, minor);
 158 
 159         mutex_enter(&state->efd_lock);
 160 
 161         while (val > EVENTFD_VALMAX - state->efd_value) {
 162                 if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
 163                         mutex_exit(&state->efd_lock);
 164                         return (EAGAIN);
 165                 }
 166 
 167                 if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
 168                         mutex_exit(&state->efd_lock);
 169                         return (EINTR);
 170                 }
 171         }
 172 
 173         /*
 174          * We now know that we can add the value without overflowing.
 175          */
 176         state->efd_value = (oval = state->efd_value) + val;
 177 
 178         mutex_exit(&state->efd_lock);
 179 
 180         if (oval == 0) {
 181                 cv_broadcast(&state->efd_cv);
 182                 pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
 183         }
 184 
 185         return (0);
 186 }
 187 
 188 /*ARGSUSED*/
 189 static int
 190 eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
 191     struct pollhead **phpp)
 192 {
 193         eventfd_state_t *state;
 194         minor_t minor = getminor(dev);
 195         short revents = 0;
 196 
 197         state = ddi_get_soft_state(eventfd_softstate, minor);
 198 
 199         mutex_enter(&state->efd_lock);
 200 
 201         if (state->efd_value > 0)
 
 | 
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2016 Joyent, Inc.
  14  */
  15 
  16 /*
  17  * Support for the eventfd facility, a Linux-borne facility for user-generated
  18  * file descriptor-based events.
  19  */
  20 
  21 #include <sys/ddi.h>
  22 #include <sys/sunddi.h>
  23 #include <sys/eventfd.h>
  24 #include <sys/conf.h>
  25 #include <sys/vmem.h>
  26 #include <sys/sysmacros.h>
  27 #include <sys/filio.h>
  28 #include <sys/stat.h>
  29 #include <sys/file.h>
  30 
  31 struct eventfd_state;
  32 typedef struct eventfd_state eventfd_state_t;
  33 
  34 struct eventfd_state {
  35         kmutex_t efd_lock;                      /* lock protecting state */
  36         boolean_t efd_semaphore;                /* boolean: sema. semantics */
  37         kcondvar_t efd_cv;                      /* condvar */
  38         pollhead_t efd_pollhd;                  /* poll head */
  39         uint64_t efd_value;                     /* value */
  40         size_t efd_bwriters;                    /* count of blocked writers */
  41         eventfd_state_t *efd_next;              /* next state on global list */
  42 };
  43 
  44 /*
  45  * Internal global variables.
  46  */
  47 static kmutex_t         eventfd_lock;           /* lock protecting state */
  48 static dev_info_t       *eventfd_devi;          /* device info */
  49 static vmem_t           *eventfd_minor;         /* minor number arena */
  50 static void             *eventfd_softstate;     /* softstate pointer */
  51 static eventfd_state_t  *eventfd_state;         /* global list of state */
  52 
  53 /*ARGSUSED*/
  54 static int
  55 eventfd_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
  56 {
  57         eventfd_state_t *state;
  58         major_t major = getemajor(*devp);
  59         minor_t minor = getminor(*devp);
  60 
 
 110                         return (EINTR);
 111                 }
 112         }
 113 
 114         /*
 115          * We have a non-zero value and we own the lock; our behavior now
 116          * depends on whether or not EFD_SEMAPHORE was set when the eventfd
 117          * was created.
 118          */
 119         val = oval = state->efd_value;
 120 
 121         if (state->efd_semaphore) {
 122                 state->efd_value--;
 123                 val = 1;
 124         } else {
 125                 state->efd_value = 0;
 126         }
 127 
 128         err = uiomove(&val, sizeof (val), UIO_READ, uio);
 129 
 130         /*
 131          * Wake any writers blocked on this eventfd as this read operation may
 132          * have created adequate capacity for their values.
 133          */
 134         if (state->efd_bwriters != 0) {
 135                 cv_broadcast(&state->efd_cv);
 136         }
 137         mutex_exit(&state->efd_lock);
 138 
 139         /*
 140          * It is necessary to emit POLLOUT events only when the eventfd
 141          * transitions from EVENTFD_VALMAX to a lower value.  At all other
 142          * times, it is already considered writable by poll.
 143          */
 144         if (oval == EVENTFD_VALMAX) {
 145                 pollwakeup(&state->efd_pollhd, POLLWRNORM | POLLOUT);
 146         }
 147 
 148         return (err);
 149 }
 150 
 151 /*ARGSUSED*/
 152 static int
 153 eventfd_write(dev_t dev, struct uio *uio, cred_t *credp)
 154 {
 155         eventfd_state_t *state;
 156         minor_t minor = getminor(dev);
 157         uint64_t val, oval;
 158         int err;
 159 
 160         if (uio->uio_resid < sizeof (val))
 161                 return (EINVAL);
 162 
 163         if ((err = uiomove(&val, sizeof (val), UIO_WRITE, uio)) != 0)
 164                 return (err);
 165 
 166         if (val > EVENTFD_VALMAX)
 167                 return (EINVAL);
 168 
 169         state = ddi_get_soft_state(eventfd_softstate, minor);
 170 
 171         mutex_enter(&state->efd_lock);
 172 
 173         while (val > EVENTFD_VALMAX - state->efd_value) {
 174                 if (uio->uio_fmode & (FNDELAY|FNONBLOCK)) {
 175                         mutex_exit(&state->efd_lock);
 176                         return (EAGAIN);
 177                 }
 178 
 179                 state->efd_bwriters++;
 180                 if (!cv_wait_sig_swap(&state->efd_cv, &state->efd_lock)) {
 181                         state->efd_bwriters--;
 182                         mutex_exit(&state->efd_lock);
 183                         return (EINTR);
 184                 }
 185                 state->efd_bwriters--;
 186         }
 187 
 188         /*
 189          * We now know that we can add the value without overflowing.
 190          */
 191         state->efd_value = (oval = state->efd_value) + val;
 192 
 193         /*
 194          * If the value was previously "empty", notify blocked readers that
 195          * data is available.
 196          */
 197         if (oval == 0) {
 198                 cv_broadcast(&state->efd_cv);
 199         }
 200         mutex_exit(&state->efd_lock);
 201 
 202         /*
 203          * Notify pollers as well if the eventfd is now readable.
 204          */
 205         if (oval == 0) {
 206                 pollwakeup(&state->efd_pollhd, POLLRDNORM | POLLIN);
 207         }
 208 
 209         return (0);
 210 }
 211 
 212 /*ARGSUSED*/
 213 static int
 214 eventfd_poll(dev_t dev, short events, int anyyet, short *reventsp,
 215     struct pollhead **phpp)
 216 {
 217         eventfd_state_t *state;
 218         minor_t minor = getminor(dev);
 219         short revents = 0;
 220 
 221         state = ddi_get_soft_state(eventfd_softstate, minor);
 222 
 223         mutex_enter(&state->efd_lock);
 224 
 225         if (state->efd_value > 0)
 
 |