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