xref: /netbsd-src/sys/kern/subr_time.c (revision 65195a4c92dbfea163b48af57736b67314fc5cbb)
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