OSDN Git Service

9d122aed125c11834f6ffefa472cbb59def9a7f0
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / clockapi.c
1 /*
2  * clockapi.c
3  *
4  * Implementation of the common elements of the POSIX clock API.
5  *
6  * $Id$
7  *
8  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
9  * Copyright (C) 2017, 2018, MinGW.org Project
10  *
11  *
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:
18  *
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
21  * Software.
22  *
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.
30  *
31  */
32 #include "clockapi.h"
33
34 static struct __clockid__ clock_api[] =
35 { { /* CLOCK_REALTIME pre-initialization implementation reference data.
36      */
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 */
41   },
42   { /* CLOCK_MONOTONIC pre-initialization implementation reference data.
43      */
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 */
48   }
49 };
50
51 CLOCK_INLINE
52 int64_t clock_api_getres_interval( clockid_t clock_api )
53 {
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.
58    */
59   if( clock_api->resolution > 0LL )
60     /* Already initialized: immediately return initialized value.
61      */
62     return clock_api->resolution;
63
64   else if( clock_api->resolution == 0LL )
65     /* Not yet initialized: perform type specific initialization.
66      */
67     switch( clock_api->type )
68     {
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.
72        */
73       union { int64_t value; LARGE_INTEGER qpc_value; FILETIME rtc_value; }
74         freq;
75
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.
83          */
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;
89
90         /* Ultimately, we initialize the effective resolution, converting
91          * from this indicated count of 100ns intervals, to nanoseconds.
92          */
93         return clock_api->resolution = freq.value * 100LL;
94
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.
101          */
102         if( QueryPerformanceFrequency( &freq.qpc_value ) && (freq.value > 0LL) )
103           return clock_api->resolution = NANOSECONDS_PER_SECOND
104             / (clock_api->frequency = freq.value);
105
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).
110        */
111       default: break;
112     }
113
114   /* If we get to here, initialization of the specified clock failed; set
115    * its "resolution" to -1LL, thus marking it as unavailable.
116    */
117   return clock_api->resolution = ((uint64_t)(clock_api_invalid_error()));
118 }
119
120 CLOCK_INLINE
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.
124    */
125   return ((uintptr_t)(clock_id) & 1)
126     ? & clock_api[(uintptr_t)(clock_id) >> 1]
127     : clock_id;
128 }
129
130 clockid_t __clock_api_is_valid( clockid_t clock_id )
131 {
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...
135    */
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)  )
139     /*
140      * ...a nominally TRUE value, equivalent to the valid clock_id...
141      */
142     return clock_id;
143
144   /* ...or NULL, (nominally FALSE), and setting "errno", otherwise.
145    */
146   errno = EINVAL;
147   return NULL;
148 }
149
150 /* $RCSfile$: end of file */