1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <errno.h>
  30 #include <string.h>
  31 #include <time.h>
  32 #include <sys/lx_misc.h>
  33 
  34 /*
  35  * Linux uses different values for it clock identifiers, so we have to do basic
  36  * translations between the two.  Thankfully, both Linux and Solaris implement
  37  * the same POSIX SUSv3 clock types, so the semantics should be identical.
  38  */
  39 
  40 static int ltos_clock[] = {
  41         CLOCK_REALTIME,
  42         CLOCK_MONOTONIC,
  43         CLOCK_PROCESS_CPUTIME_ID,
  44         CLOCK_THREAD_CPUTIME_ID
  45 };
  46 
  47 #define LX_CLOCK_MAX    (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
  48 
  49 int
  50 lx_clock_gettime(int clock, struct timespec *tp)
  51 {
  52         struct timespec ts;
  53 
  54         if (clock < 0 || clock > LX_CLOCK_MAX)
  55                 return (-EINVAL);
  56 
  57         if (clock_gettime(ltos_clock[clock], &ts) < 0)
  58                 return (-errno);
  59 
  60         return ((uucopy(&ts, tp, sizeof (struct timespec)) < 0) ? -EFAULT : 0);
  61 }
  62 
  63 int
  64 lx_clock_settime(int clock, struct timespec *tp)
  65 {
  66         struct timespec ts;
  67 
  68         if (clock < 0 || clock > LX_CLOCK_MAX)
  69                 return (-EINVAL);
  70 
  71         if (uucopy(tp, &ts, sizeof (struct timespec)) < 0)
  72                 return (-EFAULT);
  73 
  74         return ((clock_settime(ltos_clock[clock], &ts) < 0) ? -errno : 0);
  75 }
  76 
  77 int
  78 lx_clock_getres(int clock, struct timespec *tp)
  79 {
  80         struct timespec ts;
  81 
  82         if (clock < 0 || clock > LX_CLOCK_MAX)
  83                 return (-EINVAL);
  84 
  85         if (clock_getres(ltos_clock[clock], &ts) < 0)
  86                 return (-errno);
  87 
  88         return ((uucopy(&ts, tp, sizeof (struct timespec)) < 0) ? -EFAULT : 0);
  89 }
  90 
  91 int
  92 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
  93     struct timespec *rmtp)
  94 {
  95         struct timespec rqt, rmt;
  96 
  97         if (clock < 0 || clock > LX_CLOCK_MAX)
  98                 return (-EINVAL);
  99 
 100         if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
 101                 return (-EFAULT);
 102 
 103         /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
 104         if (clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt) < 0)
 105                 return (-errno);
 106 
 107         /*
 108          * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
 109          * non-NULL.
 110          */
 111         if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
 112             (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
 113                 return (-EFAULT);
 114 
 115         return (0);
 116 }