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