1 /* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD
6 * Copyright (c) 2001 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Emmanuel Dreyfus.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
40 #include "opt_compat.h"
42 #include <sys/param.h>
43 #include <sys/kernel.h>
45 #include <sys/ucred.h>
46 #include <sys/limits.h>
47 #include <sys/mount.h>
48 #include <sys/mutex.h>
49 #include <sys/resourcevar.h>
51 #include <sys/signal.h>
52 #include <sys/stdint.h>
53 #include <sys/syscallsubr.h>
54 #include <sys/sysproto.h>
56 #include <sys/systm.h>
60 #include <machine/../linux32/linux.h>
61 #include <machine/../linux32/linux32_proto.h>
63 #include <machine/../linux/linux.h>
64 #include <machine/../linux/linux_proto.h>
67 #include <compat/linux/linux_dtrace.h>
68 #include <compat/linux/linux_misc.h>
69 #include <compat/linux/linux_timer.h>
70 #include <compat/linux/linux_util.h>
73 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
76 * DTrace probes in this module.
78 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
80 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
82 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_gettime, conversion_error, "int");
83 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
84 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
85 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
86 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, gettime_error, "int");
87 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime64, copyout_error, "int");
89 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
90 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, settime_error, "int");
91 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_settime, conversion_error, "int");
92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
93 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
94 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, conversion_error, "int");
95 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime64, copyin_error, "int");
97 LIN_SDT_PROBE_DEFINE0(time, linux_common_clock_getres, nullcall);
98 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, conversion_error, "int");
99 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_getres, getres_error, "int");
100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
101 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
102 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres_time64, copyout_error, "int");
104 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
105 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
106 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
107 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
108 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
109 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
110 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_flags, "int");
111 LIN_SDT_PROBE_DEFINE1(time, linux_common_clock_nanosleep, unsupported_clockid, "int");
112 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
113 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, conversion_error, "int");
114 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyout_error, "int");
115 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep_time64, copyin_error, "int");
118 static int linux_common_clock_gettime(struct thread *, clockid_t,
120 static int linux_common_clock_settime(struct thread *, clockid_t,
122 static int linux_common_clock_getres(struct thread *, clockid_t,
124 static int linux_common_clock_nanosleep(struct thread *, clockid_t,
125 l_int, struct timespec *, struct timespec *);
128 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
131 #ifdef COMPAT_LINUX32
132 if (ntp->tv_sec > INT_MAX || ntp->tv_sec < INT_MIN)
135 ltp->tv_sec = ntp->tv_sec;
136 ltp->tv_nsec = ntp->tv_nsec;
142 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
145 if (ltp->tv_sec < 0 || ltp->tv_nsec < 0 || ltp->tv_nsec > 999999999)
147 ntp->tv_sec = ltp->tv_sec;
148 ntp->tv_nsec = ltp->tv_nsec;
153 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
155 native_to_linux_timespec64(struct l_timespec64 *ltp64, struct timespec *ntp)
158 ltp64->tv_sec = ntp->tv_sec;
159 ltp64->tv_nsec = ntp->tv_nsec;
165 linux_to_native_timespec64(struct timespec *ntp, struct l_timespec64 *ltp64)
168 if (ltp64->tv_sec < 0 || ltp64->tv_nsec < 0 || ltp64->tv_nsec > 999999999)
170 ntp->tv_sec = ltp64->tv_sec;
171 ntp->tv_nsec = ltp64->tv_nsec;
178 native_to_linux_itimerspec(struct l_itimerspec *ltp, struct itimerspec *ntp)
182 error = native_to_linux_timespec(<p->it_interval, &ntp->it_interval);
184 error = native_to_linux_timespec(<p->it_value, &ntp->it_interval);
189 linux_to_native_itimerspec(struct itimerspec *ntp, struct l_itimerspec *ltp)
193 error = linux_to_native_timespec(&ntp->it_interval, <p->it_interval);
195 error = linux_to_native_timespec(&ntp->it_value, <p->it_value);
200 linux_to_native_clockid(clockid_t *n, clockid_t l)
205 if ((l & LINUX_CLOCKFD_MASK) == LINUX_CLOCKFD)
207 if (LINUX_CPUCLOCK_WHICH(l) >= LINUX_CPUCLOCK_MAX)
210 if (LINUX_CPUCLOCK_PERTHREAD(l))
211 *n = CLOCK_THREAD_CPUTIME_ID;
213 *n = CLOCK_PROCESS_CPUTIME_ID;
218 case LINUX_CLOCK_REALTIME:
221 case LINUX_CLOCK_MONOTONIC:
222 *n = CLOCK_MONOTONIC;
224 case LINUX_CLOCK_PROCESS_CPUTIME_ID:
225 *n = CLOCK_PROCESS_CPUTIME_ID;
227 case LINUX_CLOCK_THREAD_CPUTIME_ID:
228 *n = CLOCK_THREAD_CPUTIME_ID;
230 case LINUX_CLOCK_REALTIME_COARSE:
231 *n = CLOCK_REALTIME_FAST;
233 case LINUX_CLOCK_MONOTONIC_COARSE:
234 case LINUX_CLOCK_MONOTONIC_RAW:
235 *n = CLOCK_MONOTONIC_FAST;
237 case LINUX_CLOCK_BOOTTIME:
240 case LINUX_CLOCK_REALTIME_ALARM:
241 case LINUX_CLOCK_BOOTTIME_ALARM:
242 case LINUX_CLOCK_SGI_CYCLE:
243 case LINUX_CLOCK_TAI:
244 LIN_SDT_PROBE1(time, linux_to_native_clockid,
245 unsupported_clockid, l);
248 LIN_SDT_PROBE1(time, linux_to_native_clockid,
257 linux_to_native_timerflags(int *nflags, int flags)
260 if (flags & ~LINUX_TIMER_ABSTIME)
263 if (flags & LINUX_TIMER_ABSTIME)
264 *nflags |= TIMER_ABSTIME;
269 linux_common_clock_gettime(struct thread *td, clockid_t which,
273 struct thread *targettd;
275 int error, clockwhich;
280 error = linux_to_native_clockid(&nwhich, which);
283 "unsupported clock_gettime clockid %d", which);
284 LIN_SDT_PROBE1(time, linux_common_clock_gettime,
285 conversion_error, error);
290 case CLOCK_PROCESS_CPUTIME_ID:
292 clockwhich = LINUX_CPUCLOCK_WHICH(which);
293 pid = LINUX_CPUCLOCK_ID(which);
295 clockwhich = LINUX_CPUCLOCK_SCHED;
302 error = pget(pid, PGET_CANSEE, &p);
306 switch (clockwhich) {
307 case LINUX_CPUCLOCK_PROF:
309 calcru(p, &ru.ru_utime, &ru.ru_stime);
312 timevaladd(&ru.ru_utime, &ru.ru_stime);
313 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
315 case LINUX_CPUCLOCK_VIRT:
317 calcru(p, &ru.ru_utime, &ru.ru_stime);
320 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
322 case LINUX_CPUCLOCK_SCHED:
323 kern_process_cputime(p, tp);
333 case CLOCK_THREAD_CPUTIME_ID:
335 clockwhich = LINUX_CPUCLOCK_WHICH(which);
336 tid = LINUX_CPUCLOCK_ID(which);
338 clockwhich = LINUX_CPUCLOCK_SCHED;
346 targettd = linux_tdfind(td, tid, p->p_pid);
347 if (targettd == NULL)
350 switch (clockwhich) {
351 case LINUX_CPUCLOCK_PROF:
353 thread_lock(targettd);
354 rufetchtd(targettd, &ru);
355 thread_unlock(targettd);
358 timevaladd(&ru.ru_utime, &ru.ru_stime);
359 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
361 case LINUX_CPUCLOCK_VIRT:
363 thread_lock(targettd);
364 rufetchtd(targettd, &ru);
365 thread_unlock(targettd);
368 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, tp);
370 case LINUX_CPUCLOCK_SCHED:
373 kern_thread_cputime(targettd, tp);
383 error = kern_clock_gettime(td, nwhich, tp);
391 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
393 struct l_timespec lts;
397 error = linux_common_clock_gettime(td, args->which, &tp);
399 LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
402 error = native_to_linux_timespec(<s, &tp);
405 error = copyout(<s, args->tp, sizeof(lts));
407 LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
412 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
414 linux_clock_gettime64(struct thread *td, struct linux_clock_gettime64_args *args)
416 struct l_timespec64 lts;
420 error = linux_common_clock_gettime(td, args->which, &tp);
422 LIN_SDT_PROBE1(time, linux_clock_gettime64, gettime_error, error);
425 error = native_to_linux_timespec64(<s, &tp);
428 error = copyout(<s, args->tp, sizeof(lts));
430 LIN_SDT_PROBE1(time, linux_clock_gettime64, copyout_error, error);
437 linux_common_clock_settime(struct thread *td, clockid_t which,
443 error = linux_to_native_clockid(&nwhich, which);
446 "unsupported clock_settime clockid %d", which);
447 LIN_SDT_PROBE1(time, linux_common_clock_settime, conversion_error,
452 error = kern_clock_settime(td, nwhich, ts);
454 LIN_SDT_PROBE1(time, linux_common_clock_settime,
455 settime_error, error);
461 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
464 struct l_timespec lts;
467 error = copyin(args->tp, <s, sizeof(lts));
469 LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
472 error = linux_to_native_timespec(&ts, <s);
474 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
477 return (linux_common_clock_settime(td, args->which, &ts));
480 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
482 linux_clock_settime64(struct thread *td, struct linux_clock_settime64_args *args)
485 struct l_timespec64 lts;
488 error = copyin(args->tp, <s, sizeof(lts));
490 LIN_SDT_PROBE1(time, linux_clock_settime64, copyin_error, error);
493 error = linux_to_native_timespec64(&ts, <s);
495 LIN_SDT_PROBE1(time, linux_clock_settime64, conversion_error,
497 return (linux_common_clock_settime(td, args->which, &ts));
502 linux_common_clock_getres(struct thread *td, clockid_t which,
506 int error, clockwhich;
511 error = linux_to_native_clockid(&nwhich, which);
514 "unsupported clock_getres clockid %d", which);
515 LIN_SDT_PROBE1(time, linux_common_clock_getres,
516 conversion_error, error);
521 * Check user supplied clock id in case of per-process
522 * or thread-specific cpu-time clock.
526 case CLOCK_THREAD_CPUTIME_ID:
527 tid = LINUX_CPUCLOCK_ID(which);
530 if (linux_tdfind(td, tid, p->p_pid) == NULL)
535 case CLOCK_PROCESS_CPUTIME_ID:
536 pid = LINUX_CPUCLOCK_ID(which);
538 error = pget(pid, PGET_CANSEE, &p);
548 LIN_SDT_PROBE0(time, linux_common_clock_getres, nullcall);
553 case CLOCK_THREAD_CPUTIME_ID:
554 case CLOCK_PROCESS_CPUTIME_ID:
555 clockwhich = LINUX_CPUCLOCK_WHICH(which);
557 * In both cases (when the clock id obtained by a call to
558 * clock_getcpuclockid() or using the clock
559 * ID CLOCK_PROCESS_CPUTIME_ID Linux hardcodes precision
560 * of clock. The same for the CLOCK_THREAD_CPUTIME_ID clock.
562 * See Linux posix_cpu_clock_getres() implementation.
564 if (which > 0 || clockwhich == LINUX_CPUCLOCK_SCHED) {
570 switch (clockwhich) {
571 case LINUX_CPUCLOCK_PROF:
574 case LINUX_CPUCLOCK_VIRT:
575 nwhich = CLOCK_VIRTUAL;
585 error = kern_clock_getres(td, nwhich, ts);
587 LIN_SDT_PROBE1(time, linux_common_clock_getres,
588 getres_error, error);
597 linux_clock_getres(struct thread *td,
598 struct linux_clock_getres_args *args)
601 struct l_timespec lts;
604 error = linux_common_clock_getres(td, args->which, &ts);
605 if (error != 0 || args->tp == NULL)
608 error = native_to_linux_timespec(<s, &ts);
611 error = copyout(<s, args->tp, sizeof(lts));
613 LIN_SDT_PROBE1(time, linux_clock_getres,
614 copyout_error, error);
618 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
620 linux_clock_getres_time64(struct thread *td,
621 struct linux_clock_getres_time64_args *args)
624 struct l_timespec64 lts;
627 error = linux_common_clock_getres(td, args->which, &ts);
628 if (error != 0 || args->tp == NULL)
631 error = native_to_linux_timespec64(<s, &ts);
634 error = copyout(<s, args->tp, sizeof(lts));
636 LIN_SDT_PROBE1(time, linux_clock_getres_time64,
637 copyout_error, error);
643 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
645 struct timespec *rmtp;
646 struct l_timespec lrqts, lrmts;
647 struct timespec rqts, rmts;
650 error = copyin(args->rqtp, &lrqts, sizeof lrqts);
652 LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
656 if (args->rmtp != NULL)
661 error = linux_to_native_timespec(&rqts, &lrqts);
663 LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
666 error = kern_nanosleep(td, &rqts, rmtp);
667 if (error == EINTR && args->rmtp != NULL) {
668 error2 = native_to_linux_timespec(&lrmts, rmtp);
671 error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
673 LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
683 linux_common_clock_nanosleep(struct thread *td, clockid_t which,
684 l_int lflags, struct timespec *rqtp, struct timespec *rmtp)
689 error = linux_to_native_timerflags(&flags, lflags);
691 LIN_SDT_PROBE1(time, linux_common_clock_nanosleep,
692 unsupported_flags, lflags);
696 error = linux_to_native_clockid(&clockid, which);
699 "unsupported clock_nanosleep clockid %d", which);
700 LIN_SDT_PROBE1(time, linux_common_clock_nanosleep,
701 unsupported_clockid, which);
704 if (clockid == CLOCK_THREAD_CPUTIME_ID)
707 return (kern_clock_nanosleep(td, clockid, flags, rqtp, rmtp));
711 linux_clock_nanosleep(struct thread *td,
712 struct linux_clock_nanosleep_args *args)
714 struct timespec *rmtp;
715 struct l_timespec lrqts, lrmts;
716 struct timespec rqts, rmts;
719 error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
721 LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
726 error = linux_to_native_timespec(&rqts, &lrqts);
728 LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
733 if (args->rmtp != NULL)
738 error = linux_common_clock_nanosleep(td, args->which, args->flags,
740 if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 &&
741 args->rmtp != NULL) {
742 error2 = native_to_linux_timespec(&lrmts, rmtp);
745 error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
747 LIN_SDT_PROBE1(time, linux_clock_nanosleep,
748 copyout_error, error2);
755 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
757 linux_clock_nanosleep_time64(struct thread *td,
758 struct linux_clock_nanosleep_time64_args *args)
760 struct timespec *rmtp;
761 struct l_timespec64 lrqts, lrmts;
762 struct timespec rqts, rmts;
765 error = copyin(args->rqtp, &lrqts, sizeof(lrqts));
767 LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
768 copyin_error, error);
772 error = linux_to_native_timespec64(&rqts, &lrqts);
774 LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
775 conversion_error, error);
779 if (args->rmtp != NULL)
784 error = linux_common_clock_nanosleep(td, args->which, args->flags,
786 if (error == EINTR && (args->flags & LINUX_TIMER_ABSTIME) == 0 &&
787 args->rmtp != NULL) {
788 error2 = native_to_linux_timespec64(&lrmts, rmtp);
791 error2 = copyout(&lrmts, args->rmtp, sizeof(lrmts));
793 LIN_SDT_PROBE1(time, linux_clock_nanosleep_time64,
794 copyout_error, error2);