1 #include <sys/time.h>
2 
3 #include <errno.h>
4 #include <time.h>
5 
6 #include "warnp.h"
7 
8 #include "monoclock.h"
9 
10 /* Determine which clock(s) to use. */
11 #ifndef POSIXFAIL_CLOCK_GETTIME
12 #ifdef CLOCK_MONOTONIC
13 #define USE_MONOTONIC
14 #endif
15 #ifndef POSIXFAIL_CLOCK_REALTIME
16 #define USE_REALTIME
17 #endif
18 #endif
19 
20 /**
21  * monoclock_get(tv):
22  * Store the current time in ${tv}.  If CLOCK_MONOTONIC is available, use
23  * that clock; if CLOCK_MONOTONIC is unavailable, use CLOCK_REALTIME (if
24  * available) or gettimeofday(2).
25  */
26 int
monoclock_get(struct timeval * tv)27 monoclock_get(struct timeval * tv)
28 {
29 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
30 	struct timespec tp;
31 #endif
32 
33 #ifdef USE_MONOTONIC
34 	if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
35 		tv->tv_sec = tp.tv_sec;
36 		tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
37 	} else if ((errno != ENOSYS) && (errno != EINVAL)) {
38 		warnp("clock_gettime(CLOCK_MONOTONIC)");
39 		goto err0;
40 	} else
41 #endif
42 #ifdef USE_REALTIME
43 	if (clock_gettime(CLOCK_REALTIME, &tp) == 0) {
44 		tv->tv_sec = tp.tv_sec;
45 		tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
46 	} else {
47 		warnp("clock_gettime(CLOCK_REALTIME)");
48 		goto err0;
49 	}
50 #else
51 	if (gettimeofday(tv, NULL)) {
52 		warnp("gettimeofday");
53 		goto err0;
54 	}
55 #endif
56 
57 	/* Success! */
58 	return (0);
59 
60 err0:
61 	/* Failure! */
62 	return (-1);
63 }
64 
65 /**
66  * monoclock_get_cputime(tv):
67  * Store in ${tv} the duration the process has been running if
68  * CLOCK_PROCESS_CPUTIME_ID is available; fall back to monoclock_get()
69  * otherwise.
70  */
71 int
monoclock_get_cputime(struct timeval * tv)72 monoclock_get_cputime(struct timeval * tv)
73 {
74 	/* Use CLOCK_PROCESS_CPUTIME_ID if available. */
75 #ifdef CLOCK_PROCESS_CPUTIME_ID
76 	struct timespec tp;
77 
78 	if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) == 0) {
79 		tv->tv_sec = tp.tv_sec;
80 		tv->tv_usec = (suseconds_t)(tp.tv_nsec / 1000);
81 	} else if ((errno != ENOSYS) && (errno != EINVAL)) {
82 		warnp("clock_gettime(CLOCK_PROCESS_CPUTIME_ID)");
83 		goto err0;
84 	} else
85 #endif
86 	/* Fall back to monoclock_get(). */
87 	if (monoclock_get(tv))
88 		goto err0;
89 
90 	/* Success! */
91 	return (0);
92 
93 err0:
94 	/* Failure! */
95 	return (-1);
96 }
97 
98 /**
99  * monoclock_getres(resd):
100  * Store an upper limit on timer granularity in ${resd}. If CLOCK_MONOTONIC is
101  * available, use that clock; if CLOCK_MONOTONIC is unavailable, use
102  * CLOCK_REALTIME (if available) or gettimeofday(2).  For this value to be
103  * meaningful, we assume that clock_getres(x) succeeds iff clock_gettime(x)
104  * succeeds.
105  */
106 int
monoclock_getres(double * resd)107 monoclock_getres(double * resd)
108 {
109 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
110 	struct timespec res;
111 #endif
112 
113 #ifdef USE_MONOTONIC
114 	if (clock_getres(CLOCK_MONOTONIC, &res) == 0) {
115 		/* Convert clock resolution to a double. */
116 		*resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
117 	} else if ((errno != ENOSYS) && (errno != EINVAL)) {
118 		warnp("clock_getres(CLOCK_MONOTONIC)");
119 		goto err0;
120 	} else
121 #endif
122 #ifdef USE_REALTIME
123 	if (clock_getres(CLOCK_REALTIME, &res) == 0) {
124 		/* Convert clock resolution to a double. */
125 		*resd = (double)res.tv_sec + (double)res.tv_nsec * 0.000000001;
126 	} else {
127 		warnp("clock_getres(CLOCK_REALTIME)");
128 		goto err0;
129 	}
130 #else
131 	/*
132 	 * We'll be using gettimeofday().  There is no standard way of getting
133 	 * the resolution of this clock, but it seems safe to assume that it
134 	 * ticks at a minimum rate of CLOCKS_PER_SEC Hz (even though that is
135 	 * defined in relation to the measurement of processor time usage, not
136 	 * wallclock time); on non-broken systems we'll be relying on
137 	 * clock_gettime and clock_getres anyway.
138 	 */
139 	*resd = 1.0 / CLOCKS_PER_SEC;
140 #endif
141 
142 	/* Success! */
143 	return (0);
144 
145 #if defined(USE_MONOTONIC) || defined(USE_REALTIME)
146 err0:
147 	/* Failure! */
148 	return (-1);
149 #endif
150 }
151