• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * This file has no copyright assigned and is placed in the Public Domain.
3  * This file is part of the w64 mingw-runtime package.
4  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5  */
6 
7 #include <errno.h>
8 #include <stdint.h>
9 #include <time.h>
10 #include <windows.h>
11 #ifndef IN_WINPTHREAD
12 #define IN_WINPTHREAD 1
13 #endif
14 #include "pthread.h"
15 #include "pthread_time.h"
16 
17 #define POW10_7                 10000000
18 #define POW10_9                 1000000000
19 
20 /* Number of 100ns-seconds between the beginning of the Windows epoch
21  * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970)
22  */
23 #define DELTA_EPOCH_IN_100NS    INT64_C(116444736000000000)
24 
lc_set_errno(int result)25 static WINPTHREADS_INLINE int lc_set_errno(int result)
26 {
27     if (result != 0) {
28         errno = result;
29         return -1;
30     }
31     return 0;
32 }
33 
34 /**
35  * Get the resolution of the specified clock clock_id and
36  * stores it in the struct timespec pointed to by res.
37  * @param  clock_id The clock_id argument is the identifier of the particular
38  *         clock on which to act. The following clocks are supported:
39  * <pre>
40  *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
41  *                 requires appropriate privileges.
42  *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
43  *                 time since some unspecified starting point.
44  *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
45  *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
46  * </pre>
47  * @param  res The pointer to a timespec structure to receive the time
48  *         resolution.
49  * @return If the function succeeds, the return value is 0.
50  *         If the function fails, the return value is -1,
51  *         with errno set to indicate the error.
52  */
clock_getres(clockid_t clock_id,struct timespec * res)53 int clock_getres(clockid_t clock_id, struct timespec *res)
54 {
55     switch(clock_id) {
56     case CLOCK_MONOTONIC:
57         {
58             LARGE_INTEGER pf;
59 
60             if (QueryPerformanceFrequency(&pf) == 0)
61                 return lc_set_errno(EINVAL);
62 
63             res->tv_sec = 0;
64             res->tv_nsec = (int) ((POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
65             if (res->tv_nsec < 1)
66                 res->tv_nsec = 1;
67 
68             return 0;
69         }
70 
71     case CLOCK_REALTIME:
72     case CLOCK_PROCESS_CPUTIME_ID:
73     case CLOCK_THREAD_CPUTIME_ID:
74         {
75             DWORD   timeAdjustment, timeIncrement;
76             BOOL    isTimeAdjustmentDisabled;
77 
78             (void) GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &isTimeAdjustmentDisabled);
79             res->tv_sec = 0;
80             res->tv_nsec = timeIncrement * 100;
81 
82             return 0;
83         }
84     default:
85         break;
86     }
87 
88     return lc_set_errno(EINVAL);
89 }
90 
91 /**
92  * Get the time of the specified clock clock_id and stores it in the struct
93  * timespec pointed to by tp.
94  * @param  clock_id The clock_id argument is the identifier of the particular
95  *         clock on which to act. The following clocks are supported:
96  * <pre>
97  *     CLOCK_REALTIME  System-wide real-time clock. Setting this clock
98  *                 requires appropriate privileges.
99  *     CLOCK_MONOTONIC Clock that cannot be set and represents monotonic
100  *                 time since some unspecified starting point.
101  *     CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU.
102  *     CLOCK_THREAD_CPUTIME_ID  Thread-specific CPU-time clock.
103  * </pre>
104  * @param  tp The pointer to a timespec structure to receive the time.
105  * @return If the function succeeds, the return value is 0.
106  *         If the function fails, the return value is -1,
107  *         with errno set to indicate the error.
108  */
clock_gettime(clockid_t clock_id,struct timespec * tp)109 int clock_gettime(clockid_t clock_id, struct timespec *tp)
110 {
111     unsigned __int64 t;
112     LARGE_INTEGER pf, pc;
113     union {
114         unsigned __int64 u64;
115         FILETIME ft;
116     }  ct, et, kt, ut;
117 
118     switch(clock_id) {
119     case CLOCK_REALTIME:
120         {
121             GetSystemTimeAsFileTime(&ct.ft);
122             t = ct.u64 - DELTA_EPOCH_IN_100NS;
123             tp->tv_sec = t / POW10_7;
124             tp->tv_nsec = ((int) (t % POW10_7)) * 100;
125 
126             return 0;
127         }
128 
129     case CLOCK_MONOTONIC:
130         {
131             if (QueryPerformanceFrequency(&pf) == 0)
132                 return lc_set_errno(EINVAL);
133 
134             if (QueryPerformanceCounter(&pc) == 0)
135                 return lc_set_errno(EINVAL);
136 
137             tp->tv_sec = pc.QuadPart / pf.QuadPart;
138             tp->tv_nsec = (int) (((pc.QuadPart % pf.QuadPart) * POW10_9 + (pf.QuadPart >> 1)) / pf.QuadPart);
139             if (tp->tv_nsec >= POW10_9) {
140                 tp->tv_sec ++;
141                 tp->tv_nsec -= POW10_9;
142             }
143 
144             return 0;
145         }
146 
147     case CLOCK_PROCESS_CPUTIME_ID:
148         {
149         if(0 == GetProcessTimes(GetCurrentProcess(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
150             return lc_set_errno(EINVAL);
151         t = kt.u64 + ut.u64;
152         tp->tv_sec = t / POW10_7;
153         tp->tv_nsec = ((int) (t % POW10_7)) * 100;
154 
155         return 0;
156         }
157 
158     case CLOCK_THREAD_CPUTIME_ID:
159         {
160             if(0 == GetThreadTimes(GetCurrentThread(), &ct.ft, &et.ft, &kt.ft, &ut.ft))
161                 return lc_set_errno(EINVAL);
162             t = kt.u64 + ut.u64;
163             tp->tv_sec = t / POW10_7;
164             tp->tv_nsec = ((int) (t % POW10_7)) * 100;
165 
166             return 0;
167         }
168 
169     default:
170         break;
171     }
172 
173     return lc_set_errno(EINVAL);
174 }
175 
176 /**
177  * Sleep for the specified time.
178  * @param  clock_id This argument should always be CLOCK_REALTIME (0).
179  * @param  flags 0 for relative sleep interval, others for absolute waking up.
180  * @param  request The desired sleep interval or absolute waking up time.
181  * @param  remain The remain amount of time to sleep.
182  *         The current implemention just ignore it.
183  * @return If the function succeeds, the return value is 0.
184  *         If the function fails, the return value is -1,
185  *         with errno set to indicate the error.
186  */
clock_nanosleep(clockid_t clock_id,int flags,const struct timespec * request,struct timespec * remain)187 int clock_nanosleep(clockid_t clock_id, int flags,
188                            const struct timespec *request,
189                            struct timespec *remain)
190 {
191     struct timespec tp;
192 
193     if (clock_id != CLOCK_REALTIME)
194         return lc_set_errno(EINVAL);
195 
196     if (flags == 0)
197         return nanosleep(request, remain);
198 
199     /* TIMER_ABSTIME = 1 */
200     clock_gettime(CLOCK_REALTIME, &tp);
201 
202     tp.tv_sec = request->tv_sec - tp.tv_sec;
203     tp.tv_nsec = request->tv_nsec - tp.tv_nsec;
204     if (tp.tv_nsec < 0) {
205         tp.tv_nsec += POW10_9;
206         tp.tv_sec --;
207     }
208 
209     return nanosleep(&tp, remain);
210 }
211 
212 /**
213  * Set the time of the specified clock clock_id.
214  * @param  clock_id This argument should always be CLOCK_REALTIME (0).
215  * @param  tp The requested time.
216  * @return If the function succeeds, the return value is 0.
217  *         If the function fails, the return value is -1,
218  *         with errno set to indicate the error.
219  */
clock_settime(clockid_t clock_id,const struct timespec * tp)220 int clock_settime(clockid_t clock_id, const struct timespec *tp)
221 {
222     SYSTEMTIME st;
223 
224     union {
225         unsigned __int64 u64;
226         FILETIME ft;
227     }  t;
228 
229     if (clock_id != CLOCK_REALTIME)
230         return lc_set_errno(EINVAL);
231 
232     t.u64 = tp->tv_sec * (__int64) POW10_7 + tp->tv_nsec / 100 + DELTA_EPOCH_IN_100NS;
233     if (FileTimeToSystemTime(&t.ft, &st) == 0)
234         return lc_set_errno(EINVAL);
235 
236     if (SetSystemTime(&st) == 0)
237         return lc_set_errno(EPERM);
238 
239     return 0;
240 }
241