1ad2056f2SAlexander Leidinger /* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */ 2ad2056f2SAlexander Leidinger 3ad2056f2SAlexander Leidinger /*- 4ad2056f2SAlexander Leidinger * Copyright (c) 2001 The NetBSD Foundation, Inc. 5ad2056f2SAlexander Leidinger * All rights reserved. 6ad2056f2SAlexander Leidinger * 7ad2056f2SAlexander Leidinger * This code is derived from software contributed to The NetBSD Foundation 8ad2056f2SAlexander Leidinger * by Emmanuel Dreyfus. 9ad2056f2SAlexander Leidinger * 10ad2056f2SAlexander Leidinger * Redistribution and use in source and binary forms, with or without 11ad2056f2SAlexander Leidinger * modification, are permitted provided that the following conditions 12ad2056f2SAlexander Leidinger * are met: 13ad2056f2SAlexander Leidinger * 1. Redistributions of source code must retain the above copyright 14ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer. 15ad2056f2SAlexander Leidinger * 2. Redistributions in binary form must reproduce the above copyright 16ad2056f2SAlexander Leidinger * notice, this list of conditions and the following disclaimer in the 17ad2056f2SAlexander Leidinger * documentation and/or other materials provided with the distribution. 18ad2056f2SAlexander Leidinger * 19ad2056f2SAlexander Leidinger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20ad2056f2SAlexander Leidinger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21ad2056f2SAlexander Leidinger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22ad2056f2SAlexander Leidinger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23ad2056f2SAlexander Leidinger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24ad2056f2SAlexander Leidinger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25ad2056f2SAlexander Leidinger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26ad2056f2SAlexander Leidinger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27ad2056f2SAlexander Leidinger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28ad2056f2SAlexander Leidinger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29ad2056f2SAlexander Leidinger * POSSIBILITY OF SUCH DAMAGE. 30ad2056f2SAlexander Leidinger */ 31ad2056f2SAlexander Leidinger 32ad2056f2SAlexander Leidinger #include <sys/cdefs.h> 33ad2056f2SAlexander Leidinger __FBSDID("$FreeBSD$"); 34ad2056f2SAlexander Leidinger #if 0 35ad2056f2SAlexander Leidinger __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); 36ad2056f2SAlexander Leidinger #endif 37ad2056f2SAlexander Leidinger 38ad2056f2SAlexander Leidinger #include "opt_compat.h" 39ad2056f2SAlexander Leidinger 40ad2056f2SAlexander Leidinger #include <sys/param.h> 4119e252baSAlexander Leidinger #include <sys/kernel.h> 422711aba9SDmitry Chagin #include <sys/lock.h> 43ad2056f2SAlexander Leidinger #include <sys/ucred.h> 440670e972SDmitry Chagin #include <sys/limits.h> 45ad2056f2SAlexander Leidinger #include <sys/mount.h> 462711aba9SDmitry Chagin #include <sys/mutex.h> 472711aba9SDmitry Chagin #include <sys/resourcevar.h> 4819e252baSAlexander Leidinger #include <sys/sdt.h> 49ad2056f2SAlexander Leidinger #include <sys/signal.h> 50ad2056f2SAlexander Leidinger #include <sys/stdint.h> 51ad2056f2SAlexander Leidinger #include <sys/syscallsubr.h> 52ad2056f2SAlexander Leidinger #include <sys/sysproto.h> 53ad2056f2SAlexander Leidinger #include <sys/time.h> 54ad2056f2SAlexander Leidinger #include <sys/systm.h> 55ad2056f2SAlexander Leidinger #include <sys/proc.h> 56ad2056f2SAlexander Leidinger 57ad2056f2SAlexander Leidinger #ifdef COMPAT_LINUX32 58ad2056f2SAlexander Leidinger #include <machine/../linux32/linux.h> 59ad2056f2SAlexander Leidinger #include <machine/../linux32/linux32_proto.h> 60ad2056f2SAlexander Leidinger #else 61ad2056f2SAlexander Leidinger #include <machine/../linux/linux.h> 62ad2056f2SAlexander Leidinger #include <machine/../linux/linux_proto.h> 63ad2056f2SAlexander Leidinger #endif 64ad2056f2SAlexander Leidinger 6519e252baSAlexander Leidinger #include <compat/linux/linux_dtrace.h> 662711aba9SDmitry Chagin #include <compat/linux/linux_timer.h> 6719e252baSAlexander Leidinger 6819e252baSAlexander Leidinger /* DTrace init */ 6919e252baSAlexander Leidinger LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 7019e252baSAlexander Leidinger 7119e252baSAlexander Leidinger /** 7219e252baSAlexander Leidinger * DTrace probes in this module. 7319e252baSAlexander Leidinger */ 7419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry, 7519e252baSAlexander Leidinger "struct l_timespec *", "struct timespec *"); 7619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return); 7719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry, 7819e252baSAlexander Leidinger "struct timespec *", "struct l_timespec *"); 7919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int"); 8019e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *", 8119e252baSAlexander Leidinger "clockid_t"); 8219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, 8319e252baSAlexander Leidinger "clockid_t"); 8419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, 8519e252baSAlexander Leidinger "clockid_t"); 8619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int"); 8719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t", 8819e252baSAlexander Leidinger "struct l_timespec *"); 8919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int"); 9019e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); 9119e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); 9219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int"); 9319e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t", 9419e252baSAlexander Leidinger "struct l_timespec *"); 9519e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); 9619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int"); 9719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); 9819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int"); 9919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t", 10019e252baSAlexander Leidinger "struct l_timespec *"); 10119e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall); 10219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int"); 10319e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int"); 10419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); 10519e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int"); 10619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *", 10719e252baSAlexander Leidinger "struct l_timespec *"); 10819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int"); 10919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); 11019e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); 11119e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int"); 11219e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int", 11319e252baSAlexander Leidinger "struct l_timespec *", "struct l_timespec *"); 11419e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int"); 11519e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); 11619e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); 11719e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int"); 11819e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int"); 11919e252baSAlexander Leidinger LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int"); 12019e252baSAlexander Leidinger 12168098228SDmitry Chagin 1220670e972SDmitry Chagin int 123ad2056f2SAlexander Leidinger native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) 124ad2056f2SAlexander Leidinger { 12519e252baSAlexander Leidinger 12619e252baSAlexander Leidinger LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp); 1270670e972SDmitry Chagin #ifdef COMPAT_LINUX32 12871b50d08SDmitry Chagin if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN) 1290670e972SDmitry Chagin return (EOVERFLOW); 1300670e972SDmitry Chagin #endif 131ad2056f2SAlexander Leidinger ltp->tv_sec = ntp->tv_sec; 132ad2056f2SAlexander Leidinger ltp->tv_nsec = ntp->tv_nsec; 13319e252baSAlexander Leidinger 13419e252baSAlexander Leidinger LIN_SDT_PROBE0(time, native_to_linux_timespec, return); 1350670e972SDmitry Chagin return (0); 136ad2056f2SAlexander Leidinger } 137ad2056f2SAlexander Leidinger 13868098228SDmitry Chagin int 139ad2056f2SAlexander Leidinger linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) 140ad2056f2SAlexander Leidinger { 14119e252baSAlexander Leidinger 14219e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp); 14319e252baSAlexander Leidinger 1442ac9dcedSDmitry Chagin if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999) { 14519e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL); 14677424f41SJung-uk Kim return (EINVAL); 14719e252baSAlexander Leidinger } 148ad2056f2SAlexander Leidinger ntp->tv_sec = ltp->tv_sec; 149ad2056f2SAlexander Leidinger ntp->tv_nsec = ltp->tv_nsec; 15077424f41SJung-uk Kim 15119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0); 15277424f41SJung-uk Kim return (0); 153ad2056f2SAlexander Leidinger } 154ad2056f2SAlexander Leidinger 15516ac71bcSDmitry Chagin int 156dd93b628SDmitry Chagin native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp) 157dd93b628SDmitry Chagin { 158dd93b628SDmitry Chagin int error; 159dd93b628SDmitry Chagin 160dd93b628SDmitry Chagin error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval); 161dd93b628SDmitry Chagin if (error == 0) 162dd93b628SDmitry Chagin error = native_to_linux_timespec(<p->it_value, &ntp->it_interval); 163dd93b628SDmitry Chagin return (error); 164dd93b628SDmitry Chagin } 165dd93b628SDmitry Chagin 166dd93b628SDmitry Chagin int 167dd93b628SDmitry Chagin linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp) 168dd93b628SDmitry Chagin { 169dd93b628SDmitry Chagin int error; 170dd93b628SDmitry Chagin 171dd93b628SDmitry Chagin error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval); 172dd93b628SDmitry Chagin if (error == 0) 173dd93b628SDmitry Chagin error = linux_to_native_timespec(&ntp->it_value, <p->it_value); 174dd93b628SDmitry Chagin return (error); 175dd93b628SDmitry Chagin } 176dd93b628SDmitry Chagin 177dd93b628SDmitry Chagin int 178ad2056f2SAlexander Leidinger linux_to_native_clockid(clockid_t *n, clockid_t l) 179ad2056f2SAlexander Leidinger { 18019e252baSAlexander Leidinger 18119e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l); 18219e252baSAlexander Leidinger 1832711aba9SDmitry Chagin if (l < 0) { 1842711aba9SDmitry Chagin /* cpu-clock */ 1852711aba9SDmitry Chagin if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD) 1862711aba9SDmitry Chagin return (EINVAL); 1872711aba9SDmitry Chagin if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX) 1882711aba9SDmitry Chagin return (EINVAL); 1892711aba9SDmitry Chagin 1902711aba9SDmitry Chagin if (LINUX_CPUCLOCK_PERTHREAD(l)) 1912711aba9SDmitry Chagin *n = CLOCK_THREAD_CPUTIME_ID; 1922711aba9SDmitry Chagin else 1932711aba9SDmitry Chagin *n = CLOCK_PROCESS_CPUTIME_ID; 1942711aba9SDmitry Chagin return (0); 1952711aba9SDmitry Chagin } 1962711aba9SDmitry Chagin 197ad2056f2SAlexander Leidinger switch (l) { 198ad2056f2SAlexander Leidinger case LINUX_CLOCK_REALTIME: 199ad2056f2SAlexander Leidinger *n = CLOCK_REALTIME; 200ad2056f2SAlexander Leidinger break; 201ad2056f2SAlexander Leidinger case LINUX_CLOCK_MONOTONIC: 202ad2056f2SAlexander Leidinger *n = CLOCK_MONOTONIC; 203ad2056f2SAlexander Leidinger break; 2042711aba9SDmitry Chagin case LINUX_CLOCK_REALTIME_COARSE: 2052711aba9SDmitry Chagin *n = CLOCK_REALTIME_FAST; 2062711aba9SDmitry Chagin break; 2072711aba9SDmitry Chagin case LINUX_CLOCK_MONOTONIC_COARSE: 2082711aba9SDmitry Chagin *n = CLOCK_MONOTONIC_FAST; 2092711aba9SDmitry Chagin break; 2102711aba9SDmitry Chagin case LINUX_CLOCK_BOOTTIME: 211*25ada637SDmitry Chagin *n = CLOCK_UPTIME; 212*25ada637SDmitry Chagin break; 213*25ada637SDmitry Chagin case LINUX_CLOCK_MONOTONIC_RAW: 2142711aba9SDmitry Chagin case LINUX_CLOCK_REALTIME_ALARM: 2152711aba9SDmitry Chagin case LINUX_CLOCK_BOOTTIME_ALARM: 2162711aba9SDmitry Chagin case LINUX_CLOCK_SGI_CYCLE: 2172711aba9SDmitry Chagin case LINUX_CLOCK_TAI: 21819e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, 21919e252baSAlexander Leidinger unsupported_clockid, l); 22019e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); 22119e252baSAlexander Leidinger return (EINVAL); 22277424f41SJung-uk Kim default: 22319e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, 22419e252baSAlexander Leidinger unknown_clockid, l); 22519e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); 22677424f41SJung-uk Kim return (EINVAL); 227ad2056f2SAlexander Leidinger } 228ad2056f2SAlexander Leidinger 22919e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0); 23077424f41SJung-uk Kim return (0); 231ad2056f2SAlexander Leidinger } 232ad2056f2SAlexander Leidinger 233ad2056f2SAlexander Leidinger int 234f0f58384SDmitry Chagin linux_to_native_timerflags(int *nflags, int flags) 235f0f58384SDmitry Chagin { 236f0f58384SDmitry Chagin 237f0f58384SDmitry Chagin if (flags & ~LINUX_TIMER_ABSTIME) 238f0f58384SDmitry Chagin return (EINVAL); 239f0f58384SDmitry Chagin *nflags = 0; 240f0f58384SDmitry Chagin if (flags & LINUX_TIMER_ABSTIME) 241f0f58384SDmitry Chagin *nflags |= TIMER_ABSTIME; 242f0f58384SDmitry Chagin return (0); 243f0f58384SDmitry Chagin } 244f0f58384SDmitry Chagin 245f0f58384SDmitry Chagin int 246ad2056f2SAlexander Leidinger linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) 247ad2056f2SAlexander Leidinger { 248ad2056f2SAlexander Leidinger struct l_timespec lts; 249ad2056f2SAlexander Leidinger struct timespec tp; 2502711aba9SDmitry Chagin struct rusage ru; 2512711aba9SDmitry Chagin struct thread *targettd; 2522711aba9SDmitry Chagin struct proc *p; 2532711aba9SDmitry Chagin int error, clockwhich; 2542711aba9SDmitry Chagin clockid_t nwhich = 0; /* XXX: GCC */ 2552711aba9SDmitry Chagin pid_t pid; 2562711aba9SDmitry Chagin lwpid_t tid; 257ad2056f2SAlexander Leidinger 25819e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp); 25919e252baSAlexander Leidinger 260ad2056f2SAlexander Leidinger error = linux_to_native_clockid(&nwhich, args->which); 26119e252baSAlexander Leidinger if (error != 0) { 26219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error, 26319e252baSAlexander Leidinger error); 26419e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 26577424f41SJung-uk Kim return (error); 26619e252baSAlexander Leidinger } 2672711aba9SDmitry Chagin 2682711aba9SDmitry Chagin switch (nwhich) { 2692711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 2702711aba9SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 2712711aba9SDmitry Chagin pid = LINUX_CPUCLOCK_ID(args->which); 2722711aba9SDmitry Chagin if (pid == 0) { 2732711aba9SDmitry Chagin p = td->td_proc; 2742711aba9SDmitry Chagin PROC_LOCK(p); 2752711aba9SDmitry Chagin } else { 2762711aba9SDmitry Chagin error = pget(pid, PGET_CANSEE, &p); 2772711aba9SDmitry Chagin if (error != 0) 2782711aba9SDmitry Chagin return (EINVAL); 2792711aba9SDmitry Chagin } 2802711aba9SDmitry Chagin switch (clockwhich) { 2812711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 2822711aba9SDmitry Chagin PROC_STATLOCK(p); 2832711aba9SDmitry Chagin calcru(p, &ru.ru_utime, &ru.ru_stime); 2842711aba9SDmitry Chagin PROC_STATUNLOCK(p); 2852711aba9SDmitry Chagin PROC_UNLOCK(p); 2862711aba9SDmitry Chagin timevaladd(&ru.ru_utime, &ru.ru_stime); 2872711aba9SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 2882711aba9SDmitry Chagin break; 2892711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 2902711aba9SDmitry Chagin PROC_STATLOCK(p); 2912711aba9SDmitry Chagin calcru(p, &ru.ru_utime, &ru.ru_stime); 2922711aba9SDmitry Chagin PROC_STATUNLOCK(p); 2932711aba9SDmitry Chagin PROC_UNLOCK(p); 2942711aba9SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 2952711aba9SDmitry Chagin break; 2962711aba9SDmitry Chagin case LINUX_CPUCLOCK_SCHED: 2972711aba9SDmitry Chagin PROC_UNLOCK(p); 2982711aba9SDmitry Chagin error = kern_clock_getcpuclockid2(td, pid, 2992711aba9SDmitry Chagin CPUCLOCK_WHICH_PID, &nwhich); 3002711aba9SDmitry Chagin if (error != 0) 3012711aba9SDmitry Chagin return (EINVAL); 302ad2056f2SAlexander Leidinger error = kern_clock_gettime(td, nwhich, &tp); 3032711aba9SDmitry Chagin break; 3042711aba9SDmitry Chagin default: 3052711aba9SDmitry Chagin PROC_UNLOCK(p); 3062711aba9SDmitry Chagin return (EINVAL); 3072711aba9SDmitry Chagin } 3082711aba9SDmitry Chagin 3092711aba9SDmitry Chagin break; 3102711aba9SDmitry Chagin 3112711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 3122711aba9SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 3132711aba9SDmitry Chagin p = td->td_proc; 3142711aba9SDmitry Chagin tid = LINUX_CPUCLOCK_ID(args->which); 3152711aba9SDmitry Chagin if (tid == 0) { 3162711aba9SDmitry Chagin targettd = td; 3172711aba9SDmitry Chagin PROC_LOCK(p); 3182711aba9SDmitry Chagin } else { 3192711aba9SDmitry Chagin targettd = tdfind(tid, p->p_pid); 3202711aba9SDmitry Chagin if (targettd == NULL) 3212711aba9SDmitry Chagin return (EINVAL); 3222711aba9SDmitry Chagin } 3232711aba9SDmitry Chagin switch (clockwhich) { 3242711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 3252711aba9SDmitry Chagin PROC_STATLOCK(p); 3262711aba9SDmitry Chagin thread_lock(targettd); 3272711aba9SDmitry Chagin rufetchtd(targettd, &ru); 3282711aba9SDmitry Chagin thread_unlock(targettd); 3292711aba9SDmitry Chagin PROC_STATUNLOCK(p); 3302711aba9SDmitry Chagin PROC_UNLOCK(p); 3312711aba9SDmitry Chagin timevaladd(&ru.ru_utime, &ru.ru_stime); 3322711aba9SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 3332711aba9SDmitry Chagin break; 3342711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 3352711aba9SDmitry Chagin PROC_STATLOCK(p); 3362711aba9SDmitry Chagin thread_lock(targettd); 3372711aba9SDmitry Chagin rufetchtd(targettd, &ru); 3382711aba9SDmitry Chagin thread_unlock(targettd); 3392711aba9SDmitry Chagin PROC_STATUNLOCK(p); 3402711aba9SDmitry Chagin PROC_UNLOCK(p); 3412711aba9SDmitry Chagin TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp); 3422711aba9SDmitry Chagin break; 3432711aba9SDmitry Chagin case LINUX_CPUCLOCK_SCHED: 3442711aba9SDmitry Chagin error = kern_clock_getcpuclockid2(td, tid, 3452711aba9SDmitry Chagin CPUCLOCK_WHICH_TID, &nwhich); 3462711aba9SDmitry Chagin PROC_UNLOCK(p); 3472711aba9SDmitry Chagin if (error != 0) 3482711aba9SDmitry Chagin return (EINVAL); 3492711aba9SDmitry Chagin error = kern_clock_gettime(td, nwhich, &tp); 3502711aba9SDmitry Chagin break; 3512711aba9SDmitry Chagin default: 3522711aba9SDmitry Chagin PROC_UNLOCK(p); 3532711aba9SDmitry Chagin return (EINVAL); 3542711aba9SDmitry Chagin } 3552711aba9SDmitry Chagin break; 3562711aba9SDmitry Chagin 3572711aba9SDmitry Chagin default: 3582711aba9SDmitry Chagin error = kern_clock_gettime(td, nwhich, &tp); 3592711aba9SDmitry Chagin break; 3602711aba9SDmitry Chagin } 36119e252baSAlexander Leidinger if (error != 0) { 36219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); 36319e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 36477424f41SJung-uk Kim return (error); 36519e252baSAlexander Leidinger } 3660670e972SDmitry Chagin error = native_to_linux_timespec(<s, &tp); 3670670e972SDmitry Chagin if (error != 0) 3680670e972SDmitry Chagin return (error); 36919e252baSAlexander Leidinger error = copyout(<s, args->tp, sizeof lts); 37019e252baSAlexander Leidinger if (error != 0) 37119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); 37219e252baSAlexander Leidinger 37319e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 37419e252baSAlexander Leidinger return (error); 375ad2056f2SAlexander Leidinger } 376ad2056f2SAlexander Leidinger 377ad2056f2SAlexander Leidinger int 378ad2056f2SAlexander Leidinger linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) 379ad2056f2SAlexander Leidinger { 380ad2056f2SAlexander Leidinger struct timespec ts; 381ad2056f2SAlexander Leidinger struct l_timespec lts; 382ad2056f2SAlexander Leidinger int error; 383ad2056f2SAlexander Leidinger clockid_t nwhich = 0; /* XXX: GCC */ 384ad2056f2SAlexander Leidinger 38519e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp); 386ad2056f2SAlexander Leidinger 38719e252baSAlexander Leidinger error = linux_to_native_clockid(&nwhich, args->which); 38819e252baSAlexander Leidinger if (error != 0) { 38919e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 39019e252baSAlexander Leidinger error); 39119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 39219e252baSAlexander Leidinger return (error); 39319e252baSAlexander Leidinger } 39419e252baSAlexander Leidinger error = copyin(args->tp, <s, sizeof lts); 39519e252baSAlexander Leidinger if (error != 0) { 39619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); 39719e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 39819e252baSAlexander Leidinger return (error); 39919e252baSAlexander Leidinger } 40019e252baSAlexander Leidinger error = linux_to_native_timespec(&ts, <s); 40119e252baSAlexander Leidinger if (error != 0) { 40219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 40319e252baSAlexander Leidinger error); 40419e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 40519e252baSAlexander Leidinger return (error); 40619e252baSAlexander Leidinger } 40719e252baSAlexander Leidinger 40819e252baSAlexander Leidinger error = kern_clock_settime(td, nwhich, &ts); 40919e252baSAlexander Leidinger if (error != 0) 41019e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error); 41119e252baSAlexander Leidinger 41219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 41319e252baSAlexander Leidinger return (error); 414ad2056f2SAlexander Leidinger } 415ad2056f2SAlexander Leidinger 416ad2056f2SAlexander Leidinger int 417ad2056f2SAlexander Leidinger linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args) 418ad2056f2SAlexander Leidinger { 4192711aba9SDmitry Chagin struct proc *p; 420ad2056f2SAlexander Leidinger struct timespec ts; 421ad2056f2SAlexander Leidinger struct l_timespec lts; 4222711aba9SDmitry Chagin int error, clockwhich; 423ad2056f2SAlexander Leidinger clockid_t nwhich = 0; /* XXX: GCC */ 4242711aba9SDmitry Chagin pid_t pid; 4252711aba9SDmitry Chagin lwpid_t tid; 426ad2056f2SAlexander Leidinger 42719e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp); 42819e252baSAlexander Leidinger 429ad2056f2SAlexander Leidinger error = linux_to_native_clockid(&nwhich, args->which); 43019e252baSAlexander Leidinger if (error != 0) { 43119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, 43219e252baSAlexander Leidinger error); 43319e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 43477424f41SJung-uk Kim return (error); 43519e252baSAlexander Leidinger } 4362711aba9SDmitry Chagin 4372711aba9SDmitry Chagin /* 4382711aba9SDmitry Chagin * Check user supplied clock id in case of per-process 4392711aba9SDmitry Chagin * or thread-specific cpu-time clock. 4402711aba9SDmitry Chagin */ 4412711aba9SDmitry Chagin switch (nwhich) { 4422711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 4432711aba9SDmitry Chagin tid = LINUX_CPUCLOCK_ID(args->which); 4442711aba9SDmitry Chagin if (tid != 0) { 4452711aba9SDmitry Chagin p = td->td_proc; 4462711aba9SDmitry Chagin if (tdfind(tid, p->p_pid) == NULL) 4472711aba9SDmitry Chagin return (ESRCH); 4482711aba9SDmitry Chagin PROC_UNLOCK(p); 4492711aba9SDmitry Chagin } 4502711aba9SDmitry Chagin break; 4512711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 4522711aba9SDmitry Chagin pid = LINUX_CPUCLOCK_ID(args->which); 4532711aba9SDmitry Chagin if (pid != 0) { 4542711aba9SDmitry Chagin error = pget(pid, PGET_CANSEE, &p); 4552711aba9SDmitry Chagin if (error != 0) 4562711aba9SDmitry Chagin return (EINVAL); 4572711aba9SDmitry Chagin PROC_UNLOCK(p); 4582711aba9SDmitry Chagin } 4592711aba9SDmitry Chagin break; 4602711aba9SDmitry Chagin } 4612711aba9SDmitry Chagin 4622711aba9SDmitry Chagin if (args->tp == NULL) { 4632711aba9SDmitry Chagin LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); 4642711aba9SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_getres, return, 0); 4652711aba9SDmitry Chagin return (0); 4662711aba9SDmitry Chagin } 4672711aba9SDmitry Chagin 4682711aba9SDmitry Chagin switch (nwhich) { 4692711aba9SDmitry Chagin case CLOCK_THREAD_CPUTIME_ID: 4702711aba9SDmitry Chagin case CLOCK_PROCESS_CPUTIME_ID: 4712711aba9SDmitry Chagin clockwhich = LINUX_CPUCLOCK_WHICH(args->which); 4722711aba9SDmitry Chagin switch (clockwhich) { 4732711aba9SDmitry Chagin case LINUX_CPUCLOCK_PROF: 4742711aba9SDmitry Chagin nwhich = CLOCK_PROF; 4752711aba9SDmitry Chagin break; 4762711aba9SDmitry Chagin case LINUX_CPUCLOCK_VIRT: 4772711aba9SDmitry Chagin nwhich = CLOCK_VIRTUAL; 4782711aba9SDmitry Chagin break; 4792711aba9SDmitry Chagin case LINUX_CPUCLOCK_SCHED: 4802711aba9SDmitry Chagin break; 4812711aba9SDmitry Chagin default: 4822711aba9SDmitry Chagin return (EINVAL); 4832711aba9SDmitry Chagin } 4842711aba9SDmitry Chagin break; 4852711aba9SDmitry Chagin 4862711aba9SDmitry Chagin default: 4872711aba9SDmitry Chagin break; 4882711aba9SDmitry Chagin } 489ad2056f2SAlexander Leidinger error = kern_clock_getres(td, nwhich, &ts); 49019e252baSAlexander Leidinger if (error != 0) { 49119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error); 49219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 49377424f41SJung-uk Kim return (error); 49419e252baSAlexander Leidinger } 4950670e972SDmitry Chagin error = native_to_linux_timespec(<s, &ts); 4960670e972SDmitry Chagin if (error != 0) 4970670e972SDmitry Chagin return (error); 49819e252baSAlexander Leidinger error = copyout(<s, args->tp, sizeof lts); 49919e252baSAlexander Leidinger if (error != 0) 50019e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error); 50119e252baSAlexander Leidinger 50219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 50319e252baSAlexander Leidinger return (error); 50477424f41SJung-uk Kim } 50577424f41SJung-uk Kim 50677424f41SJung-uk Kim int 50777424f41SJung-uk Kim linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) 50877424f41SJung-uk Kim { 50977424f41SJung-uk Kim struct timespec *rmtp; 51077424f41SJung-uk Kim struct l_timespec lrqts, lrmts; 51177424f41SJung-uk Kim struct timespec rqts, rmts; 5125c2748d5SDmitry Chagin int error, error2; 51377424f41SJung-uk Kim 51419e252baSAlexander Leidinger LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp); 51519e252baSAlexander Leidinger 51677424f41SJung-uk Kim error = copyin(args->rqtp, &lrqts, sizeof lrqts); 51719e252baSAlexander Leidinger if (error != 0) { 51819e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); 51919e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 52077424f41SJung-uk Kim return (error); 52119e252baSAlexander Leidinger } 52277424f41SJung-uk Kim 52377424f41SJung-uk Kim if (args->rmtp != NULL) 52477424f41SJung-uk Kim rmtp = &rmts; 52577424f41SJung-uk Kim else 52677424f41SJung-uk Kim rmtp = NULL; 52777424f41SJung-uk Kim 52877424f41SJung-uk Kim error = linux_to_native_timespec(&rqts, &lrqts); 52919e252baSAlexander Leidinger if (error != 0) { 53019e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error); 53119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 53277424f41SJung-uk Kim return (error); 53319e252baSAlexander Leidinger } 53477424f41SJung-uk Kim error = kern_nanosleep(td, &rqts, rmtp); 5354cf66812SEric van Gyzen if (error == EINTR && args->rmtp != NULL) { 5360670e972SDmitry Chagin error2 = native_to_linux_timespec(&lrmts, rmtp); 5370670e972SDmitry Chagin if (error2 != 0) 5380670e972SDmitry Chagin return (error2); 5395c2748d5SDmitry Chagin error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 5405c2748d5SDmitry Chagin if (error2 != 0) { 54119e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, 5425c2748d5SDmitry Chagin error2); 5435c2748d5SDmitry Chagin LIN_SDT_PROBE1(time, linux_nanosleep, return, error2); 5445c2748d5SDmitry Chagin return (error2); 54577424f41SJung-uk Kim } 54619e252baSAlexander Leidinger } 54777424f41SJung-uk Kim 5485c2748d5SDmitry Chagin LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 5495c2748d5SDmitry Chagin return (error); 550ad2056f2SAlexander Leidinger } 551ad2056f2SAlexander Leidinger 552ad2056f2SAlexander Leidinger int 553ad2056f2SAlexander Leidinger linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args) 554ad2056f2SAlexander Leidinger { 555ad2056f2SAlexander Leidinger struct timespec *rmtp; 556ad2056f2SAlexander Leidinger struct l_timespec lrqts, lrmts; 557ad2056f2SAlexander Leidinger struct timespec rqts, rmts; 558f0f58384SDmitry Chagin int error, error2, flags; 559f0f58384SDmitry Chagin clockid_t clockid; 560ad2056f2SAlexander Leidinger 56119e252baSAlexander Leidinger LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which, 56219e252baSAlexander Leidinger args->flags, args->rqtp, args->rmtp); 563ad2056f2SAlexander Leidinger 564f0f58384SDmitry Chagin error = linux_to_native_timerflags(&flags, args->flags); 565f0f58384SDmitry Chagin if (error != 0) { 56619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, 56719e252baSAlexander Leidinger args->flags); 568f0f58384SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 569f0f58384SDmitry Chagin return (error); 57019e252baSAlexander Leidinger } 57119e252baSAlexander Leidinger 572f0f58384SDmitry Chagin error = linux_to_native_clockid(&clockid, args->which); 573f0f58384SDmitry Chagin if (error != 0) { 57419e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, 57519e252baSAlexander Leidinger args->which); 576f0f58384SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 577f0f58384SDmitry Chagin return (error); 57819e252baSAlexander Leidinger } 579ad2056f2SAlexander Leidinger 5805c2748d5SDmitry Chagin error = copyin(args->rqtp, &lrqts, sizeof(lrqts)); 58119e252baSAlexander Leidinger if (error != 0) { 58219e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, 58319e252baSAlexander Leidinger error); 58419e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 58577424f41SJung-uk Kim return (error); 58619e252baSAlexander Leidinger } 587ad2056f2SAlexander Leidinger 588ad2056f2SAlexander Leidinger if (args->rmtp != NULL) 589ad2056f2SAlexander Leidinger rmtp = &rmts; 590ad2056f2SAlexander Leidinger else 591ad2056f2SAlexander Leidinger rmtp = NULL; 592ad2056f2SAlexander Leidinger 59377424f41SJung-uk Kim error = linux_to_native_timespec(&rqts, &lrqts); 59419e252baSAlexander Leidinger if (error != 0) { 59519e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error, 59619e252baSAlexander Leidinger error); 59719e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 59877424f41SJung-uk Kim return (error); 59919e252baSAlexander Leidinger } 600f0f58384SDmitry Chagin error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp); 601f0f58384SDmitry Chagin if (error == EINTR && (flags & TIMER_ABSTIME) == 0 && 602f0f58384SDmitry Chagin args->rmtp != NULL) { 6030670e972SDmitry Chagin error2 = native_to_linux_timespec(&lrmts, rmtp); 6040670e972SDmitry Chagin if (error2 != 0) 6050670e972SDmitry Chagin return (error2); 6065c2748d5SDmitry Chagin error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 6075c2748d5SDmitry Chagin if (error2 != 0) { 6085c2748d5SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_nanosleep, 6095c2748d5SDmitry Chagin copyout_error, error2); 6105c2748d5SDmitry Chagin LIN_SDT_PROBE1(time, linux_clock_nanosleep, 6115c2748d5SDmitry Chagin return, error2); 6125c2748d5SDmitry Chagin return (error2); 6135c2748d5SDmitry Chagin } 6145c2748d5SDmitry Chagin } 6155c2748d5SDmitry Chagin 61619e252baSAlexander Leidinger LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 61777424f41SJung-uk Kim return (error); 61819e252baSAlexander Leidinger } 619