xref: /openbsd-src/lib/libc/sys/microtime.c (revision fcde59b201a29a2b4570b00b71e7aa25d61cb5c1)
1 /*	$OpenBSD: microtime.c,v 1.1 2020/07/06 13:33:06 pirofti Exp $ */
2 /*
3  * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
4  * Copyright (c) 2020 Paul Irofti <paul@irofti.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/atomic.h>
21 #include <sys/timetc.h>
22 
23 #include <time.h>
24 
25 /*
26  * Return the difference between the timehands' counter value now and what
27  * was when we copied it to the timehands' offset_count.
28  */
29 static inline int
30 tc_delta(struct timekeep *tk, u_int *delta)
31 {
32 	u_int tc;
33 
34 	if (_tc_get_timecount(tk, &tc))
35 		return -1;
36 	*delta = (tc - tk->tk_offset_count) & tk->tk_counter_mask;
37 	return 0;
38 }
39 
40 static int
41 binuptime(struct bintime *bt, struct timekeep *tk)
42 {
43 	u_int gen, delta;
44 
45 	do {
46 		gen = tk->tk_generation;
47 		membar_consumer();
48 		*bt = tk->tk_offset;
49 		if (tc_delta(tk, &delta))
50 			return -1;
51 		bintimeaddfrac(bt, tk->tk_scale * delta, bt);
52 		membar_consumer();
53 	} while (gen == 0 || gen != tk->tk_generation);
54 
55 	return 0;
56 }
57 
58 static int
59 binruntime(struct bintime *bt, struct timekeep *tk)
60 {
61 	u_int gen, delta;
62 
63 	do {
64 		gen = tk->tk_generation;
65 		membar_consumer();
66 		if (tc_delta(tk, &delta))
67 			return -1;
68 		bintimeaddfrac(&tk->tk_offset, tk->tk_scale * delta, bt);
69 		bintimesub(bt, &tk->tk_naptime, bt);
70 		membar_consumer();
71 	} while (gen == 0 || gen != tk->tk_generation);
72 
73 	return 0;
74 }
75 
76 static int
77 bintime(struct bintime *bt, struct timekeep *tk)
78 {
79 	u_int gen, delta;
80 
81 	do {
82 		gen = tk->tk_generation;
83 		membar_consumer();
84 		*bt = tk->tk_offset;
85 		if (tc_delta(tk, &delta))
86 			return -1;
87 		bintimeaddfrac(bt, tk->tk_scale * delta, bt);
88 		bintimeadd(bt, &tk->tk_boottime, bt);
89 		membar_consumer();
90 	} while (gen == 0 || gen != tk->tk_generation);
91 
92 	return 0;
93 }
94 
95 int
96 _microtime(struct timeval *tvp, struct timekeep *tk)
97 {
98 	struct bintime bt;
99 
100 	if (bintime(&bt, tk))
101 		return -1;
102 	BINTIME_TO_TIMEVAL(&bt, tvp);
103 	return 0;
104 }
105 
106 int
107 _nanotime(struct timespec *tsp, struct timekeep *tk)
108 {
109 	struct bintime bt;
110 
111 	if (bintime(&bt, tk))
112 		return -1;
113 	BINTIME_TO_TIMESPEC(&bt, tsp);
114 	return 0;
115 }
116 
117 int
118 _nanoruntime(struct timespec *ts, struct timekeep *tk)
119 {
120 	struct bintime bt;
121 
122 	if (binruntime(&bt, tk))
123 		return -1;
124 	BINTIME_TO_TIMESPEC(&bt, ts);
125 	return 0;
126 }
127 
128 
129 int
130 _nanouptime(struct timespec *tsp, struct timekeep *tk)
131 {
132 	struct bintime bt;
133 
134 	if (binuptime(&bt, tk))
135 		return -1;
136 	BINTIME_TO_TIMESPEC(&bt, tsp);
137 	return 0;
138 }
139