1ad2056f2SAlexander Leidinger /* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ 2ad2056f2SAlexander Leidinger 3ad2056f2SAlexander Leidinger /*- 47f2d13d6SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 57f2d13d6SPedro F. Giffuni * 6ad2056f2SAlexander Leidinger * Copyright (c) 2001 The NetBSD Foundation, Inc. 7ad2056f2SAlexander Leidinger * All rights reserved. 8ad2056f2SAlexander Leidinger * 9ad2056f2SAlexander Leidinger * This code is derived from software contributed to The NetBSD Foundation 10ad2056f2SAlexander Leidinger * by Emmanuel Dreyfus. 11ad2056f2SAlexander Leidinger * 12ad2056f2SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 13ad2056f2SAlexander Leidinger * modification, are permitted provided that the following conditions 14ad2056f2SAlexander Leidinger * are met: 15ad2056f2SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 16ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer. 17ad2056f2SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 18ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 19ad2056f2SAlexander Leidinger * documentation and/or other materials provided with the distribution. 20ad2056f2SAlexander Leidinger * 21ad2056f2SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22ad2056f2SAlexander Leidinger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23ad2056f2SAlexander Leidinger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24ad2056f2SAlexander Leidinger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25ad2056f2SAlexander Leidinger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26ad2056f2SAlexander Leidinger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27ad2056f2SAlexander Leidinger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28ad2056f2SAlexander Leidinger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29ad2056f2SAlexander Leidinger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30ad2056f2SAlexander Leidinger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31ad2056f2SAlexander Leidinger * POSSIBILITY OF SUCH DAMAGE. 32ad2056f2SAlexander Leidinger */ 33ad2056f2SAlexander Leidinger 34ad2056f2SAlexander Leidinger #include <sys/cdefs.h> 35ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$"); 36ad2056f2SAlexander Leidinger #if 0 37ad2056f2SAlexander Leidinger __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); 38ad2056f2SAlexander Leidinger #endif 39ad2056f2SAlexander Leidinger 40ad2056f2SAlexander Leidinger #include "opt_compat.h" 41ad2056f2SAlexander Leidinger 42ad2056f2SAlexander Leidinger #include <sys/param.h> 4319e252baSAlexander Leidinger #include <sys/kernel.h> 442711aba9SDmitry Chagin #include <sys/lock.h> 45ad2056f2SAlexander Leidinger #include <sys/ucred.h> 460670e972SDmitry Chagin #include <sys/limits.h> 47ad2056f2SAlexander Leidinger #include <sys/mount.h> 482711aba9SDmitry Chagin #include <sys/mutex.h> 492711aba9SDmitry Chagin #include <sys/resourcevar.h> 5019e252baSAlexander Leidinger #include <sys/sdt.h> 51ad2056f2SAlexander Leidinger #include <sys/signal.h> 52ad2056f2SAlexander Leidinger #include <sys/stdint.h> 53ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h> 54ad2056f2SAlexander Leidinger #include <sys/sysproto.h> 55ad2056f2SAlexander Leidinger #include <sys/time.h> 56ad2056f2SAlexander Leidinger #include <sys/systm.h> 57ad2056f2SAlexander Leidinger #include <sys/proc.h> 58ad2056f2SAlexander Leidinger 59ad2056f2SAlexander Leidinger #ifdef COMPAT_LINUX32 60ad2056f2SAlexander Leidinger #include <machine/../linux32/linux.h> 61ad2056f2SAlexander Leidinger #include <machine/../linux32/linux32_proto.h> 62ad2056f2SAlexander Leidinger #else 63ad2056f2SAlexander Leidinger #include <machine/../linux/linux.h> 64ad2056f2SAlexander Leidinger #include <machine/../linux/linux_proto.h> 65ad2056f2SAlexander Leidinger #endif 66ad2056f2SAlexander Leidinger 6719e252baSAlexander Leidinger #include <compat/linux/linux_dtrace.h> 687bc05ae6SDmitry Chagin #include <compat/linux/linux_misc.h> 692711aba9SDmitry Chagin #include <compat/linux/linux_timer.h> 704afe4faeSEdward Tomasz Napierala #include <compat/linux/linux_util.h> 7119e252baSAlexander Leidinger 7219e252baSAlexander Leidinger /* DTrace init */ 7319e252baSAlexander Leidinger LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 7419e252baSAlexander Leidinger 7519e252baSAlexander Leidinger /** 7619e252baSAlexander Leidinger * DTrace probes in this module. 7719e252baSAlexander Leidinger */ 7819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, 7919e252baSAlexander Leidinger "clockid_t"); 8019e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, 8119e252baSAlexander Leidinger "clockid_t"); 8299b6f430SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int"); 8319e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); 8419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); 8599b6f430SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 8699b6f430SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int"); 8799b6f430SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int"); 8899b6f430SDmitry Chagin #endif 8919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); 90*19f9a0e4SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int"); 91*19f9a0e4SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int"); 9219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); 93*19f9a0e4SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 94*19f9a0e4SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int"); 95*19f9a0e4SDmitry Chagin LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int"); 96*19f9a0e4SDmitry Chagin #endif 9719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall); 9819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int"); 9919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int"); 10019e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); 10119e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int"); 10219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); 10319e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); 10419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int"); 10519e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); 10619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); 10719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int"); 10819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int"); 10919e252baSAlexander Leidinger 11099b6f430SDmitry Chagin static int linux_common_clock_gettime(struct thread *, clockid_t, 11199b6f430SDmitry Chagin struct timespec *); 112*19f9a0e4SDmitry Chagin static int linux_common_clock_settime(struct thread *, clockid_t, 113*19f9a0e4SDmitry Chagin struct timespec *); 11499b6f430SDmitry Chagin 1150670e972SDmitry Chagin int 116ad2056f2SAlexander Leidinger native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) 117ad2056f2SAlexander Leidinger { 11819e252baSAlexander Leidinger 1190670e972SDmitry Chagin #ifdef COMPAT_LINUX32 12071b50d08SDmitry Chagin if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN) 1210670e972SDmitry Chagin return (EOVERFLOW); 1220670e972SDmitry Chagin #endif 123ad2056f2SAlexander Leidinger ltp->tv_sec = ntp->tv_sec; 124ad2056f2SAlexander Leidinger ltp->tv_nsec = ntp->tv_nsec; 12519e252baSAlexander Leidinger 1260670e972SDmitry Chagin return (0); 127ad2056f2SAlexander Leidinger } 128ad2056f2SAlexander Leidinger 12968098228SDmitry Chagin int 130ad2056f2SAlexander Leidinger linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) 131ad2056f2SAlexander Leidinger { 13219e252baSAlexander Leidinger 1335e8caee2SEdward Tomasz Napierala if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999) 13477424f41SJung-uk Kim return (EINVAL); 135ad2056f2SAlexander Leidinger ntp->tv_sec = ltp->tv_sec; 136ad2056f2SAlexander Leidinger ntp->tv_nsec = ltp->tv_nsec; 13777424f41SJung-uk Kim 13877424f41SJung-uk Kim return (0); 139ad2056f2SAlexander Leidinger } 140ad2056f2SAlexander Leidinger 141bfcce1a9SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 142bfcce1a9SDmitry Chagin int 143bfcce1a9SDmitry Chagin native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp) 144bfcce1a9SDmitry Chagin { 145bfcce1a9SDmitry Chagin 146bfcce1a9SDmitry Chagin ltp64->tv_sec = ntp->tv_sec; 147bfcce1a9SDmitry Chagin ltp64->tv_nsec = ntp->tv_nsec; 148bfcce1a9SDmitry Chagin 149bfcce1a9SDmitry Chagin return (0); 150bfcce1a9SDmitry Chagin } 151bfcce1a9SDmitry Chagin 152bfcce1a9SDmitry Chagin int 153bfcce1a9SDmitry Chagin linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64) 154bfcce1a9SDmitry Chagin { 155bfcce1a9SDmitry Chagin 156bfcce1a9SDmitry Chagin if (ltp64->tv_sec < 0 || ltp64->tv_nsec < 0 || ltp64->tv_nsec > 999999999) 157bfcce1a9SDmitry Chagin return (EINVAL); 158bfcce1a9SDmitry Chagin ntp->tv_sec = ltp64->tv_sec; 159bfcce1a9SDmitry Chagin ntp->tv_nsec = ltp64->tv_nsec; 160bfcce1a9SDmitry Chagin 161bfcce1a9SDmitry Chagin return (0); 162bfcce1a9SDmitry Chagin } 163bfcce1a9SDmitry Chagin #endif 164bfcce1a9SDmitry Chagin 16516ac71bcSDmitry Chagin int 166dd93b628SDmitry Chagin native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp) 167dd93b628SDmitry Chagin { 168dd93b628SDmitry Chagin int error; 169dd93b628SDmitry Chagin 170dd93b628SDmitry Chagin error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval); 171dd93b628SDmitry Chagin if (error == 0) 172dd93b628SDmitry Chagin error = native_to_linux_timespec(<p->it_value, &ntp->it_interval); 173dd93b628SDmitry Chagin return (error); 174dd93b628SDmitry Chagin } 175dd93b628SDmitry Chagin 176dd93b628SDmitry Chagin int 177dd93b628SDmitry Chagin linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp) 178dd93b628SDmitry Chagin { 179dd93b628SDmitry Chagin int error; 180dd93b628SDmitry Chagin 181dd93b628SDmitry Chagin error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval); 182dd93b628SDmitry Chagin if (error == 0) 183dd93b628SDmitry Chagin error = linux_to_native_timespec(&ntp->it_value, <p->it_value); 184dd93b628SDmitry Chagin return (error); 185dd93b628SDmitry Chagin } 186dd93b628SDmitry Chagin 187dd93b628SDmitry Chagin int 188ad2056f2SAlexander Leidinger linux_to_native_clockid(clockid_t *n, clockid_t l) 189ad2056f2SAlexander Leidinger { 19019e252baSAlexander Leidinger 1912711aba9SDmitry Chagin if (l < 0) { 1922711aba9SDmitry Chagin /* cpu-clock */ 1932711aba9SDmitry Chagin if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD) 1942711aba9SDmitry Chagin return (EINVAL); 1952711aba9SDmitry Chagin if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX) 1962711aba9SDmitry Chagin return (EINVAL); 1972711aba9SDmitry Chagin 1982711aba9SDmitry Chagin if (LINUX_CPUCLOCK_PERTHREAD(l)) 1992711aba9SDmitry Chagin *n = CLOCK_THREAD_CPUTIME_ID; 2002711aba9SDmitry Chagin else 2012711aba9SDmitry Chagin *n = CLOCK_PROCESS_CPUTIME_ID; 2022711aba9SDmitry Chagin return (0); 2032711aba9SDmitry Chagin } 2042711aba9SDmitry Chagin 205ad2056f2SAlexander Leidinger switch (l) { 206ad2056f2SAlexander Leidinger case LINUX_CLOCK_REALTIME: 207ad2056f2SAlexander Leidinger *n = CLOCK_REALTIME; 208ad2056f2SAlexander Leidinger break; 209ad2056f2SAlexander Leidinger case LINUX_CLOCK_MONOTONIC: 210ad2056f2SAlexander Leidinger *n = CLOCK_MONOTONIC; 211ad2056f2SAlexander Leidinger break; 2127bc05ae6SDmitry Chagin case LINUX_CLOCK_PROCESS_CPUTIME_ID: 2137bc05ae6SDmitry Chagin *n = CLOCK_PROCESS_CPUTIME_ID; 2147bc05ae6SDmitry Chagin break; 2157bc05ae6SDmitry Chagin case LINUX_CLOCK_THREAD_CPUTIME_ID: 2167bc05ae6SDmitry Chagin *n = CLOCK_THREAD_CPUTIME_ID; 2177bc05ae6SDmitry Chagin break; 2182711aba9SDmitry Chagin case LINUX_CLOCK_REALTIME_COARSE: 2192711aba9SDmitry Chagin *n = CLOCK_REALTIME_FAST; 2202711aba9SDmitry Chagin break; 2212711aba9SDmitry Chagin case LINUX_CLOCK_MONOTONIC_COARSE: 222e37db348SAlexander Leidinger case LINUX_CLOCK_MONOTONIC_RAW: 2232711aba9SDmitry Chagin *n = CLOCK_MONOTONIC_FAST; 2242711aba9SDmitry Chagin break; 2252711aba9SDmitry Chagin case LINUX_CLOCK_BOOTTIME: 22625ada637SDmitry Chagin *n = CLOCK_UPTIME; 22725ada637SDmitry Chagin break; 2282711aba9SDmitry Chagin case LINUX_CLOCK_REALTIME_ALARM: 2292711aba9SDmitry Chagin case LINUX_CLOCK_BOOTTIME_ALARM: 2302711aba9SDmitry Chagin case LINUX_CLOCK_SGI_CYCLE: 2312711aba9SDmitry Chagin case LINUX_CLOCK_TAI: 23219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, 23319e252baSAlexander Leidinger unsupported_clockid, l); 23419e252baSAlexander Leidinger return (EINVAL); 23577424f41SJung-uk Kim default: 23619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, 23719e252baSAlexander Leidinger unknown_clockid, l); 23877424f41SJung-uk Kim return (EINVAL); 239ad2056f2SAlexander Leidinger } 240ad2056f2SAlexander Leidinger 24177424f41SJung-uk Kim return (0); 242ad2056f2SAlexander Leidinger } 243ad2056f2SAlexander Leidinger 244ad2056f2SAlexander Leidinger int 245f0f58384SDmitry Chagin linux_to_native_timerflags(int *nflags, int flags) 246f0f58384SDmitry Chagin { 247f0f58384SDmitry Chagin 248f0f58384SDmitry Chagin if (flags & ~LINUX_TIMER_ABSTIME) 249f0f58384SDmitry Chagin return (EINVAL); 250f0f58384SDmitry Chagin *nflags = 0; 251f0f58384SDmitry Chagin if (flags & LINUX_TIMER_ABSTIME) 252f0f58384SDmitry Chagin *nflags |= TIMER_ABSTIME; 253f0f58384SDmitry Chagin return (0); 254f0f58384SDmitry Chagin } 255f0f58384SDmitry Chagin 25699b6f430SDmitry Chagin static int 25799b6f430SDmitry Chagin linux_common_clock_gettime(struct thread *td, clockid_t which, 25899b6f430SDmitry Chagin struct timespec *tp) 259ad2056f2SAlexander Leidinger { 2602711aba9SDmitry Chagin struct rusage ru; 2612711aba9SDmitry Chagin struct thread *targettd; 2622711aba9SDmitry Chagin struct proc *p; 2632711aba9SDmitry Chagin int error, clockwhich; 2642506c761SDmitry Chagin clockid_t nwhich; 2652711aba9SDmitry Chagin pid_t pid; 2662711aba9SDmitry Chagin lwpid_t tid; 267ad2056f2SAlexander Leidinger 26899b6f430SDmitry Chagin error = linux_to_native_clockid(&nwhich, which); 26919e252baSAlexander Leidinger if (error != 0) { 2704afe4faeSEdward Tomasz Napierala linux_msg(curthread, 27199b6f430SDmitry Chagin "unsupported clock_gettime clockid %d", which); 27299b6f430SDmitry Chagin LIN_SDT_PROBE1(time, linux_common_clock_gettime, 27399b6f430SDmitry Chagin conversion_error, error); 27477424f41SJung-uk Kim return (error); 27519e252baSAlexander Leidinger } 2762711aba9SDmitry Chagin 2772711aba9SDmitry Chagin switch (nwhich) { 2782711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 27999b6f430SDmitry Chagin if (which < 0) { 28099b6f430SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(which); 28199b6f430SDmitry Chagin pid = LINUX_CPUCLOCK_ID(which); 2827bc05ae6SDmitry Chagin } else { 2837bc05ae6SDmitry Chagin clockwhich = LINUX_CPUCLOCK_SCHED; 2847bc05ae6SDmitry Chagin pid = 0; 2857bc05ae6SDmitry Chagin } 2862711aba9SDmitry Chagin if (pid == 0) { 2872711aba9SDmitry Chagin p = td->td_proc; 2882711aba9SDmitry Chagin PROC_LOCK(p); 2892711aba9SDmitry Chagin } else { 2902711aba9SDmitry Chagin error = pget(pid, PGET_CANSEE, &p); 2912711aba9SDmitry Chagin if (error != 0) 2922711aba9SDmitry Chagin return (EINVAL); 2932711aba9SDmitry Chagin } 2942711aba9SDmitry Chagin switch (clockwhich) { 2952711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 2962711aba9SDmitry Chagin PROC_STATLOCK(p); 2972711aba9SDmitry Chagin calcru(p, &ru.ru_utime, &ru.ru_stime); 2982711aba9SDmitry Chagin PROC_STATUNLOCK(p); 2992711aba9SDmitry Chagin PROC_UNLOCK(p); 3002711aba9SDmitry Chagin timevaladd(&ru.ru_utime, &ru.ru_stime); 30199b6f430SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 3022711aba9SDmitry Chagin break; 3032711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 3042711aba9SDmitry Chagin PROC_STATLOCK(p); 3052711aba9SDmitry Chagin calcru(p, &ru.ru_utime, &ru.ru_stime); 3062711aba9SDmitry Chagin PROC_STATUNLOCK(p); 3072711aba9SDmitry Chagin PROC_UNLOCK(p); 30899b6f430SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 3092711aba9SDmitry Chagin break; 3102711aba9SDmitry Chagin case LINUX_CPUCLOCK_SCHED: 31199b6f430SDmitry Chagin kern_process_cputime(p, tp); 3122711aba9SDmitry Chagin PROC_UNLOCK(p); 3132711aba9SDmitry Chagin break; 3142711aba9SDmitry Chagin default: 3152711aba9SDmitry Chagin PROC_UNLOCK(p); 3162711aba9SDmitry Chagin return (EINVAL); 3172711aba9SDmitry Chagin } 3182711aba9SDmitry Chagin 3192711aba9SDmitry Chagin break; 3202711aba9SDmitry Chagin 3212711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 32299b6f430SDmitry Chagin if (which < 0) { 32399b6f430SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(which); 32499b6f430SDmitry Chagin tid = LINUX_CPUCLOCK_ID(which); 3257bc05ae6SDmitry Chagin } else { 3267bc05ae6SDmitry Chagin clockwhich = LINUX_CPUCLOCK_SCHED; 3277bc05ae6SDmitry Chagin tid = 0; 3287bc05ae6SDmitry Chagin } 3297bc05ae6SDmitry Chagin p = td->td_proc; 3302711aba9SDmitry Chagin if (tid == 0) { 3312711aba9SDmitry Chagin targettd = td; 3322711aba9SDmitry Chagin PROC_LOCK(p); 3332711aba9SDmitry Chagin } else { 3347bc05ae6SDmitry Chagin targettd = linux_tdfind(td, tid, p->p_pid); 3352711aba9SDmitry Chagin if (targettd == NULL) 3362711aba9SDmitry Chagin return (EINVAL); 3372711aba9SDmitry Chagin } 3382711aba9SDmitry Chagin switch (clockwhich) { 3392711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 3402711aba9SDmitry Chagin PROC_STATLOCK(p); 3412711aba9SDmitry Chagin thread_lock(targettd); 3422711aba9SDmitry Chagin rufetchtd(targettd, &ru); 3432711aba9SDmitry Chagin thread_unlock(targettd); 3442711aba9SDmitry Chagin PROC_STATUNLOCK(p); 3452711aba9SDmitry Chagin PROC_UNLOCK(p); 3462711aba9SDmitry Chagin timevaladd(&ru.ru_utime, &ru.ru_stime); 34799b6f430SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 3482711aba9SDmitry Chagin break; 3492711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 3502711aba9SDmitry Chagin PROC_STATLOCK(p); 3512711aba9SDmitry Chagin thread_lock(targettd); 3522711aba9SDmitry Chagin rufetchtd(targettd, &ru); 3532711aba9SDmitry Chagin thread_unlock(targettd); 3542711aba9SDmitry Chagin PROC_STATUNLOCK(p); 3552711aba9SDmitry Chagin PROC_UNLOCK(p); 35699b6f430SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp); 3572711aba9SDmitry Chagin break; 3582711aba9SDmitry Chagin case LINUX_CPUCLOCK_SCHED: 3597bc05ae6SDmitry Chagin if (td == targettd) 3607bc05ae6SDmitry Chagin targettd = NULL; 36199b6f430SDmitry Chagin kern_thread_cputime(targettd, tp); 3622711aba9SDmitry Chagin PROC_UNLOCK(p); 3632711aba9SDmitry Chagin break; 3642711aba9SDmitry Chagin default: 3652711aba9SDmitry Chagin PROC_UNLOCK(p); 3662711aba9SDmitry Chagin return (EINVAL); 3672711aba9SDmitry Chagin } 3682711aba9SDmitry Chagin break; 3692711aba9SDmitry Chagin 3702711aba9SDmitry Chagin default: 37199b6f430SDmitry Chagin error = kern_clock_gettime(td, nwhich, tp); 3722711aba9SDmitry Chagin break; 3732711aba9SDmitry Chagin } 37499b6f430SDmitry Chagin 37599b6f430SDmitry Chagin return (error); 37699b6f430SDmitry Chagin } 37799b6f430SDmitry Chagin 37899b6f430SDmitry Chagin int 37999b6f430SDmitry Chagin linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) 38099b6f430SDmitry Chagin { 38199b6f430SDmitry Chagin struct l_timespec lts; 38299b6f430SDmitry Chagin struct timespec tp; 38399b6f430SDmitry Chagin int error; 38499b6f430SDmitry Chagin 38599b6f430SDmitry Chagin error = linux_common_clock_gettime(td, args->which, &tp); 38619e252baSAlexander Leidinger if (error != 0) { 38719e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); 38877424f41SJung-uk Kim return (error); 38919e252baSAlexander Leidinger } 3900670e972SDmitry Chagin error = native_to_linux_timespec(<s, &tp); 3910670e972SDmitry Chagin if (error != 0) 3920670e972SDmitry Chagin return (error); 39399b6f430SDmitry Chagin error = copyout(<s, args->tp, sizeof(lts)); 39419e252baSAlexander Leidinger if (error != 0) 39519e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); 39619e252baSAlexander Leidinger 39719e252baSAlexander Leidinger return (error); 398ad2056f2SAlexander Leidinger } 399ad2056f2SAlexander Leidinger 40099b6f430SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 40199b6f430SDmitry Chagin int 40299b6f430SDmitry Chagin linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args) 40399b6f430SDmitry Chagin { 40499b6f430SDmitry Chagin struct l_timespec64 lts; 40599b6f430SDmitry Chagin struct timespec tp; 40699b6f430SDmitry Chagin int error; 40799b6f430SDmitry Chagin 40899b6f430SDmitry Chagin error = linux_common_clock_gettime(td, args->which, &tp); 40999b6f430SDmitry Chagin if (error != 0) { 41099b6f430SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error); 41199b6f430SDmitry Chagin return (error); 41299b6f430SDmitry Chagin } 41399b6f430SDmitry Chagin error = native_to_linux_timespec64(<s, &tp); 41499b6f430SDmitry Chagin if (error != 0) 41599b6f430SDmitry Chagin return (error); 41699b6f430SDmitry Chagin error = copyout(<s, args->tp, sizeof(lts)); 41799b6f430SDmitry Chagin if (error != 0) 41899b6f430SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error); 41999b6f430SDmitry Chagin 42099b6f430SDmitry Chagin return (error); 42199b6f430SDmitry Chagin } 42299b6f430SDmitry Chagin #endif 42399b6f430SDmitry Chagin 424*19f9a0e4SDmitry Chagin static int 425*19f9a0e4SDmitry Chagin linux_common_clock_settime(struct thread *td, clockid_t which, 426*19f9a0e4SDmitry Chagin struct timespec *ts) 427*19f9a0e4SDmitry Chagin { 428*19f9a0e4SDmitry Chagin int error; 429*19f9a0e4SDmitry Chagin clockid_t nwhich; 430*19f9a0e4SDmitry Chagin 431*19f9a0e4SDmitry Chagin error = linux_to_native_clockid(&nwhich, which); 432*19f9a0e4SDmitry Chagin if (error != 0) { 433*19f9a0e4SDmitry Chagin linux_msg(curthread, 434*19f9a0e4SDmitry Chagin "unsupported clock_settime clockid %d", which); 435*19f9a0e4SDmitry Chagin LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error, 436*19f9a0e4SDmitry Chagin error); 437*19f9a0e4SDmitry Chagin return (error); 438*19f9a0e4SDmitry Chagin } 439*19f9a0e4SDmitry Chagin 440*19f9a0e4SDmitry Chagin error = kern_clock_settime(td, nwhich, ts); 441*19f9a0e4SDmitry Chagin if (error != 0) 442*19f9a0e4SDmitry Chagin LIN_SDT_PROBE1(time, linux_common_clock_settime, 443*19f9a0e4SDmitry Chagin settime_error, error); 444*19f9a0e4SDmitry Chagin 445*19f9a0e4SDmitry Chagin return (error); 446*19f9a0e4SDmitry Chagin } 447*19f9a0e4SDmitry Chagin 448ad2056f2SAlexander Leidinger int 449ad2056f2SAlexander Leidinger linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) 450ad2056f2SAlexander Leidinger { 451ad2056f2SAlexander Leidinger struct timespec ts; 452ad2056f2SAlexander Leidinger struct l_timespec lts; 453ad2056f2SAlexander Leidinger int error; 454ad2056f2SAlexander Leidinger 455*19f9a0e4SDmitry Chagin error = copyin(args->tp, <s, sizeof(lts)); 45619e252baSAlexander Leidinger if (error != 0) { 45719e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); 45819e252baSAlexander Leidinger return (error); 45919e252baSAlexander Leidinger } 46019e252baSAlexander Leidinger error = linux_to_native_timespec(&ts, <s); 461*19f9a0e4SDmitry Chagin if (error != 0) 46219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 46319e252baSAlexander Leidinger error); 464*19f9a0e4SDmitry Chagin 465*19f9a0e4SDmitry Chagin return (linux_common_clock_settime(td, args->which, &ts)); 46619e252baSAlexander Leidinger } 46719e252baSAlexander Leidinger 468*19f9a0e4SDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 469*19f9a0e4SDmitry Chagin int 470*19f9a0e4SDmitry Chagin linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args) 471*19f9a0e4SDmitry Chagin { 472*19f9a0e4SDmitry Chagin struct timespec ts; 473*19f9a0e4SDmitry Chagin struct l_timespec64 lts; 474*19f9a0e4SDmitry Chagin int error; 475*19f9a0e4SDmitry Chagin 476*19f9a0e4SDmitry Chagin error = copyin(args->tp, <s, sizeof(lts)); 477*19f9a0e4SDmitry Chagin if (error != 0) { 478*19f9a0e4SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error); 479*19f9a0e4SDmitry Chagin return (error); 480*19f9a0e4SDmitry Chagin } 481*19f9a0e4SDmitry Chagin error = linux_to_native_timespec64(&ts, <s); 48219e252baSAlexander Leidinger if (error != 0) 483*19f9a0e4SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_settime64, conversion_error, 484*19f9a0e4SDmitry Chagin error); 485*19f9a0e4SDmitry Chagin return (linux_common_clock_settime(td, args->which, &ts)); 486ad2056f2SAlexander Leidinger } 487*19f9a0e4SDmitry Chagin #endif 488ad2056f2SAlexander Leidinger 489ad2056f2SAlexander Leidinger int 490ad2056f2SAlexander Leidinger linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args) 491ad2056f2SAlexander Leidinger { 4922711aba9SDmitry Chagin struct proc *p; 493ad2056f2SAlexander Leidinger struct timespec ts; 494ad2056f2SAlexander Leidinger struct l_timespec lts; 4952711aba9SDmitry Chagin int error, clockwhich; 4962506c761SDmitry Chagin clockid_t nwhich; 4972711aba9SDmitry Chagin pid_t pid; 4982711aba9SDmitry Chagin lwpid_t tid; 499ad2056f2SAlexander Leidinger 500ad2056f2SAlexander Leidinger error = linux_to_native_clockid(&nwhich, args->which); 50119e252baSAlexander Leidinger if (error != 0) { 5024afe4faeSEdward Tomasz Napierala linux_msg(curthread, 5034afe4faeSEdward Tomasz Napierala "unsupported clock_getres clockid %d", args->which); 50419e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, 50519e252baSAlexander Leidinger error); 50677424f41SJung-uk Kim return (error); 50719e252baSAlexander Leidinger } 5082711aba9SDmitry Chagin 5092711aba9SDmitry Chagin /* 5102711aba9SDmitry Chagin * Check user supplied clock id in case of per-process 5112711aba9SDmitry Chagin * or thread-specific cpu-time clock. 5122711aba9SDmitry Chagin */ 5137bc05ae6SDmitry Chagin if (args->which < 0) { 5142711aba9SDmitry Chagin switch (nwhich) { 5152711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 5162711aba9SDmitry Chagin tid = LINUX_CPUCLOCK_ID(args->which); 5172711aba9SDmitry Chagin if (tid != 0) { 5182711aba9SDmitry Chagin p = td->td_proc; 5197bc05ae6SDmitry Chagin if (linux_tdfind(td, tid, p->p_pid) == NULL) 5207bc05ae6SDmitry Chagin return (EINVAL); 5212711aba9SDmitry Chagin PROC_UNLOCK(p); 5222711aba9SDmitry Chagin } 5232711aba9SDmitry Chagin break; 5242711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 5252711aba9SDmitry Chagin pid = LINUX_CPUCLOCK_ID(args->which); 5262711aba9SDmitry Chagin if (pid != 0) { 5272711aba9SDmitry Chagin error = pget(pid, PGET_CANSEE, &p); 5282711aba9SDmitry Chagin if (error != 0) 5292711aba9SDmitry Chagin return (EINVAL); 5302711aba9SDmitry Chagin PROC_UNLOCK(p); 5312711aba9SDmitry Chagin } 5322711aba9SDmitry Chagin break; 5332711aba9SDmitry Chagin } 5347bc05ae6SDmitry Chagin } 5352711aba9SDmitry Chagin 5362711aba9SDmitry Chagin if (args->tp == NULL) { 5372711aba9SDmitry Chagin LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); 5382711aba9SDmitry Chagin return (0); 5392711aba9SDmitry Chagin } 5402711aba9SDmitry Chagin 5412711aba9SDmitry Chagin switch (nwhich) { 5422711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 5432711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 5442711aba9SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 5457bc05ae6SDmitry Chagin /* 5467bc05ae6SDmitry Chagin * In both cases (when the clock id obtained by a call to 5477bc05ae6SDmitry Chagin * clock_getcpuclockid() or using the clock 5487bc05ae6SDmitry Chagin * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision 5497bc05ae6SDmitry Chagin * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock. 5507bc05ae6SDmitry Chagin * 5517bc05ae6SDmitry Chagin * See Linux posix_cpu_clock_getres() implementation. 5527bc05ae6SDmitry Chagin */ 5537bc05ae6SDmitry Chagin if (args->which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) { 5547bc05ae6SDmitry Chagin ts.tv_sec = 0; 5557bc05ae6SDmitry Chagin ts.tv_nsec = 1; 5567bc05ae6SDmitry Chagin goto out; 5577bc05ae6SDmitry Chagin } 5587bc05ae6SDmitry Chagin 5592711aba9SDmitry Chagin switch (clockwhich) { 5602711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 5612711aba9SDmitry Chagin nwhich = CLOCK_PROF; 5622711aba9SDmitry Chagin break; 5632711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 5642711aba9SDmitry Chagin nwhich = CLOCK_VIRTUAL; 5652711aba9SDmitry Chagin break; 5662711aba9SDmitry Chagin default: 5672711aba9SDmitry Chagin return (EINVAL); 5682711aba9SDmitry Chagin } 5692711aba9SDmitry Chagin break; 5702711aba9SDmitry Chagin 5712711aba9SDmitry Chagin default: 5722711aba9SDmitry Chagin break; 5732711aba9SDmitry Chagin } 574ad2056f2SAlexander Leidinger error = kern_clock_getres(td, nwhich, &ts); 57519e252baSAlexander Leidinger if (error != 0) { 57619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error); 57777424f41SJung-uk Kim return (error); 57819e252baSAlexander Leidinger } 5797bc05ae6SDmitry Chagin 5807bc05ae6SDmitry Chagin out: 5810670e972SDmitry Chagin error = native_to_linux_timespec(<s, &ts); 5820670e972SDmitry Chagin if (error != 0) 5830670e972SDmitry Chagin return (error); 58419e252baSAlexander Leidinger error = copyout(<s, args->tp, sizeof lts); 58519e252baSAlexander Leidinger if (error != 0) 58619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error); 58719e252baSAlexander Leidinger 58819e252baSAlexander Leidinger return (error); 58977424f41SJung-uk Kim } 59077424f41SJung-uk Kim 59177424f41SJung-uk Kim int 59277424f41SJung-uk Kim linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) 59377424f41SJung-uk Kim { 59477424f41SJung-uk Kim struct timespec *rmtp; 59577424f41SJung-uk Kim struct l_timespec lrqts, lrmts; 59677424f41SJung-uk Kim struct timespec rqts, rmts; 5975c2748d5SDmitry Chagin int error, error2; 59877424f41SJung-uk Kim 59977424f41SJung-uk Kim error = copyin(args->rqtp, &lrqts, sizeof lrqts); 60019e252baSAlexander Leidinger if (error != 0) { 60119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); 60277424f41SJung-uk Kim return (error); 60319e252baSAlexander Leidinger } 60477424f41SJung-uk Kim 60577424f41SJung-uk Kim if (args->rmtp != NULL) 60677424f41SJung-uk Kim rmtp = &rmts; 60777424f41SJung-uk Kim else 60877424f41SJung-uk Kim rmtp = NULL; 60977424f41SJung-uk Kim 61077424f41SJung-uk Kim error = linux_to_native_timespec(&rqts, &lrqts); 61119e252baSAlexander Leidinger if (error != 0) { 61219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error); 61377424f41SJung-uk Kim return (error); 61419e252baSAlexander Leidinger } 61577424f41SJung-uk Kim error = kern_nanosleep(td, &rqts, rmtp); 6164cf66812SEric van Gyzen if (error == EINTR && args->rmtp != NULL) { 6170670e972SDmitry Chagin error2 = native_to_linux_timespec(&lrmts, rmtp); 6180670e972SDmitry Chagin if (error2 != 0) 6190670e972SDmitry Chagin return (error2); 6205c2748d5SDmitry Chagin error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 6215c2748d5SDmitry Chagin if (error2 != 0) { 62219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, 6235c2748d5SDmitry Chagin error2); 6245c2748d5SDmitry Chagin return (error2); 62577424f41SJung-uk Kim } 62619e252baSAlexander Leidinger } 62777424f41SJung-uk Kim 6285c2748d5SDmitry Chagin return (error); 629ad2056f2SAlexander Leidinger } 630ad2056f2SAlexander Leidinger 631ad2056f2SAlexander Leidinger int 632ad2056f2SAlexander Leidinger linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args) 633ad2056f2SAlexander Leidinger { 634ad2056f2SAlexander Leidinger struct timespec *rmtp; 635ad2056f2SAlexander Leidinger struct l_timespec lrqts, lrmts; 636ad2056f2SAlexander Leidinger struct timespec rqts, rmts; 637f0f58384SDmitry Chagin int error, error2, flags; 638f0f58384SDmitry Chagin clockid_t clockid; 639ad2056f2SAlexander Leidinger 640f0f58384SDmitry Chagin error = linux_to_native_timerflags(&flags, args->flags); 641f0f58384SDmitry Chagin if (error != 0) { 64219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, 64319e252baSAlexander Leidinger args->flags); 644f0f58384SDmitry Chagin return (error); 64519e252baSAlexander Leidinger } 64619e252baSAlexander Leidinger 647f0f58384SDmitry Chagin error = linux_to_native_clockid(&clockid, args->which); 648f0f58384SDmitry Chagin if (error != 0) { 6494afe4faeSEdward Tomasz Napierala linux_msg(curthread, 6504afe4faeSEdward Tomasz Napierala "unsupported clock_nanosleep clockid %d", args->which); 65119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, 65219e252baSAlexander Leidinger args->which); 653f0f58384SDmitry Chagin return (error); 65419e252baSAlexander Leidinger } 655ad2056f2SAlexander Leidinger 6565c2748d5SDmitry Chagin error = copyin(args->rqtp, &lrqts, sizeof(lrqts)); 65719e252baSAlexander Leidinger if (error != 0) { 65819e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, 65919e252baSAlexander Leidinger error); 66077424f41SJung-uk Kim return (error); 66119e252baSAlexander Leidinger } 662ad2056f2SAlexander Leidinger 663ad2056f2SAlexander Leidinger if (args->rmtp != NULL) 664ad2056f2SAlexander Leidinger rmtp = &rmts; 665ad2056f2SAlexander Leidinger else 666ad2056f2SAlexander Leidinger rmtp = NULL; 667ad2056f2SAlexander Leidinger 66877424f41SJung-uk Kim error = linux_to_native_timespec(&rqts, &lrqts); 66919e252baSAlexander Leidinger if (error != 0) { 67019e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error, 67119e252baSAlexander Leidinger error); 67277424f41SJung-uk Kim return (error); 67319e252baSAlexander Leidinger } 674f0f58384SDmitry Chagin error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp); 675f0f58384SDmitry Chagin if (error == EINTR && (flags & TIMER_ABSTIME) == 0 && 676f0f58384SDmitry Chagin args->rmtp != NULL) { 6770670e972SDmitry Chagin error2 = native_to_linux_timespec(&lrmts, rmtp); 6780670e972SDmitry Chagin if (error2 != 0) 6790670e972SDmitry Chagin return (error2); 6805c2748d5SDmitry Chagin error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 6815c2748d5SDmitry Chagin if (error2 != 0) { 6825c2748d5SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_nanosleep, 6835c2748d5SDmitry Chagin copyout_error, error2); 6845c2748d5SDmitry Chagin return (error2); 6855c2748d5SDmitry Chagin } 6865c2748d5SDmitry Chagin } 6875c2748d5SDmitry Chagin 68877424f41SJung-uk Kim return (error); 68919e252baSAlexander Leidinger } 690