xref: /freebsd/sys/compat/linux/linux_time.c (revision f0f583842e4f1ad17d507053d11f9469ca8d96a1)
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(&ltp->it_interval, &ntp->it_interval);
161dd93b628SDmitry Chagin 	if (error == 0)
162dd93b628SDmitry Chagin 		error = native_to_linux_timespec(&ltp->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, &ltp->it_interval);
172dd93b628SDmitry Chagin 	if (error == 0)
173dd93b628SDmitry Chagin 		error = linux_to_native_timespec(&ntp->it_value, &ltp->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_MONOTONIC_RAW:
2112711aba9SDmitry Chagin 	case LINUX_CLOCK_BOOTTIME:
2122711aba9SDmitry Chagin 	case LINUX_CLOCK_REALTIME_ALARM:
2132711aba9SDmitry Chagin 	case LINUX_CLOCK_BOOTTIME_ALARM:
2142711aba9SDmitry Chagin 	case LINUX_CLOCK_SGI_CYCLE:
2152711aba9SDmitry Chagin 	case LINUX_CLOCK_TAI:
21619e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
21719e252baSAlexander Leidinger 		    unsupported_clockid, l);
21819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
21919e252baSAlexander Leidinger 		return (EINVAL);
22077424f41SJung-uk Kim 	default:
22119e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid,
22219e252baSAlexander Leidinger 		    unknown_clockid, l);
22319e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
22477424f41SJung-uk Kim 		return (EINVAL);
225ad2056f2SAlexander Leidinger 	}
226ad2056f2SAlexander Leidinger 
22719e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
22877424f41SJung-uk Kim 	return (0);
229ad2056f2SAlexander Leidinger }
230ad2056f2SAlexander Leidinger 
231ad2056f2SAlexander Leidinger int
232*f0f58384SDmitry Chagin linux_to_native_timerflags(int *nflags, int flags)
233*f0f58384SDmitry Chagin {
234*f0f58384SDmitry Chagin 
235*f0f58384SDmitry Chagin 	if (flags & ~LINUX_TIMER_ABSTIME)
236*f0f58384SDmitry Chagin 		return (EINVAL);
237*f0f58384SDmitry Chagin 	*nflags = 0;
238*f0f58384SDmitry Chagin 	if (flags & LINUX_TIMER_ABSTIME)
239*f0f58384SDmitry Chagin 		*nflags |= TIMER_ABSTIME;
240*f0f58384SDmitry Chagin 	return (0);
241*f0f58384SDmitry Chagin }
242*f0f58384SDmitry Chagin 
243*f0f58384SDmitry Chagin int
244ad2056f2SAlexander Leidinger linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
245ad2056f2SAlexander Leidinger {
246ad2056f2SAlexander Leidinger 	struct l_timespec lts;
247ad2056f2SAlexander Leidinger 	struct timespec tp;
2482711aba9SDmitry Chagin 	struct rusage ru;
2492711aba9SDmitry Chagin 	struct thread *targettd;
2502711aba9SDmitry Chagin 	struct proc *p;
2512711aba9SDmitry Chagin 	int error, clockwhich;
2522711aba9SDmitry Chagin 	clockid_t nwhich = 0;	/* XXX: GCC */
2532711aba9SDmitry Chagin 	pid_t pid;
2542711aba9SDmitry Chagin 	lwpid_t tid;
255ad2056f2SAlexander Leidinger 
25619e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
25719e252baSAlexander Leidinger 
258ad2056f2SAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
25919e252baSAlexander Leidinger 	if (error != 0) {
26019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
26119e252baSAlexander Leidinger 		    error);
26219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
26377424f41SJung-uk Kim 		return (error);
26419e252baSAlexander Leidinger 	}
2652711aba9SDmitry Chagin 
2662711aba9SDmitry Chagin 	switch (nwhich) {
2672711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
2682711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
2692711aba9SDmitry Chagin 		pid = LINUX_CPUCLOCK_ID(args->which);
2702711aba9SDmitry Chagin 		if (pid == 0) {
2712711aba9SDmitry Chagin 			p = td->td_proc;
2722711aba9SDmitry Chagin 			PROC_LOCK(p);
2732711aba9SDmitry Chagin 		} else {
2742711aba9SDmitry Chagin 			error = pget(pid, PGET_CANSEE, &p);
2752711aba9SDmitry Chagin 			if (error != 0)
2762711aba9SDmitry Chagin 				return (EINVAL);
2772711aba9SDmitry Chagin 		}
2782711aba9SDmitry Chagin 		switch (clockwhich) {
2792711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
2802711aba9SDmitry Chagin 			PROC_STATLOCK(p);
2812711aba9SDmitry Chagin 			calcru(p, &ru.ru_utime, &ru.ru_stime);
2822711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
2832711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2842711aba9SDmitry Chagin 			timevaladd(&ru.ru_utime, &ru.ru_stime);
2852711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
2862711aba9SDmitry Chagin 			break;
2872711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
2882711aba9SDmitry Chagin 			PROC_STATLOCK(p);
2892711aba9SDmitry Chagin 			calcru(p, &ru.ru_utime, &ru.ru_stime);
2902711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
2912711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2922711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
2932711aba9SDmitry Chagin 			break;
2942711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
2952711aba9SDmitry Chagin 			PROC_UNLOCK(p);
2962711aba9SDmitry Chagin 			error = kern_clock_getcpuclockid2(td, pid,
2972711aba9SDmitry Chagin 			    CPUCLOCK_WHICH_PID, &nwhich);
2982711aba9SDmitry Chagin 			if (error != 0)
2992711aba9SDmitry Chagin 				return (EINVAL);
300ad2056f2SAlexander Leidinger 			error = kern_clock_gettime(td, nwhich, &tp);
3012711aba9SDmitry Chagin 			break;
3022711aba9SDmitry Chagin 		default:
3032711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3042711aba9SDmitry Chagin 			return (EINVAL);
3052711aba9SDmitry Chagin 		}
3062711aba9SDmitry Chagin 
3072711aba9SDmitry Chagin 		break;
3082711aba9SDmitry Chagin 
3092711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
3102711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
3112711aba9SDmitry Chagin 		p = td->td_proc;
3122711aba9SDmitry Chagin 		tid = LINUX_CPUCLOCK_ID(args->which);
3132711aba9SDmitry Chagin 		if (tid == 0) {
3142711aba9SDmitry Chagin 			targettd = td;
3152711aba9SDmitry Chagin 			PROC_LOCK(p);
3162711aba9SDmitry Chagin 		} else {
3172711aba9SDmitry Chagin 			targettd = tdfind(tid, p->p_pid);
3182711aba9SDmitry Chagin 			if (targettd == NULL)
3192711aba9SDmitry Chagin 				return (EINVAL);
3202711aba9SDmitry Chagin 		}
3212711aba9SDmitry Chagin 		switch (clockwhich) {
3222711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
3232711aba9SDmitry Chagin 			PROC_STATLOCK(p);
3242711aba9SDmitry Chagin 			thread_lock(targettd);
3252711aba9SDmitry Chagin 			rufetchtd(targettd, &ru);
3262711aba9SDmitry Chagin 			thread_unlock(targettd);
3272711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
3282711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3292711aba9SDmitry Chagin 			timevaladd(&ru.ru_utime, &ru.ru_stime);
3302711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
3312711aba9SDmitry Chagin 			break;
3322711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
3332711aba9SDmitry Chagin 			PROC_STATLOCK(p);
3342711aba9SDmitry Chagin 			thread_lock(targettd);
3352711aba9SDmitry Chagin 			rufetchtd(targettd, &ru);
3362711aba9SDmitry Chagin 			thread_unlock(targettd);
3372711aba9SDmitry Chagin 			PROC_STATUNLOCK(p);
3382711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3392711aba9SDmitry Chagin 			TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &tp);
3402711aba9SDmitry Chagin 			break;
3412711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
3422711aba9SDmitry Chagin 			error = kern_clock_getcpuclockid2(td, tid,
3432711aba9SDmitry Chagin 			    CPUCLOCK_WHICH_TID, &nwhich);
3442711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3452711aba9SDmitry Chagin 			if (error != 0)
3462711aba9SDmitry Chagin 				return (EINVAL);
3472711aba9SDmitry Chagin 			error = kern_clock_gettime(td, nwhich, &tp);
3482711aba9SDmitry Chagin 			break;
3492711aba9SDmitry Chagin 		default:
3502711aba9SDmitry Chagin 			PROC_UNLOCK(p);
3512711aba9SDmitry Chagin 			return (EINVAL);
3522711aba9SDmitry Chagin 		}
3532711aba9SDmitry Chagin 		break;
3542711aba9SDmitry Chagin 
3552711aba9SDmitry Chagin 	default:
3562711aba9SDmitry Chagin 		error = kern_clock_gettime(td, nwhich, &tp);
3572711aba9SDmitry Chagin 		break;
3582711aba9SDmitry Chagin 	}
35919e252baSAlexander Leidinger 	if (error != 0) {
36019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
36119e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
36277424f41SJung-uk Kim 		return (error);
36319e252baSAlexander Leidinger 	}
3640670e972SDmitry Chagin 	error = native_to_linux_timespec(&lts, &tp);
3650670e972SDmitry Chagin 	if (error != 0)
3660670e972SDmitry Chagin 		return (error);
36719e252baSAlexander Leidinger 	error = copyout(&lts, args->tp, sizeof lts);
36819e252baSAlexander Leidinger 	if (error != 0)
36919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
37019e252baSAlexander Leidinger 
37119e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
37219e252baSAlexander Leidinger 	return (error);
373ad2056f2SAlexander Leidinger }
374ad2056f2SAlexander Leidinger 
375ad2056f2SAlexander Leidinger int
376ad2056f2SAlexander Leidinger linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
377ad2056f2SAlexander Leidinger {
378ad2056f2SAlexander Leidinger 	struct timespec ts;
379ad2056f2SAlexander Leidinger 	struct l_timespec lts;
380ad2056f2SAlexander Leidinger 	int error;
381ad2056f2SAlexander Leidinger 	clockid_t nwhich = 0;	/* XXX: GCC */
382ad2056f2SAlexander Leidinger 
38319e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
384ad2056f2SAlexander Leidinger 
38519e252baSAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
38619e252baSAlexander Leidinger 	if (error != 0) {
38719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
38819e252baSAlexander Leidinger 		    error);
38919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
39019e252baSAlexander Leidinger 		return (error);
39119e252baSAlexander Leidinger 	}
39219e252baSAlexander Leidinger 	error = copyin(args->tp, &lts, sizeof lts);
39319e252baSAlexander Leidinger 	if (error != 0) {
39419e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
39519e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
39619e252baSAlexander Leidinger 		return (error);
39719e252baSAlexander Leidinger 	}
39819e252baSAlexander Leidinger 	error = linux_to_native_timespec(&ts, &lts);
39919e252baSAlexander Leidinger 	if (error != 0) {
40019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
40119e252baSAlexander Leidinger 		    error);
40219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
40319e252baSAlexander Leidinger 		return (error);
40419e252baSAlexander Leidinger 	}
40519e252baSAlexander Leidinger 
40619e252baSAlexander Leidinger 	error = kern_clock_settime(td, nwhich, &ts);
40719e252baSAlexander Leidinger 	if (error != 0)
40819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
40919e252baSAlexander Leidinger 
41019e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
41119e252baSAlexander Leidinger 	return (error);
412ad2056f2SAlexander Leidinger }
413ad2056f2SAlexander Leidinger 
414ad2056f2SAlexander Leidinger int
415ad2056f2SAlexander Leidinger linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
416ad2056f2SAlexander Leidinger {
4172711aba9SDmitry Chagin 	struct proc *p;
418ad2056f2SAlexander Leidinger 	struct timespec ts;
419ad2056f2SAlexander Leidinger 	struct l_timespec lts;
4202711aba9SDmitry Chagin 	int error, clockwhich;
421ad2056f2SAlexander Leidinger 	clockid_t nwhich = 0;	/* XXX: GCC */
4222711aba9SDmitry Chagin 	pid_t pid;
4232711aba9SDmitry Chagin 	lwpid_t tid;
424ad2056f2SAlexander Leidinger 
42519e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
42619e252baSAlexander Leidinger 
427ad2056f2SAlexander Leidinger 	error = linux_to_native_clockid(&nwhich, args->which);
42819e252baSAlexander Leidinger 	if (error != 0) {
42919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
43019e252baSAlexander Leidinger 		    error);
43119e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
43277424f41SJung-uk Kim 		return (error);
43319e252baSAlexander Leidinger 	}
4342711aba9SDmitry Chagin 
4352711aba9SDmitry Chagin 	/*
4362711aba9SDmitry Chagin 	 * Check user supplied clock id in case of per-process
4372711aba9SDmitry Chagin 	 * or thread-specific cpu-time clock.
4382711aba9SDmitry Chagin 	 */
4392711aba9SDmitry Chagin 	switch (nwhich) {
4402711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
4412711aba9SDmitry Chagin 		tid = LINUX_CPUCLOCK_ID(args->which);
4422711aba9SDmitry Chagin 		if (tid != 0) {
4432711aba9SDmitry Chagin 			p = td->td_proc;
4442711aba9SDmitry Chagin 			if (tdfind(tid, p->p_pid) == NULL)
4452711aba9SDmitry Chagin 				return (ESRCH);
4462711aba9SDmitry Chagin 			PROC_UNLOCK(p);
4472711aba9SDmitry Chagin 		}
4482711aba9SDmitry Chagin 		break;
4492711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
4502711aba9SDmitry Chagin 		pid = LINUX_CPUCLOCK_ID(args->which);
4512711aba9SDmitry Chagin 		if (pid != 0) {
4522711aba9SDmitry Chagin 			error = pget(pid, PGET_CANSEE, &p);
4532711aba9SDmitry Chagin 			if (error != 0)
4542711aba9SDmitry Chagin 				return (EINVAL);
4552711aba9SDmitry Chagin 			PROC_UNLOCK(p);
4562711aba9SDmitry Chagin 		}
4572711aba9SDmitry Chagin 		break;
4582711aba9SDmitry Chagin 	}
4592711aba9SDmitry Chagin 
4602711aba9SDmitry Chagin 	if (args->tp == NULL) {
4612711aba9SDmitry Chagin 		LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
4622711aba9SDmitry Chagin 		LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
4632711aba9SDmitry Chagin 	  	return (0);
4642711aba9SDmitry Chagin 	}
4652711aba9SDmitry Chagin 
4662711aba9SDmitry Chagin 	switch (nwhich) {
4672711aba9SDmitry Chagin 	case CLOCK_THREAD_CPUTIME_ID:
4682711aba9SDmitry Chagin 	case CLOCK_PROCESS_CPUTIME_ID:
4692711aba9SDmitry Chagin 		clockwhich = LINUX_CPUCLOCK_WHICH(args->which);
4702711aba9SDmitry Chagin 		switch (clockwhich) {
4712711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_PROF:
4722711aba9SDmitry Chagin 			nwhich = CLOCK_PROF;
4732711aba9SDmitry Chagin 			break;
4742711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_VIRT:
4752711aba9SDmitry Chagin 			nwhich = CLOCK_VIRTUAL;
4762711aba9SDmitry Chagin 			break;
4772711aba9SDmitry Chagin 		case LINUX_CPUCLOCK_SCHED:
4782711aba9SDmitry Chagin 			break;
4792711aba9SDmitry Chagin 		default:
4802711aba9SDmitry Chagin 			return (EINVAL);
4812711aba9SDmitry Chagin 		}
4822711aba9SDmitry Chagin 		break;
4832711aba9SDmitry Chagin 
4842711aba9SDmitry Chagin 	default:
4852711aba9SDmitry Chagin 		break;
4862711aba9SDmitry Chagin 	}
487ad2056f2SAlexander Leidinger 	error = kern_clock_getres(td, nwhich, &ts);
48819e252baSAlexander Leidinger 	if (error != 0) {
48919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
49019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
49177424f41SJung-uk Kim 		return (error);
49219e252baSAlexander Leidinger 	}
4930670e972SDmitry Chagin 	error = native_to_linux_timespec(&lts, &ts);
4940670e972SDmitry Chagin 	if (error != 0)
4950670e972SDmitry Chagin 		return (error);
49619e252baSAlexander Leidinger 	error = copyout(&lts, args->tp, sizeof lts);
49719e252baSAlexander Leidinger 	if (error != 0)
49819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
49919e252baSAlexander Leidinger 
50019e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
50119e252baSAlexander Leidinger 	return (error);
50277424f41SJung-uk Kim }
50377424f41SJung-uk Kim 
50477424f41SJung-uk Kim int
50577424f41SJung-uk Kim linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
50677424f41SJung-uk Kim {
50777424f41SJung-uk Kim 	struct timespec *rmtp;
50877424f41SJung-uk Kim 	struct l_timespec lrqts, lrmts;
50977424f41SJung-uk Kim 	struct timespec rqts, rmts;
5105c2748d5SDmitry Chagin 	int error, error2;
51177424f41SJung-uk Kim 
51219e252baSAlexander Leidinger 	LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
51319e252baSAlexander Leidinger 
51477424f41SJung-uk Kim 	error = copyin(args->rqtp, &lrqts, sizeof lrqts);
51519e252baSAlexander Leidinger 	if (error != 0) {
51619e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
51719e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
51877424f41SJung-uk Kim 		return (error);
51919e252baSAlexander Leidinger 	}
52077424f41SJung-uk Kim 
52177424f41SJung-uk Kim 	if (args->rmtp != NULL)
52277424f41SJung-uk Kim 		rmtp = &rmts;
52377424f41SJung-uk Kim 	else
52477424f41SJung-uk Kim 		rmtp = NULL;
52577424f41SJung-uk Kim 
52677424f41SJung-uk Kim 	error = linux_to_native_timespec(&rqts, &lrqts);
52719e252baSAlexander Leidinger 	if (error != 0) {
52819e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
52919e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
53077424f41SJung-uk Kim 		return (error);
53119e252baSAlexander Leidinger 	}
53277424f41SJung-uk Kim 	error = kern_nanosleep(td, &rqts, rmtp);
5334cf66812SEric van Gyzen 	if (error == EINTR && args->rmtp != NULL) {
5340670e972SDmitry Chagin 		error2 = native_to_linux_timespec(&lrmts, rmtp);
5350670e972SDmitry Chagin 		if (error2 != 0)
5360670e972SDmitry Chagin 			return (error2);
5375c2748d5SDmitry Chagin 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
5385c2748d5SDmitry Chagin 		if (error2 != 0) {
53919e252baSAlexander Leidinger 			LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
5405c2748d5SDmitry Chagin 			    error2);
5415c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_nanosleep, return, error2);
5425c2748d5SDmitry Chagin 			return (error2);
54377424f41SJung-uk Kim 		}
54419e252baSAlexander Leidinger 	}
54577424f41SJung-uk Kim 
5465c2748d5SDmitry Chagin 	LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
5475c2748d5SDmitry Chagin 	return (error);
548ad2056f2SAlexander Leidinger }
549ad2056f2SAlexander Leidinger 
550ad2056f2SAlexander Leidinger int
551ad2056f2SAlexander Leidinger linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
552ad2056f2SAlexander Leidinger {
553ad2056f2SAlexander Leidinger 	struct timespec *rmtp;
554ad2056f2SAlexander Leidinger 	struct l_timespec lrqts, lrmts;
555ad2056f2SAlexander Leidinger 	struct timespec rqts, rmts;
556*f0f58384SDmitry Chagin 	int error, error2, flags;
557*f0f58384SDmitry Chagin 	clockid_t clockid;
558ad2056f2SAlexander Leidinger 
55919e252baSAlexander Leidinger 	LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
56019e252baSAlexander Leidinger 	    args->flags, args->rqtp, args->rmtp);
561ad2056f2SAlexander Leidinger 
562*f0f58384SDmitry Chagin 	error = linux_to_native_timerflags(&flags, args->flags);
563*f0f58384SDmitry Chagin 	if (error != 0) {
56419e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
56519e252baSAlexander Leidinger 		    args->flags);
566*f0f58384SDmitry Chagin 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
567*f0f58384SDmitry Chagin 		return (error);
56819e252baSAlexander Leidinger 	}
56919e252baSAlexander Leidinger 
570*f0f58384SDmitry Chagin 	error = linux_to_native_clockid(&clockid, args->which);
571*f0f58384SDmitry Chagin 	if (error != 0) {
57219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
57319e252baSAlexander Leidinger 		    args->which);
574*f0f58384SDmitry Chagin 		LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
575*f0f58384SDmitry Chagin 		return (error);
57619e252baSAlexander Leidinger 	}
577ad2056f2SAlexander Leidinger 
5785c2748d5SDmitry Chagin 	error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
57919e252baSAlexander Leidinger 	if (error != 0) {
58019e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
58119e252baSAlexander Leidinger 		    error);
58219e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
58377424f41SJung-uk Kim 		return (error);
58419e252baSAlexander Leidinger 	}
585ad2056f2SAlexander Leidinger 
586ad2056f2SAlexander Leidinger 	if (args->rmtp != NULL)
587ad2056f2SAlexander Leidinger 		rmtp = &rmts;
588ad2056f2SAlexander Leidinger 	else
589ad2056f2SAlexander Leidinger 		rmtp = NULL;
590ad2056f2SAlexander Leidinger 
59177424f41SJung-uk Kim 	error = linux_to_native_timespec(&rqts, &lrqts);
59219e252baSAlexander Leidinger 	if (error != 0) {
59319e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
59419e252baSAlexander Leidinger 		    error);
59519e252baSAlexander Leidinger 		LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
59677424f41SJung-uk Kim 		return (error);
59719e252baSAlexander Leidinger 	}
598*f0f58384SDmitry Chagin 	error = kern_clock_nanosleep(td, clockid, flags, &rqts, rmtp);
599*f0f58384SDmitry Chagin 	if (error == EINTR && (flags & TIMER_ABSTIME) == 0 &&
600*f0f58384SDmitry Chagin 	    args->rmtp != NULL) {
6010670e972SDmitry Chagin 		error2 = native_to_linux_timespec(&lrmts, rmtp);
6020670e972SDmitry Chagin 		if (error2 != 0)
6030670e972SDmitry Chagin 			return (error2);
6045c2748d5SDmitry Chagin 		error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
6055c2748d5SDmitry Chagin 		if (error2 != 0) {
6065c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
6075c2748d5SDmitry Chagin 			    copyout_error, error2);
6085c2748d5SDmitry Chagin 			LIN_SDT_PROBE1(time, linux_clock_nanosleep,
6095c2748d5SDmitry Chagin 			    return, error2);
6105c2748d5SDmitry Chagin 			return (error2);
6115c2748d5SDmitry Chagin 		}
6125c2748d5SDmitry Chagin 	}
6135c2748d5SDmitry Chagin 
61419e252baSAlexander Leidinger 	LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
61577424f41SJung-uk Kim 	return (error);
61619e252baSAlexander Leidinger }
617