1 /* $OpenBSD: microtime.c,v 1.2 2022/07/23 22:58:51 cheloha 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 if (tc_delta(tk, &delta)) 49 return -1; 50 TIMECOUNT_TO_BINTIME(delta, tk->tk_scale, bt); 51 bintimeadd(bt, &tk->tk_offset, 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 TIMECOUNT_TO_BINTIME(delta, tk->tk_scale, bt); 69 bintimeadd(bt, &tk->tk_offset, bt); 70 bintimesub(bt, &tk->tk_naptime, bt); 71 membar_consumer(); 72 } while (gen == 0 || gen != tk->tk_generation); 73 74 return 0; 75 } 76 77 static int 78 bintime(struct bintime *bt, struct timekeep *tk) 79 { 80 u_int gen, delta; 81 82 do { 83 gen = tk->tk_generation; 84 membar_consumer(); 85 if (tc_delta(tk, &delta)) 86 return -1; 87 TIMECOUNT_TO_BINTIME(delta, tk->tk_scale, bt); 88 bintimeadd(bt, &tk->tk_offset, bt); 89 bintimeadd(bt, &tk->tk_boottime, bt); 90 membar_consumer(); 91 } while (gen == 0 || gen != tk->tk_generation); 92 93 return 0; 94 } 95 96 int 97 _microtime(struct timeval *tvp, struct timekeep *tk) 98 { 99 struct bintime bt; 100 101 if (bintime(&bt, tk)) 102 return -1; 103 BINTIME_TO_TIMEVAL(&bt, tvp); 104 return 0; 105 } 106 107 int 108 _nanotime(struct timespec *tsp, struct timekeep *tk) 109 { 110 struct bintime bt; 111 112 if (bintime(&bt, tk)) 113 return -1; 114 BINTIME_TO_TIMESPEC(&bt, tsp); 115 return 0; 116 } 117 118 int 119 _nanoruntime(struct timespec *ts, struct timekeep *tk) 120 { 121 struct bintime bt; 122 123 if (binruntime(&bt, tk)) 124 return -1; 125 BINTIME_TO_TIMESPEC(&bt, ts); 126 return 0; 127 } 128 129 130 int 131 _nanouptime(struct timespec *tsp, struct timekeep *tk) 132 { 133 struct bintime bt; 134 135 if (binuptime(&bt, tk)) 136 return -1; 137 BINTIME_TO_TIMESPEC(&bt, tsp); 138 return 0; 139 } 140