OSDN Git Service

Make clockapi symbolic constants #ifdef detectable.
[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, 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 /* Publicly visible references to the preceding (opaque) clock definitions.
52  */
53 clockid_t const CLOCK_REALTIME = &clock_api[CLOCK_TYPE_REALTIME];
54 clockid_t const CLOCK_MONOTONIC = &clock_api[CLOCK_TYPE_MONOTONIC];
55
56 CLOCK_INLINE
57 int64_t clock_api_getres_interval( clockid_t clock_api )
58 {
59   /* Initialization helper for POSIX clock implementation; called ONLY
60    * by __clock_api_is_valid(), and triggered by an uninitialized value
61    * of zero (0LL) for the "resolution" field within the implementation
62    * reference data structure; returns the initialized value thereof.
63    */
64   if( clock_api->resolution > 0LL )
65     /* Already initialized: immediately return initialized value.
66      */
67     return clock_api->resolution;
68
69   else if( clock_api->resolution == 0LL )
70     /* Not yet initialized: perform type specific initialization.
71      */
72     switch( clock_api->type )
73     {
74       /* We must be prepared to retrieve clock frequencies from Windows
75        * APIs, which report either LARGE_INTEGER or FILETIME values, but
76        * we prefer to interpret them as scalar int64_t values.
77        */
78       union { int64_t value; LARGE_INTEGER qpc_value; FILETIME rtc_value; }
79         freq;
80
81       case CLOCK_TYPE_REALTIME:
82         /* Clocks in this category use the GetSystemTimeAsFileTime() API
83          * to read the system clock; although this is nominally updated at
84          * 100ns intervals, it is unrealistic to expect resolution at such
85          * a high frequency.  Thus, we read it once, then again in a busy
86          * wait loop, until we detect a change, and compute the actual
87          * update interval between the two reported values.
88          */
89         GetSystemTimeAsFileTime( &freq.rtc_value );
90         clock_api->resolution = freq.value;
91         do { GetSystemTimeAsFileTime( &freq.rtc_value );
92            } while( freq.value == clock_api->resolution );
93         freq.value -= clock_api->resolution;
94
95         /* Ultimately, we initialize the effective resolution, converting
96          * from this indicated count of 100ns intervals, to nanoseconds.
97          */
98         return clock_api->resolution = freq.value * 100LL;
99
100       case CLOCK_TYPE_MONOTONIC:
101         /* Clocks in this category use the QueryPerformanceCounter() API
102          * to count arbitrarily scaled time slices, relative to an equally
103          * arbitrary timebase; we must use the QueryPerformanceFrequency()
104          * call to verify availability of this API, and to establish its
105          * update frequency and resolution in nanoseconds.
106          */
107         if( QueryPerformanceFrequency( &freq.qpc_value ) && (freq.value > 0LL) )
108           return clock_api->resolution = NANOSECONDS_PER_SECOND
109             / (clock_api->frequency = freq.value);
110     }
111
112   /* If we get to here, initialization of the specified clock failed; set
113    * its "resolution" to -1LL, thus marking it as unavailable.
114    */
115   return clock_api->resolution = ((uint64_t)(clock_api_invalid_error()));
116 }
117
118 int __clock_api_is_valid( clockid_t clock_id )
119 {
120   /* Helper function, called by any of clock_getres(), clock_gettime(),
121    * or clock_settime(), to check availability of the specified clock,
122    * initializing it if necessary, returning...
123    */
124   if(  (clock_id != NULL)
125   &&  ((unsigned)(clock_id->type) < CLOCK_TYPE_UNIMPLEMENTED)
126   &&   (clock_api_getres_interval( clock_id ) > 0LL)  )
127     /*
128      * ...a nominally TRUE value of 1, in the case of a valid clock...
129      */
130     return 1;
131
132   /* ...or FALSE (zero), and setting "errno", otherwise.
133    */
134   errno = EINVAL;
135   return 0;
136 }
137
138 /* $RCSfile$: end of file */