Cygwin: flock: Fix overlap handling in lf_setlock() and lf_clearlock()
[newlib-cygwin.git] / winsup / cygwin / clock.cc
blob1c675f0f26c81f93ead7c31f7fd865a55672f64f
1 #include "winsup.h"
2 #include <realtimeapiset.h>
3 #include "pinfo.h"
4 #include "clock.h"
5 #include "miscfuncs.h"
6 #include "spinlock.h"
8 static inline LONGLONG
9 system_qpc_tickspersec ()
11 LARGE_INTEGER qpf;
13 /* ticks per sec */
14 QueryPerformanceFrequency (&qpf);
15 return qpf.QuadPart;
18 static inline LONGLONG
19 system_tickcount_period ()
21 ULONG coarsest = 0, finest, actual;
23 if (!coarsest)
25 /* The actual resolution of the OS timer is a system-wide setting which
26 can be changed any time, by any process. The only fixed value we
27 can rely on is the coarsest value. */
28 NtQueryTimerResolution (&coarsest, &finest, &actual);
30 return coarsest;
33 void inline
34 clk_t::init ()
36 if (!period)
37 InterlockedExchange64 (&period, system_tickcount_period ());
40 void inline
41 clk_realtime_t::init ()
43 if (!ticks_per_sec)
44 InterlockedExchange64 (&ticks_per_sec, system_qpc_tickspersec ());
47 void inline
48 clk_monotonic_t::init ()
50 if (!ticks_per_sec)
51 InterlockedExchange64 (&ticks_per_sec, system_qpc_tickspersec ());
54 int
55 clk_realtime_coarse_t::now (clockid_t clockid, struct timespec *ts)
57 LARGE_INTEGER now;
59 GetSystemTimeAsFileTime ((LPFILETIME) &now);
60 /* Add conversion factor for UNIX vs. Windows base time */
61 now.QuadPart -= FACTOR;
62 ts->tv_sec = now.QuadPart / NS100PERSEC;
63 ts->tv_nsec = (now.QuadPart % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
64 return 0;
67 int
68 clk_realtime_t::now (clockid_t clockid, struct timespec *ts)
70 LARGE_INTEGER now;
72 GetSystemTimePreciseAsFileTime ((LPFILETIME) &now);
73 /* Add conversion factor for UNIX vs. Windows base time */
74 now.QuadPart -= FACTOR;
75 ts->tv_sec = now.QuadPart / NS100PERSEC;
76 ts->tv_nsec = (now.QuadPart % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
77 return 0;
80 int
81 clk_process_t::now (clockid_t clockid, struct timespec *ts)
83 pid_t pid = CLOCKID_TO_PID (clockid);
84 HANDLE hProcess;
85 KERNEL_USER_TIMES kut;
86 int64_t x;
88 if (pid == 0)
89 pid = myself->pid;
91 pinfo p (pid);
92 if (!p || !p->exists ())
94 set_errno (EINVAL);
95 return -1;
98 hProcess = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, 0,
99 p->dwProcessId);
100 NtQueryInformationProcess (hProcess, ProcessTimes,
101 &kut, sizeof kut, NULL);
103 x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
104 ts->tv_sec = x / NS100PERSEC;
105 ts->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
106 CloseHandle (hProcess);
107 return 0;
111 clk_thread_t::now (clockid_t clockid, struct timespec *ts)
113 long thr_id = CLOCKID_TO_THREADID (clockid);
114 HANDLE hThread;
115 KERNEL_USER_TIMES kut;
116 int64_t x;
118 if (thr_id == 0)
119 thr_id = pthread::self ()->getsequence_np ();
121 hThread = OpenThread (THREAD_QUERY_LIMITED_INFORMATION, 0, thr_id);
122 if (!hThread)
124 set_errno (EINVAL);
125 return -1;
128 NtQueryInformationThread (hThread, ThreadTimes,
129 &kut, sizeof kut, NULL);
131 x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
132 ts->tv_sec = x / NS100PERSEC;
133 ts->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
134 CloseHandle (hThread);
135 return 0;
139 clk_monotonic_t::now (clockid_t clockid, struct timespec *ts)
141 if (wincap.has_precise_interrupt_time ())
143 /* Suspend time not taken into account, as on Linux */
144 ULONGLONG now;
146 QueryUnbiasedInterruptTimePrecise (&now);
147 ts->tv_sec = now / NS100PERSEC;
148 now %= NS100PERSEC;
149 ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
151 else
153 /* https://stackoverflow.com/questions/24330496. Skip rounding since
154 its almost always wrong when working with timestamps */
155 UINT64 bias;
156 LARGE_INTEGER now;
157 struct timespec bts;
159 init ();
162 bias = SharedUserData.InterruptTimeBias;
163 QueryPerformanceCounter(&now);
165 while (bias != SharedUserData.InterruptTimeBias);
166 /* Convert perf counter to timespec */
167 ts->tv_sec = now.QuadPart / ticks_per_sec;
168 now.QuadPart %= ticks_per_sec;
169 ts->tv_nsec = (now.QuadPart * NSPERSEC) / ticks_per_sec;
170 /* Convert bias to timespec */
171 bts.tv_sec = bias / NS100PERSEC;
172 bias %= NS100PERSEC;
173 bts.tv_nsec = bias * (NSPERSEC/NS100PERSEC);
174 /* Subtract bias from perf */
175 ts_diff (bts, *ts);
177 return 0;
181 clk_monotonic_coarse_t::now (clockid_t clockid, struct timespec *ts)
183 /* Suspend time not taken into account, as on Linux */
184 ULONGLONG now;
186 QueryUnbiasedInterruptTime (&now);
187 ts->tv_sec = now / NS100PERSEC;
188 now %= NS100PERSEC;
189 ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
190 return 0;
194 clk_boottime_t::now (clockid_t clockid, struct timespec *ts)
196 /* Suspend time taken into account, as on Linux */
197 if (wincap.has_precise_interrupt_time ())
199 ULONGLONG now;
201 QueryInterruptTimePrecise (&now);
202 ts->tv_sec = now / NS100PERSEC;
203 now %= NS100PERSEC;
204 ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
206 else
208 LARGE_INTEGER now;
210 init ();
211 QueryPerformanceCounter (&now);
212 ts->tv_sec = now.QuadPart / ticks_per_sec;
213 now.QuadPart %= ticks_per_sec;
214 ts->tv_nsec = (now.QuadPart * NSPERSEC) / ticks_per_sec;
216 return 0;
219 void
220 clk_t::resolution (struct timespec *ts)
222 init ();
223 ts->tv_sec = 0;
224 ts->tv_nsec = period * (NSPERSEC/NS100PERSEC);
227 void
228 clk_realtime_t::resolution (struct timespec *ts)
230 init ();
231 ts->tv_sec = 0;
232 ts->tv_nsec = NSPERSEC / ticks_per_sec;
235 void
236 clk_monotonic_t::resolution (struct timespec *ts)
238 init ();
239 ts->tv_sec = 0;
240 ts->tv_nsec = NSPERSEC / ticks_per_sec;
243 static clk_realtime_coarse_t clk_realtime_coarse;
244 static clk_realtime_t clk_realtime;
245 static clk_process_t clk_process;
246 static clk_thread_t clk_thread;
247 static clk_monotonic_t clk_monotonic;
248 static clk_monotonic_t clk_monotonic_raw; /* same as clk_monotonic */
249 static clk_monotonic_coarse_t clk_monotonic_coarse;
250 static clk_boottime_t clk_boottime;
251 static clk_realtime_t clk_realtime_alarm; /* same as clk_realtime */
252 static clk_boottime_t clk_boottime_alarm; /* same as clk_boottime_t */
254 clk_t *cyg_clock[MAX_CLOCKS] =
256 &clk_realtime_coarse,
257 &clk_realtime,
258 &clk_process,
259 &clk_thread,
260 &clk_monotonic,
261 &clk_monotonic_raw,
262 &clk_monotonic_coarse,
263 &clk_boottime,
264 &clk_realtime_alarm,
265 &clk_boottime_alarm,
268 clk_t *
269 get_clock (clockid_t clk_id)
271 extern clk_t *cyg_clock[MAX_CLOCKS];
272 clockid_t clockid = CLOCKID (clk_id);
273 if (clk_id >= MAX_CLOCKS
274 && clockid != CLOCK_PROCESS_CPUTIME_ID
275 && clockid != CLOCK_THREAD_CPUTIME_ID)
276 return NULL;
277 return cyg_clock[clockid];