subr_time.c revision 1.41 1 1.41 riastrad /* $NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $ */
2 1.1 pooka
3 1.1 pooka /*
4 1.1 pooka * Copyright (c) 1982, 1986, 1989, 1993
5 1.1 pooka * The Regents of the University of California. All rights reserved.
6 1.1 pooka *
7 1.1 pooka * Redistribution and use in source and binary forms, with or without
8 1.1 pooka * modification, are permitted provided that the following conditions
9 1.1 pooka * are met:
10 1.1 pooka * 1. Redistributions of source code must retain the above copyright
11 1.1 pooka * notice, this list of conditions and the following disclaimer.
12 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 pooka * notice, this list of conditions and the following disclaimer in the
14 1.1 pooka * documentation and/or other materials provided with the distribution.
15 1.1 pooka * 3. Neither the name of the University nor the names of its contributors
16 1.1 pooka * may be used to endorse or promote products derived from this software
17 1.1 pooka * without specific prior written permission.
18 1.1 pooka *
19 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.1 pooka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.1 pooka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.1 pooka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.1 pooka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.1 pooka * SUCH DAMAGE.
30 1.1 pooka *
31 1.1 pooka * @(#)kern_clock.c 8.5 (Berkeley) 1/21/94
32 1.1 pooka * @(#)kern_time.c 8.4 (Berkeley) 5/26/95
33 1.1 pooka */
34 1.1 pooka
35 1.1 pooka #include <sys/cdefs.h>
36 1.41 riastrad __KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $");
37 1.1 pooka
38 1.1 pooka #include <sys/param.h>
39 1.40 riastrad #include <sys/types.h>
40 1.40 riastrad
41 1.40 riastrad #include <sys/intr.h>
42 1.40 riastrad #include <sys/kauth.h>
43 1.1 pooka #include <sys/kernel.h>
44 1.40 riastrad #include <sys/lwp.h>
45 1.18 christos #include <sys/proc.h>
46 1.1 pooka #include <sys/time.h>
47 1.1 pooka #include <sys/timetc.h>
48 1.40 riastrad #include <sys/timex.h>
49 1.1 pooka
50 1.1 pooka /*
51 1.1 pooka * Compute number of hz until specified time. Used to compute second
52 1.1 pooka * argument to callout_reset() from an absolute time.
53 1.1 pooka */
54 1.1 pooka int
55 1.4 christos tvhzto(const struct timeval *tvp)
56 1.1 pooka {
57 1.1 pooka struct timeval now, tv;
58 1.1 pooka
59 1.1 pooka tv = *tvp; /* Don't modify original tvp. */
60 1.1 pooka getmicrotime(&now);
61 1.1 pooka timersub(&tv, &now, &tv);
62 1.1 pooka return tvtohz(&tv);
63 1.1 pooka }
64 1.1 pooka
65 1.4 christos int
66 1.4 christos tshzto(const struct timespec *tsp)
67 1.4 christos {
68 1.4 christos struct timespec now, ts;
69 1.4 christos
70 1.4 christos ts = *tsp; /* Don't modify original tsp. */
71 1.4 christos getnanotime(&now);
72 1.4 christos timespecsub(&ts, &now, &ts);
73 1.4 christos return tstohz(&ts);
74 1.4 christos }
75 1.9 christos
76 1.9 christos int
77 1.9 christos tshztoup(const struct timespec *tsp)
78 1.9 christos {
79 1.9 christos struct timespec now, ts;
80 1.9 christos
81 1.9 christos ts = *tsp; /* Don't modify original tsp. */
82 1.9 christos getnanouptime(&now);
83 1.9 christos timespecsub(&ts, &now, &ts);
84 1.9 christos return tstohz(&ts);
85 1.9 christos }
86 1.9 christos
87 1.1 pooka /*
88 1.1 pooka * Compute number of ticks in the specified amount of time.
89 1.1 pooka */
90 1.1 pooka int
91 1.4 christos tstohz(const struct timespec *ts)
92 1.1 pooka {
93 1.1 pooka struct timeval tv;
94 1.1 pooka
95 1.1 pooka /*
96 1.1 pooka * usec has great enough resolution for hz, so convert to a
97 1.1 pooka * timeval and use tvtohz() above.
98 1.1 pooka */
99 1.1 pooka TIMESPEC_TO_TIMEVAL(&tv, ts);
100 1.1 pooka return tvtohz(&tv);
101 1.1 pooka }
102 1.1 pooka
103 1.5 rmind int
104 1.5 rmind inittimeleft(struct timespec *ts, struct timespec *sleepts)
105 1.5 rmind {
106 1.5 rmind
107 1.5 rmind if (itimespecfix(ts)) {
108 1.5 rmind return -1;
109 1.5 rmind }
110 1.35 riastrad KASSERT(ts->tv_sec >= 0);
111 1.5 rmind getnanouptime(sleepts);
112 1.5 rmind return 0;
113 1.5 rmind }
114 1.5 rmind
115 1.5 rmind int
116 1.5 rmind gettimeleft(struct timespec *ts, struct timespec *sleepts)
117 1.5 rmind {
118 1.35 riastrad struct timespec now, sleptts;
119 1.35 riastrad
120 1.35 riastrad KASSERT(ts->tv_sec >= 0);
121 1.5 rmind
122 1.5 rmind /*
123 1.5 rmind * Reduce ts by elapsed time based on monotonic time scale.
124 1.5 rmind */
125 1.35 riastrad getnanouptime(&now);
126 1.35 riastrad KASSERT(timespeccmp(sleepts, &now, <=));
127 1.35 riastrad timespecsub(&now, sleepts, &sleptts);
128 1.35 riastrad *sleepts = now;
129 1.35 riastrad
130 1.35 riastrad if (timespeccmp(ts, &sleptts, <=)) { /* timed out */
131 1.35 riastrad timespecclear(ts);
132 1.35 riastrad return 0;
133 1.35 riastrad }
134 1.5 rmind timespecsub(ts, &sleptts, ts);
135 1.5 rmind
136 1.5 rmind return tstohz(ts);
137 1.5 rmind }
138 1.5 rmind
139 1.20 christos void
140 1.20 christos clock_timeleft(clockid_t clockid, struct timespec *ts, struct timespec *sleepts)
141 1.20 christos {
142 1.20 christos struct timespec sleptts;
143 1.20 christos
144 1.20 christos clock_gettime1(clockid, &sleptts);
145 1.20 christos timespecadd(ts, sleepts, ts);
146 1.20 christos timespecsub(ts, &sleptts, ts);
147 1.20 christos *sleepts = sleptts;
148 1.20 christos }
149 1.20 christos
150 1.11 martin int
151 1.11 martin clock_gettime1(clockid_t clock_id, struct timespec *ts)
152 1.11 martin {
153 1.18 christos int error;
154 1.18 christos struct proc *p;
155 1.18 christos
156 1.18 christos #define CPUCLOCK_ID_MASK (~(CLOCK_THREAD_CPUTIME_ID|CLOCK_PROCESS_CPUTIME_ID))
157 1.18 christos if (clock_id & CLOCK_PROCESS_CPUTIME_ID) {
158 1.18 christos pid_t pid = clock_id & CPUCLOCK_ID_MASK;
159 1.38 riastrad struct timeval cputime;
160 1.18 christos
161 1.25 ad mutex_enter(&proc_lock);
162 1.18 christos p = pid == 0 ? curproc : proc_find(pid);
163 1.18 christos if (p == NULL) {
164 1.25 ad mutex_exit(&proc_lock);
165 1.18 christos return ESRCH;
166 1.18 christos }
167 1.38 riastrad mutex_enter(p->p_lock);
168 1.38 riastrad calcru(p, /*usertime*/NULL, /*systime*/NULL, /*intrtime*/NULL,
169 1.38 riastrad &cputime);
170 1.38 riastrad mutex_exit(p->p_lock);
171 1.25 ad mutex_exit(&proc_lock);
172 1.18 christos
173 1.18 christos // XXX: Perhaps create a special kauth type
174 1.31 christos error = kauth_authorize_process(kauth_cred_get(),
175 1.18 christos KAUTH_PROCESS_PTRACE, p,
176 1.18 christos KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL);
177 1.18 christos if (error)
178 1.18 christos return error;
179 1.38 riastrad
180 1.38 riastrad TIMEVAL_TO_TIMESPEC(&cputime, ts);
181 1.38 riastrad return 0;
182 1.18 christos } else if (clock_id & CLOCK_THREAD_CPUTIME_ID) {
183 1.18 christos struct lwp *l;
184 1.18 christos lwpid_t lid = clock_id & CPUCLOCK_ID_MASK;
185 1.38 riastrad struct bintime tm = {0, 0};
186 1.38 riastrad
187 1.18 christos p = curproc;
188 1.18 christos mutex_enter(p->p_lock);
189 1.18 christos l = lid == 0 ? curlwp : lwp_find(p, lid);
190 1.18 christos if (l == NULL) {
191 1.18 christos mutex_exit(p->p_lock);
192 1.18 christos return ESRCH;
193 1.18 christos }
194 1.38 riastrad addrulwp(l, &tm);
195 1.18 christos mutex_exit(p->p_lock);
196 1.18 christos
197 1.38 riastrad bintime2timespec(&tm, ts);
198 1.18 christos return 0;
199 1.18 christos }
200 1.11 martin
201 1.11 martin switch (clock_id) {
202 1.11 martin case CLOCK_REALTIME:
203 1.11 martin nanotime(ts);
204 1.11 martin break;
205 1.11 martin case CLOCK_MONOTONIC:
206 1.11 martin nanouptime(ts);
207 1.11 martin break;
208 1.11 martin default:
209 1.11 martin return EINVAL;
210 1.11 martin }
211 1.11 martin
212 1.11 martin return 0;
213 1.11 martin }
214 1.11 martin
215 1.5 rmind /*
216 1.5 rmind * Calculate delta and convert from struct timespec to the ticks.
217 1.5 rmind */
218 1.5 rmind int
219 1.10 christos ts2timo(clockid_t clock_id, int flags, struct timespec *ts,
220 1.10 christos int *timo, struct timespec *start)
221 1.5 rmind {
222 1.14 christos int error;
223 1.28 nia struct timespec tsd;
224 1.5 rmind
225 1.21 kamil if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000L)
226 1.21 kamil return EINVAL;
227 1.21 kamil
228 1.30 nia if ((flags & TIMER_ABSTIME) != 0 || start != NULL) {
229 1.29 nia error = clock_gettime1(clock_id, &tsd);
230 1.26 nia if (error != 0)
231 1.17 christos return error;
232 1.29 nia if (start != NULL)
233 1.29 nia *start = tsd;
234 1.26 nia }
235 1.10 christos
236 1.30 nia if ((flags & TIMER_ABSTIME) != 0) {
237 1.34 riastrad if (!timespecsubok(ts, &tsd))
238 1.29 nia return EINVAL;
239 1.39 kre timespecsub(ts, &tsd, &tsd);
240 1.39 kre ts = &tsd;
241 1.29 nia }
242 1.10 christos
243 1.26 nia error = itimespecfix(ts);
244 1.26 nia if (error != 0)
245 1.5 rmind return error;
246 1.10 christos
247 1.15 christos if (ts->tv_sec == 0 && ts->tv_nsec == 0)
248 1.15 christos return ETIMEDOUT;
249 1.15 christos
250 1.14 christos *timo = tstohz(ts);
251 1.14 christos KASSERT(*timo > 0);
252 1.5 rmind
253 1.5 rmind return 0;
254 1.5 rmind }
255