Print this page
OS-4514 [lx] SIGEV_THREAD_ID emulation needed

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/brand/lx/lx_brand/common/clock.c
          +++ new/usr/src/lib/brand/lx/lx_brand/common/clock.c
↓ open down ↓ 18 lines elided ↑ open up ↑
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   * Copyright 2015 Joyent, Inc.
  26   26   */
  27   27  
  28   28  #include <errno.h>
       29 +#include <stdlib.h>
  29   30  #include <string.h>
  30   31  #include <time.h>
       32 +#include <unistd.h>
  31   33  #include <sys/resource.h>
       34 +#include <sys/syscall.h>
  32   35  #include <sys/lx_misc.h>
  33   36  #include <sys/lx_syscall.h>
  34   37  #include <lx_signum.h>
  35   38  
  36   39  /*
  37   40   * Translating from the Linux clock types to the Illumos types is a bit of a
  38   41   * mess.
  39   42   *
  40   43   * Linux uses different values for it clock identifiers, so we have to do basic
  41   44   * translations between the two.  Thankfully, both Linux and Illumos implement
↓ open down ↓ 64 lines elided ↑ open up ↑
 106  109                  } lx_sigev_thread;
 107  110          } lx_sigev_un;
 108  111  } lx_sigevent_t;
 109  112  
 110  113  /* sigevent sigev_notify conversion table */
 111  114  static int ltos_sigev[] = {
 112  115          SIGEV_SIGNAL,
 113  116          SIGEV_NONE,
 114  117          SIGEV_THREAD,
 115  118          0,              /* Linux skips event 3 */
 116      -        SIGEV_THREAD    /* the Linux SIGEV_THREAD_ID */
      119 +        SIGEV_THREAD    /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
 117  120  };
 118  121  
 119      -#define LX_SIGEV_MAX    (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
      122 +#define LX_SIGEV_MAX            (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
      123 +#define LX_SIGEV_THREAD_ID      4
 120  124  
 121  125  long
 122  126  lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
 123  127      struct timespec *rmtp)
 124  128  {
 125  129          int ret = 0;
 126  130          int err;
 127  131          struct timespec rqt, rmt;
 128  132  
 129  133          if (clock < 0 || clock >= LX_CLOCK_MAX)
↓ open down ↓ 26 lines elided ↑ open up ↑
 156  160  }
 157  161  
 158  162  /*ARGSUSED*/
 159  163  long
 160  164  lx_adjtimex(void *tp)
 161  165  {
 162  166          return (-EPERM);
 163  167  }
 164  168  
 165  169  /*
      170 + * Notification function for use with native SIGEV_THREAD in order to
      171 + * emulate Linux SIGEV_THREAD_ID. Native SIGEV_THREAD is used as the
      172 + * timer mechanism and B_SIGEV_THREAD_ID performs the actual event
      173 + * delivery to the appropriate lx tid.
      174 + */
      175 +static void
      176 +lx_sigev_thread_id(union sigval sival)
      177 +{
      178 +        lx_sigevent_t *lev = (lx_sigevent_t *)sival.sival_ptr;
      179 +        syscall(SYS_brand, B_SIGEV_THREAD_ID, lev->lx_sigev_un.lx_tid,
      180 +            lev->lx_sigev_signo, lev->lx_sigev_value.sival_ptr);
      181 +        free(lev);
      182 +}
      183 +
      184 +
      185 +/*
 166  186   * The Illumos timer_create man page says it accepts the following clocks:
 167  187   *   CLOCK_REALTIME (3) wall clock
 168  188   *   CLOCK_VIRTUAL (1)  user CPU usage clock - No Backend
 169  189   *   CLOCK_PROF (2)     user and system CPU usage clock - No Backend
 170  190   *   CLOCK_HIGHRES (4)  non-adjustable, high-resolution clock
 171  191   * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
 172  192   * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
 173  193   * down to one clock.
 174  194   */
 175  195  long
↓ open down ↓ 6 lines elided ↑ open up ↑
 182  202                  return (-EINVAL);
 183  203  
 184  204          /* We have to convert the Linux sigevent layout to the Illumos layout */
 185  205          if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
 186  206                  return (-EFAULT);
 187  207  
 188  208          if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
 189  209                  return (-EINVAL);
 190  210  
 191  211          sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
 192      -        sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
      212 +        sev.sigev_signo = lx_ltos_signo(lev.lx_sigev_signo, 0);
 193  213          sev.sigev_value = lev.lx_sigev_value;
 194  214  
 195  215          /*
 196      -         * The sigevent sigev_notify_function and sigev_notify_attributes
 197      -         * members are not used by timer_create, so no conversion is needed.
      216 +         * The signal number is meaningless in SIGEV_NONE, Linux
      217 +         * accepts any value. We convert invalid signals to 0 so other
      218 +         * parts of lx signal handling don't break.
 198  219           */
      220 +        if ((sev.sigev_notify != SIGEV_NONE) && (sev.sigev_signo == 0))
      221 +                return (-EINVAL);
 199  222  
      223 +        /*
      224 +         * Assume all Linux libc implementations map SIGEV_THREAD to
      225 +         * SIGEV_THREAD_ID and ignore passed-in attributes.
      226 +         */
      227 +        sev.sigev_notify_attributes = NULL;
      228 +
      229 +        if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
      230 +                pid_t caller_pid = getpid();
      231 +                pid_t target_pid;
      232 +                lwpid_t ignore;
      233 +                lx_sigevent_t *lev_copy;
      234 +
      235 +                if (lx_lpid_to_spair(lev.lx_sigev_un.lx_tid,
      236 +                    &target_pid, &ignore) != 0)
      237 +                        return (-EINVAL);
      238 +
      239 +                /*
      240 +                 * The caller of SIGEV_THREAD_ID must be in the same
      241 +                 * process as the target thread.
      242 +                 */
      243 +                if (caller_pid != target_pid)
      244 +                        return (-EINVAL);
      245 +
      246 +                /*
      247 +                 * Pass the original lx sigevent_t to the native
      248 +                 * notify function so that it may pass it to the lx
      249 +                 * helper thread. It is the responsibility of
      250 +                 * lx_sigev_thread_id() to free lev_copy after the
      251 +                 * information is relayed to lx.
      252 +                 *
      253 +                 * If the calling process is forked without an exec
      254 +                 * after this copy but before the timer fires then
      255 +                 * lev_copy will leak in the child. This is acceptable
      256 +                 * given the rarity of this event, the miniscule
      257 +                 * amount leaked, and the fact that the memory is
      258 +                 * reclaimed when the proc dies. It is firmly in the
      259 +                 * land of "good enough".
      260 +                 */
      261 +                lev_copy = malloc(sizeof (lx_sigevent_t));
      262 +                if (lev_copy == NULL)
      263 +                        return (-ENOMEM);
      264 +
      265 +                if (uucopy(&lev, lev_copy, sizeof (lx_sigevent_t)) < 0) {
      266 +                        free(lev_copy);
      267 +                        return (-EFAULT);
      268 +                }
      269 +
      270 +                sev.sigev_notify_function = lx_sigev_thread_id;
      271 +                sev.sigev_value.sival_ptr = lev_copy;
      272 +        }
      273 +
 200  274          return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
 201  275  }
 202  276  
 203  277  long
 204  278  lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
 205  279      struct itimerspec *old_val)
 206  280  {
 207  281          return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
 208  282  }
 209  283  
↓ open down ↓ 20 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX