4 * Implementation of the common elements of the POSIX clock API.
8 * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
9 * Copyright (C) 2017, 2018, MinGW.org Project
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice (including the next
20 * paragraph) shall be included in all copies or substantial portions of the
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
34 static struct __clockid__ clock_api[] =
35 { { /* CLOCK_REALTIME pre-initialization implementation reference data.
37 CLOCK_TYPE_REALTIME, /* Fixed category index */
38 CLOCK_REALTIME_FREQUENCY, /* Always updated at this frequency */
39 0LL, /* Resolution in ns; needs initialization */
40 UNIX_EPOCH_AS_FILETIME /* Fixed timebase reference */
42 { /* CLOCK_MONOTONIC pre-initialization implementation reference data.
44 CLOCK_TYPE_MONOTONIC, /* Fixed category index */
45 NANOSECONDS_PER_SECOND, /* Update frequency; needs initialization */
46 0LL, /* Resolution in ns; needs initialization */
47 0LL /* Fixed timebase reference */
52 int64_t clock_api_getres_interval( clockid_t clock_api )
54 /* Initialization helper for POSIX clock implementation; called ONLY
55 * by __clock_api_is_valid(), and triggered by an uninitialized value
56 * of zero (0LL) for the "resolution" field within the implementation
57 * reference data structure; returns the initialized value thereof.
59 if( clock_api->resolution > 0LL )
60 /* Already initialized: immediately return initialized value.
62 return clock_api->resolution;
64 else if( clock_api->resolution == 0LL )
65 /* Not yet initialized: perform type specific initialization.
67 switch( clock_api->type )
69 /* We must be prepared to retrieve clock frequencies from Windows
70 * APIs, which report either LARGE_INTEGER or FILETIME values, but
71 * we prefer to interpret them as scalar int64_t values.
73 union { int64_t value; LARGE_INTEGER qpc_value; FILETIME rtc_value; }
76 case CLOCK_TYPE_REALTIME:
77 /* Clocks in this category use the GetSystemTimeAsFileTime() API
78 * to read the system clock; although this is nominally updated at
79 * 100ns intervals, it is unrealistic to expect resolution at such
80 * a high frequency. Thus, we read it once, then again in a busy
81 * wait loop, until we detect a change, and compute the actual
82 * update interval between the two reported values.
84 GetSystemTimeAsFileTime( &freq.rtc_value );
85 clock_api->resolution = freq.value;
86 do { GetSystemTimeAsFileTime( &freq.rtc_value );
87 } while( freq.value == clock_api->resolution );
88 freq.value -= clock_api->resolution;
90 /* Ultimately, we initialize the effective resolution, converting
91 * from this indicated count of 100ns intervals, to nanoseconds.
93 return clock_api->resolution = freq.value * 100LL;
95 case CLOCK_TYPE_MONOTONIC:
96 /* Clocks in this category use the QueryPerformanceCounter() API
97 * to count arbitrarily scaled time slices, relative to an equally
98 * arbitrary timebase; we must use the QueryPerformanceFrequency()
99 * call to verify availability of this API, and to establish its
100 * update frequency and resolution in nanoseconds.
102 if( QueryPerformanceFrequency( &freq.qpc_value ) && (freq.value > 0LL) )
103 return clock_api->resolution = NANOSECONDS_PER_SECOND
104 / (clock_api->frequency = freq.value);
106 /* In any other case, (implicitly including CLOCK_TYPE_UNIMPLEMENTED),
107 * we may simply fall through to the default error return, (but note
108 * that we specify a "do-nothing" default case handler, to suppress
109 * possible GCC -Wswitch warnings).
114 /* If we get to here, initialization of the specified clock failed; set
115 * its "resolution" to -1LL, thus marking it as unavailable.
117 return clock_api->resolution = ((uint64_t)(clock_api_invalid_error()));
121 clockid_t clock_reference( clockid_t clock_id )
122 { /* Inline helper function to map pseudo-pointer clockid_t entity
123 * references to their actual implementation data references.
125 return ((uintptr_t)(clock_id) & 1)
126 ? & clock_api[(uintptr_t)(clock_id) >> 1]
130 clockid_t __clock_api_is_valid( clockid_t clock_id )
132 /* Helper function, called by any of clock_getres(), clock_gettime(),
133 * or clock_settime(), to check availability of the specified clock,
134 * initializing it if necessary, returning...
136 if( ((clock_id = clock_reference( clock_id )) != NULL)
137 && ((unsigned)(clock_id->type) < CLOCK_TYPE_UNIMPLEMENTED)
138 && (clock_api_getres_interval( clock_id ) > 0LL) )
140 * ...a nominally TRUE value, equivalent to the valid clock_id...
144 /* ...or NULL, (nominally FALSE), and setting "errno", otherwise.
150 /* $RCSfile$: end of file */