1*65195a4cSriastradh /* $NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $ */ 25fbd525bSpooka 35fbd525bSpooka /* 45fbd525bSpooka * Copyright (c) 1982, 1986, 1989, 1993 55fbd525bSpooka * The Regents of the University of California. All rights reserved. 65fbd525bSpooka * 75fbd525bSpooka * Redistribution and use in source and binary forms, with or without 85fbd525bSpooka * modification, are permitted provided that the following conditions 95fbd525bSpooka * are met: 105fbd525bSpooka * 1. Redistributions of source code must retain the above copyright 115fbd525bSpooka * notice, this list of conditions and the following disclaimer. 125fbd525bSpooka * 2. Redistributions in binary form must reproduce the above copyright 135fbd525bSpooka * notice, this list of conditions and the following disclaimer in the 145fbd525bSpooka * documentation and/or other materials provided with the distribution. 155fbd525bSpooka * 3. Neither the name of the University nor the names of its contributors 165fbd525bSpooka * may be used to endorse or promote products derived from this software 175fbd525bSpooka * without specific prior written permission. 185fbd525bSpooka * 195fbd525bSpooka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 205fbd525bSpooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 215fbd525bSpooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 225fbd525bSpooka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 235fbd525bSpooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 245fbd525bSpooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 255fbd525bSpooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 265fbd525bSpooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 275fbd525bSpooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 285fbd525bSpooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 295fbd525bSpooka * SUCH DAMAGE. 305fbd525bSpooka * 315fbd525bSpooka * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94 325fbd525bSpooka * @(#)kern_time.c 8.4 (Berkeley) 5/26/95 335fbd525bSpooka */ 345fbd525bSpooka 355fbd525bSpooka #include <sys/cdefs.h> 36*65195a4cSriastradh __KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $"); 375fbd525bSpooka 385fbd525bSpooka #include <sys/param.h> 3912ae7b37Sriastradh #include <sys/types.h> 4012ae7b37Sriastradh 4112ae7b37Sriastradh #include <sys/intr.h> 428114776cSchristos #include <sys/kauth.h> 4312ae7b37Sriastradh #include <sys/kernel.h> 448114776cSchristos #include <sys/lwp.h> 4512ae7b37Sriastradh #include <sys/proc.h> 465fbd525bSpooka #include <sys/time.h> 475fbd525bSpooka #include <sys/timetc.h> 4812ae7b37Sriastradh #include <sys/timex.h> 495fbd525bSpooka 505fbd525bSpooka /* 515fbd525bSpooka * Compute number of hz until specified time. Used to compute second 525fbd525bSpooka * argument to callout_reset() from an absolute time. 535fbd525bSpooka */ 545fbd525bSpooka int 55aa389c69Schristos tvhzto(const struct timeval *tvp) 565fbd525bSpooka { 575fbd525bSpooka struct timeval now, tv; 585fbd525bSpooka 595fbd525bSpooka tv = *tvp; /* Don't modify original tvp. */ 605fbd525bSpooka getmicrotime(&now); 615fbd525bSpooka timersub(&tv, &now, &tv); 625fbd525bSpooka return tvtohz(&tv); 635fbd525bSpooka } 645fbd525bSpooka 65aa389c69Schristos int 66aa389c69Schristos tshzto(const struct timespec *tsp) 67aa389c69Schristos { 68aa389c69Schristos struct timespec now, ts; 69aa389c69Schristos 70aa389c69Schristos ts = *tsp; /* Don't modify original tsp. */ 71aa389c69Schristos getnanotime(&now); 72aa389c69Schristos timespecsub(&ts, &now, &ts); 73aa389c69Schristos return tstohz(&ts); 74aa389c69Schristos } 752e4fce7cSchristos 762e4fce7cSchristos int 772e4fce7cSchristos tshztoup(const struct timespec *tsp) 782e4fce7cSchristos { 792e4fce7cSchristos struct timespec now, ts; 802e4fce7cSchristos 812e4fce7cSchristos ts = *tsp; /* Don't modify original tsp. */ 822e4fce7cSchristos getnanouptime(&now); 832e4fce7cSchristos timespecsub(&ts, &now, &ts); 842e4fce7cSchristos return tstohz(&ts); 852e4fce7cSchristos } 862e4fce7cSchristos 875fbd525bSpooka /* 885fbd525bSpooka * Compute number of ticks in the specified amount of time. 895fbd525bSpooka */ 905fbd525bSpooka int 91aa389c69Schristos tstohz(const struct timespec *ts) 925fbd525bSpooka { 935fbd525bSpooka struct timeval tv; 945fbd525bSpooka 955fbd525bSpooka /* 965fbd525bSpooka * usec has great enough resolution for hz, so convert to a 975fbd525bSpooka * timeval and use tvtohz() above. 985fbd525bSpooka */ 995fbd525bSpooka TIMESPEC_TO_TIMEVAL(&tv, ts); 1005fbd525bSpooka return tvtohz(&tv); 1015fbd525bSpooka } 1025fbd525bSpooka 103b9a294cfSrmind int 104b9a294cfSrmind inittimeleft(struct timespec *ts, struct timespec *sleepts) 105b9a294cfSrmind { 106b9a294cfSrmind 107b9a294cfSrmind if (itimespecfix(ts)) { 108b9a294cfSrmind return -1; 109b9a294cfSrmind } 110eaf33ef4Sriastradh KASSERT(ts->tv_sec >= 0); 111b9a294cfSrmind getnanouptime(sleepts); 112b9a294cfSrmind return 0; 113b9a294cfSrmind } 114b9a294cfSrmind 115b9a294cfSrmind int 116b9a294cfSrmind gettimeleft(struct timespec *ts, struct timespec *sleepts) 117b9a294cfSrmind { 118eaf33ef4Sriastradh struct timespec now, sleptts; 119eaf33ef4Sriastradh 120eaf33ef4Sriastradh KASSERT(ts->tv_sec >= 0); 121b9a294cfSrmind 122b9a294cfSrmind /* 123b9a294cfSrmind * Reduce ts by elapsed time based on monotonic time scale. 124b9a294cfSrmind */ 125eaf33ef4Sriastradh getnanouptime(&now); 126eaf33ef4Sriastradh KASSERT(timespeccmp(sleepts, &now, <=)); 127eaf33ef4Sriastradh timespecsub(&now, sleepts, &sleptts); 128eaf33ef4Sriastradh *sleepts = now; 129eaf33ef4Sriastradh 130eaf33ef4Sriastradh if (timespeccmp(ts, &sleptts, <=)) { /* timed out */ 131eaf33ef4Sriastradh timespecclear(ts); 132eaf33ef4Sriastradh return 0; 133eaf33ef4Sriastradh } 134b9a294cfSrmind timespecsub(ts, &sleptts, ts); 135b9a294cfSrmind 136b9a294cfSrmind return tstohz(ts); 137b9a294cfSrmind } 138b9a294cfSrmind 13985bf85b7Schristos void 14085bf85b7Schristos clock_timeleft(clockid_t clockid, struct timespec *ts, struct timespec *sleepts) 14185bf85b7Schristos { 14285bf85b7Schristos struct timespec sleptts; 14385bf85b7Schristos 14485bf85b7Schristos clock_gettime1(clockid, &sleptts); 14585bf85b7Schristos timespecadd(ts, sleepts, ts); 14685bf85b7Schristos timespecsub(ts, &sleptts, ts); 14785bf85b7Schristos *sleepts = sleptts; 14885bf85b7Schristos } 14985bf85b7Schristos 150573f2396Smartin int 151573f2396Smartin clock_gettime1(clockid_t clock_id, struct timespec *ts) 152573f2396Smartin { 1538114776cSchristos int error; 1548114776cSchristos struct proc *p; 1558114776cSchristos 1568114776cSchristos #define CPUCLOCK_ID_MASK (~(CLOCK_THREAD_CPUTIME_ID|CLOCK_PROCESS_CPUTIME_ID)) 1578114776cSchristos if (clock_id & CLOCK_PROCESS_CPUTIME_ID) { 1588114776cSchristos pid_t pid = clock_id & CPUCLOCK_ID_MASK; 15942ba7a81Sriastradh struct timeval cputime; 1608114776cSchristos 1610eaaa024Sad mutex_enter(&proc_lock); 1628114776cSchristos p = pid == 0 ? curproc : proc_find(pid); 1638114776cSchristos if (p == NULL) { 1640eaaa024Sad mutex_exit(&proc_lock); 1658114776cSchristos return ESRCH; 1668114776cSchristos } 16742ba7a81Sriastradh mutex_enter(p->p_lock); 16842ba7a81Sriastradh calcru(p, /*usertime*/NULL, /*systime*/NULL, /*intrtime*/NULL, 16942ba7a81Sriastradh &cputime); 17042ba7a81Sriastradh mutex_exit(p->p_lock); 1710eaaa024Sad mutex_exit(&proc_lock); 1728114776cSchristos 1738114776cSchristos // XXX: Perhaps create a special kauth type 174813a709dSchristos error = kauth_authorize_process(kauth_cred_get(), 1758114776cSchristos KAUTH_PROCESS_PTRACE, p, 1768114776cSchristos KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL); 1778114776cSchristos if (error) 1788114776cSchristos return error; 17942ba7a81Sriastradh 18042ba7a81Sriastradh TIMEVAL_TO_TIMESPEC(&cputime, ts); 18142ba7a81Sriastradh return 0; 1828114776cSchristos } else if (clock_id & CLOCK_THREAD_CPUTIME_ID) { 1838114776cSchristos struct lwp *l; 1848114776cSchristos lwpid_t lid = clock_id & CPUCLOCK_ID_MASK; 18542ba7a81Sriastradh struct bintime tm = {0, 0}; 18642ba7a81Sriastradh 1878114776cSchristos p = curproc; 1888114776cSchristos mutex_enter(p->p_lock); 1898114776cSchristos l = lid == 0 ? curlwp : lwp_find(p, lid); 1908114776cSchristos if (l == NULL) { 1918114776cSchristos mutex_exit(p->p_lock); 1928114776cSchristos return ESRCH; 1938114776cSchristos } 19442ba7a81Sriastradh addrulwp(l, &tm); 1958114776cSchristos mutex_exit(p->p_lock); 1968114776cSchristos 19742ba7a81Sriastradh bintime2timespec(&tm, ts); 1988114776cSchristos return 0; 1998114776cSchristos } 200573f2396Smartin 201573f2396Smartin switch (clock_id) { 202573f2396Smartin case CLOCK_REALTIME: 203573f2396Smartin nanotime(ts); 204573f2396Smartin break; 205573f2396Smartin case CLOCK_MONOTONIC: 206573f2396Smartin nanouptime(ts); 207573f2396Smartin break; 208573f2396Smartin default: 209573f2396Smartin return EINVAL; 210573f2396Smartin } 211573f2396Smartin 212573f2396Smartin return 0; 213573f2396Smartin } 214573f2396Smartin 215b9a294cfSrmind /* 216b9a294cfSrmind * Calculate delta and convert from struct timespec to the ticks. 217b9a294cfSrmind */ 218b9a294cfSrmind int 2194cec95f0Schristos ts2timo(clockid_t clock_id, int flags, struct timespec *ts, 2204cec95f0Schristos int *timo, struct timespec *start) 221b9a294cfSrmind { 2227f7fe0a2Schristos int error; 223a95db406Snia struct timespec tsd; 224b9a294cfSrmind 225ffd5d3e3Skamil if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000L) 226ffd5d3e3Skamil return EINVAL; 227ffd5d3e3Skamil 2289e6dbce9Snia if ((flags & TIMER_ABSTIME) != 0 || start != NULL) { 2296f5e84c0Snia error = clock_gettime1(clock_id, &tsd); 23073fcbb1bSnia if (error != 0) 231b9a294cfSrmind return error; 2326f5e84c0Snia if (start != NULL) 2336f5e84c0Snia *start = tsd; 23473fcbb1bSnia } 2354cec95f0Schristos 2369e6dbce9Snia if ((flags & TIMER_ABSTIME) != 0) { 23754baa6cfSriastradh if (!timespecsubok(ts, &tsd)) 2386f5e84c0Snia return EINVAL; 23930a14a5aSkre timespecsub(ts, &tsd, &tsd); 24030a14a5aSkre ts = &tsd; 2416f5e84c0Snia } 2424cec95f0Schristos 24373fcbb1bSnia error = itimespecfix(ts); 24473fcbb1bSnia if (error != 0) 2454cec95f0Schristos return error; 2464cec95f0Schristos 24711c04fdfSchristos if (ts->tv_sec == 0 && ts->tv_nsec == 0) 24811c04fdfSchristos return ETIMEDOUT; 24911c04fdfSchristos 2507f7fe0a2Schristos *timo = tstohz(ts); 2517f7fe0a2Schristos KASSERT(*timo > 0); 252b9a294cfSrmind 253b9a294cfSrmind return 0; 254b9a294cfSrmind } 255