xref: /freebsd/sys/compat/linux/linux_time.c (revision 4cf66812ea5fd231c98474cd9759a632043a6a37)
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
1280670e972SDmitry Chagin 	if (ntp->tv_sec > INT_MAX &&
1290670e972SDmitry Chagin 	    sizeof(ltp->tv_sec) != sizeof(ntp->tv_sec))
1300670e972SDmitry Chagin 		return (EOVERFLOW);
1310670e972SDmitry Chagin #endif
132ad2056f2SAlexander Leidinger 	ltp->tv_sec = ntp->tv_sec;
133ad2056f2SAlexander Leidinger 	ltp->tv_nsec = ntp->tv_nsec;
13419e252baSAlexander Leidinger 
13519e252baSAlexander Leidinger 	LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
1360670e972SDmitry Chagin 	return (0);
137ad2056f2SAlexander Leidinger }
138ad2056f2SAlexander Leidinger 
13968098228SDmitry Chagin int
140ad2056f2SAlexander Leidinger linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
141ad2056f2SAlexander Leidinger {
14219e252baSAlexander Leidinger 
14319e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp);
14419e252baSAlexander Leidinger 
145bd597911SDmitry Chagin 	if (ltp->tv_sec < 0 || (l_ulong)ltp->tv_nsec > 999999999L) {
14619e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL);
14777424f41SJung-uk Kim 		return (EINVAL);
14819e252baSAlexander Leidinger 	}
149ad2056f2SAlexander Leidinger 	ntp->tv_sec = ltp->tv_sec;
150ad2056f2SAlexander Leidinger 	ntp->tv_nsec = ltp->tv_nsec;
15177424f41SJung-uk Kim 
15219e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0);
15377424f41SJung-uk Kim 	return (0);
154ad2056f2SAlexander Leidinger }
155ad2056f2SAlexander Leidinger 
15616ac71bcSDmitry Chagin int
157dd93b628SDmitry Chagin native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp)
158dd93b628SDmitry Chagin {
159dd93b628SDmitry Chagin 	int error;
160dd93b628SDmitry Chagin 
161dd93b628SDmitry Chagin 	error = native_to_linux_timespec(&ltp->it_interval, &ntp->it_interval);
162dd93b628SDmitry Chagin 	if (error == 0)
163dd93b628SDmitry Chagin 		error = native_to_linux_timespec(&ltp->it_value, &ntp->it_interval);
164dd93b628SDmitry Chagin 	return (error);
165dd93b628SDmitry Chagin }
166dd93b628SDmitry Chagin 
167dd93b628SDmitry Chagin int
168dd93b628SDmitry Chagin linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp)
169dd93b628SDmitry Chagin {
170dd93b628SDmitry Chagin 	int error;
171dd93b628SDmitry Chagin 
172dd93b628SDmitry Chagin 	error = linux_to_native_timespec(&ntp->it_interval, &ltp->it_interval);
173dd93b628SDmitry Chagin 	if (error == 0)
174dd93b628SDmitry Chagin 		error = linux_to_native_timespec(&ntp->it_value, &ltp->it_value);
175dd93b628SDmitry Chagin 	return (error);
176dd93b628SDmitry Chagin }
177dd93b628SDmitry Chagin 
178dd93b628SDmitry Chagin int
179ad2056f2SAlexander Leidinger linux_to_native_clockid(clockid_t *n, clockid_t l)
180ad2056f2SAlexander Leidinger {
18119e252baSAlexander Leidinger 
18219e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
18319e252baSAlexander Leidinger 
1842711aba9SDmitry Chagin 	if (l < 0) {
1852711aba9SDmitry Chagin 		/* cpu-clock */
1862711aba9SDmitry Chagin 		if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
1872711aba9SDmitry Chagin 			return (EINVAL);
1882711aba9SDmitry Chagin 		if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
1892711aba9SDmitry Chagin 			return (EINVAL);
1902711aba9SDmitry Chagin 
1912711aba9SDmitry Chagin 		if (LINUX_CPUCLOCK_PERTHREAD(l))
1922711aba9SDmitry Chagin 			*n = CLOCK_THREAD_CPUTIME_ID;
1932711aba9SDmitry Chagin 		else
1942711aba9SDmitry Chagin 			*n = CLOCK_PROCESS_CPUTIME_ID;
1952711aba9SDmitry Chagin 		return (0);
1962711aba9SDmitry Chagin 	}
1972711aba9SDmitry Chagin 
198ad2056f2SAlexander Leidinger 	switch (l) {
199ad2056f2SAlexander Leidinger 	case LINUX_CLOCK_REALTIME:
200ad2056f2SAlexander Leidinger 		*n = CLOCK_REALTIME;
201ad2056f2SAlexander Leidinger 		break;
202ad2056f2SAlexander Leidinger 	case LINUX_CLOCK_MONOTONIC:
203ad2056f2SAlexander Leidinger 		*n = CLOCK_MONOTONIC;
204ad2056f2SAlexander Leidinger 		break;
2052711aba9SDmitry Chagin 	case LINUX_CLOCK_REALTIME_COARSE:
2062711aba9SDmitry Chagin 		*n = CLOCK_REALTIME_FAST;
2072711aba9SDmitry Chagin 		break;
2082711aba9SDmitry Chagin 	case LINUX_CLOCK_MONOTONIC_COARSE:
2092711aba9SDmitry Chagin 		*n = CLOCK_MONOTONIC_FAST;
2102711aba9SDmitry Chagin 		break;
2112711aba9SDmitry Chagin 	case LINUX_CLOCK_MONOTONIC_RAW:
2122711aba9SDmitry Chagin 	case LINUX_CLOCK_BOOTTIME:
2132711aba9SDmitry Chagin 	case LINUX_CLOCK_REALTIME_ALARM:
2142711aba9SDmitry Chagin 	case LINUX_CLOCK_BOOTTIME_ALARM:
2152711aba9SDmitry Chagin 	case LINUX_CLOCK_SGI_CYCLE:
2162711aba9SDmitry Chagin 	case LINUX_CLOCK_TAI:
21719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
21819e252baSAlexander Leidinger 		    unsupported_clockid, l);
21919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
22019e252baSAlexander Leidinger 		return (EINVAL);
22177424f41SJung-uk Kim 	default:
22219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
22319e252baSAlexander Leidinger 		    unknown_clockid, l);
22419e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
22577424f41SJung-uk Kim 		return (EINVAL);
226ad2056f2SAlexander Leidinger 	}
227ad2056f2SAlexander Leidinger 
22819e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
22977424f41SJung-uk Kim 	return (0);
230ad2056f2SAlexander Leidinger }
231ad2056f2SAlexander Leidinger 
232ad2056f2SAlexander Leidinger int
233ad2056f2SAlexander Leidinger linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
234ad2056f2SAlexander Leidinger {
235ad2056f2SAlexander Leidinger 	struct l_timespec lts;
236ad2056f2SAlexander Leidinger 	struct timespec tp;
2372711aba9SDmitry Chagin 	struct rusage ru;
2382711aba9SDmitry Chagin 	struct thread *targettd;
2392711aba9SDmitry Chagin 	struct proc *p;
2402711aba9SDmitry Chagin 	int error, clockwhich;
2412711aba9SDmitry Chagin 	clockid_t nwhich = 0;	/* XXX: GCC */
2422711aba9SDmitry Chagin 	pid_t pid;
2432711aba9SDmitry Chagin 	lwpid_t tid;
244ad2056f2SAlexander Leidinger 
24519e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
24619e252baSAlexander Leidinger 
247ad2056f2SAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
24819e252baSAlexander Leidinger 	if (error != 0) {
24919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
25019e252baSAlexander Leidinger 		    error);
25119e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
25277424f41SJung-uk Kim 		return (error);
25319e252baSAlexander Leidinger 	}
2542711aba9SDmitry Chagin 
2552711aba9SDmitry Chagin 	switch (nwhich) {
2562711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
2572711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
2582711aba9SDmitry Chagin 		pid = LINUX_CPUCLOCK_ID(args->which);
2592711aba9SDmitry Chagin 		if (pid == 0) {
2602711aba9SDmitry Chagin 			p = td->td_proc;
2612711aba9SDmitry Chagin 			PROC_LOCK(p);
2622711aba9SDmitry Chagin 		} else {
2632711aba9SDmitry Chagin 			error = pget(pid, PGET_CANSEE, &p);
2642711aba9SDmitry Chagin 			if (error != 0)
2652711aba9SDmitry Chagin 				return (EINVAL);
2662711aba9SDmitry Chagin 		}
2672711aba9SDmitry Chagin 		switch (clockwhich) {
2682711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
2692711aba9SDmitry Chagin 			PROC_STATLOCK(p);
2702711aba9SDmitry Chagin 			calcru(p, &ru.ru_utime, &ru.ru_stime);
2712711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
2722711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2732711aba9SDmitry Chagin 			timevaladd(&ru.ru_utime, &ru.ru_stime);
2742711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
2752711aba9SDmitry Chagin 			break;
2762711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
2772711aba9SDmitry Chagin 			PROC_STATLOCK(p);
2782711aba9SDmitry Chagin 			calcru(p, &ru.ru_utime, &ru.ru_stime);
2792711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
2802711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2812711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
2822711aba9SDmitry Chagin 			break;
2832711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
2842711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2852711aba9SDmitry Chagin 			error = kern_clock_getcpuclockid2(td, pid,
2862711aba9SDmitry Chagin 			    CPUCLOCK_WHICH_PID, &nwhich);
2872711aba9SDmitry Chagin 			if (error != 0)
2882711aba9SDmitry Chagin 				return (EINVAL);
289ad2056f2SAlexander Leidinger 			error = kern_clock_gettime(td, nwhich, &tp);
2902711aba9SDmitry Chagin 			break;
2912711aba9SDmitry Chagin 		default:
2922711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2932711aba9SDmitry Chagin 			return (EINVAL);
2942711aba9SDmitry Chagin 		}
2952711aba9SDmitry Chagin 
2962711aba9SDmitry Chagin 		break;
2972711aba9SDmitry Chagin 
2982711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
2992711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
3002711aba9SDmitry Chagin 		p = td->td_proc;
3012711aba9SDmitry Chagin 		tid = LINUX_CPUCLOCK_ID(args->which);
3022711aba9SDmitry Chagin 		if (tid == 0) {
3032711aba9SDmitry Chagin 			targettd = td;
3042711aba9SDmitry Chagin 			PROC_LOCK(p);
3052711aba9SDmitry Chagin 		} else {
3062711aba9SDmitry Chagin 			targettd = tdfind(tid, p->p_pid);
3072711aba9SDmitry Chagin 			if (targettd == NULL)
3082711aba9SDmitry Chagin 				return (EINVAL);
3092711aba9SDmitry Chagin 		}
3102711aba9SDmitry Chagin 		switch (clockwhich) {
3112711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
3122711aba9SDmitry Chagin 			PROC_STATLOCK(p);
3132711aba9SDmitry Chagin 			thread_lock(targettd);
3142711aba9SDmitry Chagin 			rufetchtd(targettd, &ru);
3152711aba9SDmitry Chagin 			thread_unlock(targettd);
3162711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
3172711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3182711aba9SDmitry Chagin 			timevaladd(&ru.ru_utime, &ru.ru_stime);
3192711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
3202711aba9SDmitry Chagin 			break;
3212711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
3222711aba9SDmitry Chagin 			PROC_STATLOCK(p);
3232711aba9SDmitry Chagin 			thread_lock(targettd);
3242711aba9SDmitry Chagin 			rufetchtd(targettd, &ru);
3252711aba9SDmitry Chagin 			thread_unlock(targettd);
3262711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
3272711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3282711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
3292711aba9SDmitry Chagin 			break;
3302711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
3312711aba9SDmitry Chagin 			error = kern_clock_getcpuclockid2(td, tid,
3322711aba9SDmitry Chagin 			    CPUCLOCK_WHICH_TID, &nwhich);
3332711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3342711aba9SDmitry Chagin 			if (error != 0)
3352711aba9SDmitry Chagin 				return (EINVAL);
3362711aba9SDmitry Chagin 			error = kern_clock_gettime(td, nwhich, &tp);
3372711aba9SDmitry Chagin 			break;
3382711aba9SDmitry Chagin 		default:
3392711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3402711aba9SDmitry Chagin 			return (EINVAL);
3412711aba9SDmitry Chagin 		}
3422711aba9SDmitry Chagin 		break;
3432711aba9SDmitry Chagin 
3442711aba9SDmitry Chagin 	default:
3452711aba9SDmitry Chagin 		error = kern_clock_gettime(td, nwhich, &tp);
3462711aba9SDmitry Chagin 		break;
3472711aba9SDmitry Chagin 	}
34819e252baSAlexander Leidinger 	if (error != 0) {
34919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
35019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
35177424f41SJung-uk Kim 		return (error);
35219e252baSAlexander Leidinger 	}
3530670e972SDmitry Chagin 	error = native_to_linux_timespec(&lts, &tp);
3540670e972SDmitry Chagin 	if (error != 0)
3550670e972SDmitry Chagin 		return (error);
35619e252baSAlexander Leidinger 	error = copyout(&lts, args->tp, sizeof lts);
35719e252baSAlexander Leidinger 	if (error != 0)
35819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
35919e252baSAlexander Leidinger 
36019e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
36119e252baSAlexander Leidinger 	return (error);
362ad2056f2SAlexander Leidinger }
363ad2056f2SAlexander Leidinger 
364ad2056f2SAlexander Leidinger int
365ad2056f2SAlexander Leidinger linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
366ad2056f2SAlexander Leidinger {
367ad2056f2SAlexander Leidinger 	struct timespec ts;
368ad2056f2SAlexander Leidinger 	struct l_timespec lts;
369ad2056f2SAlexander Leidinger 	int error;
370ad2056f2SAlexander Leidinger 	clockid_t nwhich = 0;	/* XXX: GCC */
371ad2056f2SAlexander Leidinger 
37219e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
373ad2056f2SAlexander Leidinger 
37419e252baSAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
37519e252baSAlexander Leidinger 	if (error != 0) {
37619e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
37719e252baSAlexander Leidinger 		    error);
37819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
37919e252baSAlexander Leidinger 		return (error);
38019e252baSAlexander Leidinger 	}
38119e252baSAlexander Leidinger 	error = copyin(args->tp, &lts, sizeof lts);
38219e252baSAlexander Leidinger 	if (error != 0) {
38319e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
38419e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
38519e252baSAlexander Leidinger 		return (error);
38619e252baSAlexander Leidinger 	}
38719e252baSAlexander Leidinger 	error = linux_to_native_timespec(&ts, &lts);
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 
39519e252baSAlexander Leidinger 	error = kern_clock_settime(td, nwhich, &ts);
39619e252baSAlexander Leidinger 	if (error != 0)
39719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
39819e252baSAlexander Leidinger 
39919e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
40019e252baSAlexander Leidinger 	return (error);
401ad2056f2SAlexander Leidinger }
402ad2056f2SAlexander Leidinger 
403ad2056f2SAlexander Leidinger int
404ad2056f2SAlexander Leidinger linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
405ad2056f2SAlexander Leidinger {
4062711aba9SDmitry Chagin 	struct proc *p;
407ad2056f2SAlexander Leidinger 	struct timespec ts;
408ad2056f2SAlexander Leidinger 	struct l_timespec lts;
4092711aba9SDmitry Chagin 	int error, clockwhich;
410ad2056f2SAlexander Leidinger 	clockid_t nwhich = 0;	/* XXX: GCC */
4112711aba9SDmitry Chagin 	pid_t pid;
4122711aba9SDmitry Chagin 	lwpid_t tid;
413ad2056f2SAlexander Leidinger 
41419e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
41519e252baSAlexander Leidinger 
416ad2056f2SAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
41719e252baSAlexander Leidinger 	if (error != 0) {
41819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
41919e252baSAlexander Leidinger 		    error);
42019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
42177424f41SJung-uk Kim 		return (error);
42219e252baSAlexander Leidinger 	}
4232711aba9SDmitry Chagin 
4242711aba9SDmitry Chagin 	/*
4252711aba9SDmitry Chagin 	 * Check user supplied clock id in case of per-process
4262711aba9SDmitry Chagin 	 * or thread-specific cpu-time clock.
4272711aba9SDmitry Chagin 	 */
4282711aba9SDmitry Chagin 	switch (nwhich) {
4292711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
4302711aba9SDmitry Chagin 		tid = LINUX_CPUCLOCK_ID(args->which);
4312711aba9SDmitry Chagin 		if (tid != 0) {
4322711aba9SDmitry Chagin 			p = td->td_proc;
4332711aba9SDmitry Chagin 			if (tdfind(tid, p->p_pid) == NULL)
4342711aba9SDmitry Chagin 				return (ESRCH);
4352711aba9SDmitry Chagin 			PROC_UNLOCK(p);
4362711aba9SDmitry Chagin 		}
4372711aba9SDmitry Chagin 		break;
4382711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
4392711aba9SDmitry Chagin 		pid = LINUX_CPUCLOCK_ID(args->which);
4402711aba9SDmitry Chagin 		if (pid != 0) {
4412711aba9SDmitry Chagin 			error = pget(pid, PGET_CANSEE, &p);
4422711aba9SDmitry Chagin 			if (error != 0)
4432711aba9SDmitry Chagin 				return (EINVAL);
4442711aba9SDmitry Chagin 			PROC_UNLOCK(p);
4452711aba9SDmitry Chagin 		}
4462711aba9SDmitry Chagin 		break;
4472711aba9SDmitry Chagin 	}
4482711aba9SDmitry Chagin 
4492711aba9SDmitry Chagin 	if (args->tp == NULL) {
4502711aba9SDmitry Chagin 		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
4512711aba9SDmitry Chagin 		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
4522711aba9SDmitry Chagin 	  	return (0);
4532711aba9SDmitry Chagin 	}
4542711aba9SDmitry Chagin 
4552711aba9SDmitry Chagin 	switch (nwhich) {
4562711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
4572711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
4582711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
4592711aba9SDmitry Chagin 		switch (clockwhich) {
4602711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
4612711aba9SDmitry Chagin 			nwhich = CLOCK_PROF;
4622711aba9SDmitry Chagin 			break;
4632711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
4642711aba9SDmitry Chagin 			nwhich = CLOCK_VIRTUAL;
4652711aba9SDmitry Chagin 			break;
4662711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
4672711aba9SDmitry Chagin 			break;
4682711aba9SDmitry Chagin 		default:
4692711aba9SDmitry Chagin 			return (EINVAL);
4702711aba9SDmitry Chagin 		}
4712711aba9SDmitry Chagin 		break;
4722711aba9SDmitry Chagin 
4732711aba9SDmitry Chagin 	default:
4742711aba9SDmitry Chagin 		break;
4752711aba9SDmitry Chagin 	}
476ad2056f2SAlexander Leidinger 	error = kern_clock_getres(td, nwhich, &ts);
47719e252baSAlexander Leidinger 	if (error != 0) {
47819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
47919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
48077424f41SJung-uk Kim 		return (error);
48119e252baSAlexander Leidinger 	}
4820670e972SDmitry Chagin 	error = native_to_linux_timespec(&lts, &ts);
4830670e972SDmitry Chagin 	if (error != 0)
4840670e972SDmitry Chagin 		return (error);
48519e252baSAlexander Leidinger 	error = copyout(&lts, args->tp, sizeof lts);
48619e252baSAlexander Leidinger 	if (error != 0)
48719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
48819e252baSAlexander Leidinger 
48919e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
49019e252baSAlexander Leidinger 	return (error);
49177424f41SJung-uk Kim }
49277424f41SJung-uk Kim 
49377424f41SJung-uk Kim int
49477424f41SJung-uk Kim linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
49577424f41SJung-uk Kim {
49677424f41SJung-uk Kim 	struct timespec *rmtp;
49777424f41SJung-uk Kim 	struct l_timespec lrqts, lrmts;
49877424f41SJung-uk Kim 	struct timespec rqts, rmts;
4995c2748d5SDmitry Chagin 	int error, error2;
50077424f41SJung-uk Kim 
50119e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
50219e252baSAlexander Leidinger 
50377424f41SJung-uk Kim 	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
50419e252baSAlexander Leidinger 	if (error != 0) {
50519e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
50619e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
50777424f41SJung-uk Kim 		return (error);
50819e252baSAlexander Leidinger 	}
50977424f41SJung-uk Kim 
51077424f41SJung-uk Kim 	if (args->rmtp != NULL)
51177424f41SJung-uk Kim 		rmtp = &rmts;
51277424f41SJung-uk Kim 	else
51377424f41SJung-uk Kim 		rmtp = NULL;
51477424f41SJung-uk Kim 
51577424f41SJung-uk Kim 	error = linux_to_native_timespec(&rqts, &lrqts);
51619e252baSAlexander Leidinger 	if (error != 0) {
51719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
51819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
51977424f41SJung-uk Kim 		return (error);
52019e252baSAlexander Leidinger 	}
52177424f41SJung-uk Kim 	error = kern_nanosleep(td, &rqts, rmtp);
522*4cf66812SEric van Gyzen 	if (error == EINTR && args->rmtp != NULL) {
5230670e972SDmitry Chagin 		error2 = native_to_linux_timespec(&lrmts, rmtp);
5240670e972SDmitry Chagin 		if (error2 != 0)
5250670e972SDmitry Chagin 			return (error2);
5265c2748d5SDmitry Chagin 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
5275c2748d5SDmitry Chagin 		if (error2 != 0) {
52819e252baSAlexander Leidinger 			LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
5295c2748d5SDmitry Chagin 			    error2);
5305c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_nanosleep, return, error2);
5315c2748d5SDmitry Chagin 			return (error2);
53277424f41SJung-uk Kim 		}
53319e252baSAlexander Leidinger 	}
53477424f41SJung-uk Kim 
5355c2748d5SDmitry Chagin 	LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
5365c2748d5SDmitry Chagin 	return (error);
537ad2056f2SAlexander Leidinger }
538ad2056f2SAlexander Leidinger 
539ad2056f2SAlexander Leidinger int
540ad2056f2SAlexander Leidinger linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
541ad2056f2SAlexander Leidinger {
542ad2056f2SAlexander Leidinger 	struct timespec *rmtp;
543ad2056f2SAlexander Leidinger 	struct l_timespec lrqts, lrmts;
544ad2056f2SAlexander Leidinger 	struct timespec rqts, rmts;
5455c2748d5SDmitry Chagin 	int error, error2;
546ad2056f2SAlexander Leidinger 
54719e252baSAlexander Leidinger 	LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
54819e252baSAlexander Leidinger 	    args->flags, args->rqtp, args->rmtp);
549ad2056f2SAlexander Leidinger 
55019e252baSAlexander Leidinger 	if (args->flags != 0) {
55119e252baSAlexander Leidinger 		/* XXX deal with TIMER_ABSTIME */
55219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
55319e252baSAlexander Leidinger 		    args->flags);
55419e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
55519e252baSAlexander Leidinger 		return (EINVAL);	/* XXX deal with TIMER_ABSTIME */
55619e252baSAlexander Leidinger 	}
55719e252baSAlexander Leidinger 
55819e252baSAlexander Leidinger 	if (args->which != LINUX_CLOCK_REALTIME) {
55919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
56019e252baSAlexander Leidinger 		    args->which);
56119e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
56277424f41SJung-uk Kim 		return (EINVAL);
56319e252baSAlexander Leidinger 	}
564ad2056f2SAlexander Leidinger 
5655c2748d5SDmitry Chagin 	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
56619e252baSAlexander Leidinger 	if (error != 0) {
56719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
56819e252baSAlexander Leidinger 		    error);
56919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
57077424f41SJung-uk Kim 		return (error);
57119e252baSAlexander Leidinger 	}
572ad2056f2SAlexander Leidinger 
573ad2056f2SAlexander Leidinger 	if (args->rmtp != NULL)
574ad2056f2SAlexander Leidinger 		rmtp = &rmts;
575ad2056f2SAlexander Leidinger 	else
576ad2056f2SAlexander Leidinger 		rmtp = NULL;
577ad2056f2SAlexander Leidinger 
57877424f41SJung-uk Kim 	error = linux_to_native_timespec(&rqts, &lrqts);
57919e252baSAlexander Leidinger 	if (error != 0) {
58019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
58119e252baSAlexander Leidinger 		    error);
58219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
58377424f41SJung-uk Kim 		return (error);
58419e252baSAlexander Leidinger 	}
585ad2056f2SAlexander Leidinger 	error = kern_nanosleep(td, &rqts, rmtp);
586*4cf66812SEric van Gyzen 	if (error == EINTR && args->rmtp != NULL) {
5875c2748d5SDmitry Chagin 		/* XXX. Not for TIMER_ABSTIME */
5880670e972SDmitry Chagin 		error2 = native_to_linux_timespec(&lrmts, rmtp);
5890670e972SDmitry Chagin 		if (error2 != 0)
5900670e972SDmitry Chagin 			return (error2);
5915c2748d5SDmitry Chagin 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
5925c2748d5SDmitry Chagin 		if (error2 != 0) {
5935c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
5945c2748d5SDmitry Chagin 			    copyout_error, error2);
5955c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
5965c2748d5SDmitry Chagin 			    return, error2);
5975c2748d5SDmitry Chagin 			return (error2);
5985c2748d5SDmitry Chagin 		}
5995c2748d5SDmitry Chagin 	}
6005c2748d5SDmitry Chagin 
60119e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
60277424f41SJung-uk Kim 	return (error);
60319e252baSAlexander Leidinger }
604