OSDN Git Service

* path.cc (conv_path_list): Take cygwin_conv_path_t as third parameter.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / times.cc
1 /* times.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #define __timezonefunc__
13 #include "winsup.h"
14 #include <sys/times.h>
15 #include <sys/timeb.h>
16 #include <utime.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include "cygerrno.h"
20 #include "security.h"
21 #include "path.h"
22 #include "fhandler.h"
23 #include "dtable.h"
24 #include "cygheap.h"
25 #include "pinfo.h"
26 #include "thread.h"
27 #include "cygtls.h"
28 #include "ntdll.h"
29
30 /* Max allowed diversion in 100ns of internal timer from system time.  If
31    this difference is exceeded, the internal timer gets re-primed. */
32 #define JITTER (40 * 10000LL)
33
34 /* TODO: Putting this variable in the shared cygwin region partially solves
35    the problem of cygwin processes not recognizing date changes when other
36    cygwin processes set the date.  There is still an additional problem of
37    long-running cygwin processes becoming confused when a non-cygwin process
38    sets the date.  Unfortunately, it looks like a minor redesign is required
39    to handle that case.  */
40 hires_ms gtod __attribute__((section (".cygwin_dll_common"), shared));
41
42 hires_ns NO_COPY ntod;
43
44 static inline LONGLONG
45 systime_ns ()
46 {
47   LARGE_INTEGER x;
48   GetSystemTimeAsFileTime ((LPFILETIME) &x);
49   x.QuadPart -= FACTOR;         /* Add conversion factor for UNIX vs. Windows base time */
50   return x.QuadPart;
51 }
52
53 /* Cygwin internal */
54 static unsigned long long __stdcall
55 __to_clock_t (FILETIME *src, int flag)
56 {
57   unsigned long long total = ((unsigned long long) src->dwHighDateTime << 32) + ((unsigned)src->dwLowDateTime);
58   syscall_printf ("dwHighDateTime %u, dwLowDateTime %u", src->dwHighDateTime, src->dwLowDateTime);
59
60   /* Convert into clock ticks - the total is in 10ths of a usec.  */
61   if (flag)
62     total -= FACTOR;
63
64   total /= (unsigned long long) (NSPERSEC / CLOCKS_PER_SEC);
65   syscall_printf ("total %08x %08x", (unsigned) (total>>32), (unsigned) (total));
66   return total;
67 }
68
69 /* times: POSIX 4.5.2.1 */
70 extern "C" clock_t
71 times (struct tms *buf)
72 {
73   FILETIME creation_time, exit_time, kernel_time, user_time;
74
75   myfault efault;
76   if (efault.faulted (EFAULT))
77     return ((clock_t) -1);
78
79   LONGLONG ticks = gtod.uptime ();
80   /* Ticks is in milliseconds, convert to our ticks. Use long long to prevent
81      overflow. */
82   clock_t tc = (clock_t) (ticks * CLOCKS_PER_SEC / 1000);
83
84   GetProcessTimes (GetCurrentProcess (), &creation_time, &exit_time,
85                    &kernel_time, &user_time);
86
87   syscall_printf ("ticks %d, CLOCKS_PER_SEC %d", ticks, CLOCKS_PER_SEC);
88   syscall_printf ("user_time %d, kernel_time %d, creation_time %d, exit_time %d",
89                   user_time, kernel_time, creation_time, exit_time);
90   buf->tms_stime = __to_clock_t (&kernel_time, 0);
91   buf->tms_utime = __to_clock_t (&user_time, 0);
92   timeval_to_filetime (&myself->rusage_children.ru_stime, &kernel_time);
93   buf->tms_cstime = __to_clock_t (&kernel_time, 1);
94   timeval_to_filetime (&myself->rusage_children.ru_utime, &user_time);
95   buf->tms_cutime = __to_clock_t (&user_time, 1);
96
97   return tc;
98 }
99
100 EXPORT_ALIAS (times, _times)
101
102 /* settimeofday: BSD */
103 extern "C" int
104 settimeofday (const struct timeval *tv, const struct timezone *tz)
105 {
106   SYSTEMTIME st;
107   struct tm *ptm;
108   int res;
109
110   myfault efault;
111   if (efault.faulted (EFAULT))
112     return -1;
113
114   if (tv->tv_usec < 0 || tv->tv_usec >= 1000000)
115     {
116       set_errno (EINVAL);
117       return -1;
118     }
119
120   ptm = gmtime (&tv->tv_sec);
121   st.wYear         = ptm->tm_year + 1900;
122   st.wMonth        = ptm->tm_mon + 1;
123   st.wDayOfWeek    = ptm->tm_wday;
124   st.wDay          = ptm->tm_mday;
125   st.wHour         = ptm->tm_hour;
126   st.wMinute       = ptm->tm_min;
127   st.wSecond       = ptm->tm_sec;
128   st.wMilliseconds = tv->tv_usec / 1000;
129
130   res = -!SetSystemTime (&st);
131   gtod.reset ();
132
133   syscall_printf ("%d = settimeofday (%x, %x)", res, tv, tz);
134
135   if (res != 0)
136     set_errno (EPERM);
137
138   return res;
139 }
140
141 /* timezone: standards? */
142 extern "C" char *
143 timezone (void)
144 {
145   char *b = _my_tls.locals.timezone_buf;
146
147   tzset ();
148   __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs (_timezone / 60) % 60));
149   return b;
150 }
151
152 /* Cygwin internal */
153 void __stdcall
154 totimeval (struct timeval *dst, FILETIME *src, int sub, int flag)
155 {
156   long long x = __to_clock_t (src, flag);
157
158   x *= (int) (1e6) / CLOCKS_PER_SEC; /* Turn x into usecs */
159   x -= (long long) sub * (int) (1e6);
160
161   dst->tv_usec = x % (long long) (1e6); /* And split */
162   dst->tv_sec = x / (long long) (1e6);
163 }
164
165 /* FIXME: Make thread safe */
166 extern "C" int
167 gettimeofday (struct timeval *tv, void *tzvp)
168 {
169   struct timezone *tz = (struct timezone *) tzvp;
170   static bool tzflag;
171   LONGLONG now = gtod.usecs ();
172
173   if (now == (LONGLONG) -1)
174     return -1;
175
176   tv->tv_sec = now / 1000000;
177   tv->tv_usec = now % 1000000;
178
179   if (tz != NULL)
180     {
181       if (!tzflag)
182         {
183           tzset ();
184           tzflag = true;
185         }
186       tz->tz_minuteswest = _timezone / 60;
187       tz->tz_dsttime = _daylight;
188     }
189
190   return 0;
191 }
192
193 EXPORT_ALIAS (gettimeofday, _gettimeofday)
194
195 /* Cygwin internal */
196 void
197 time_t_to_filetime (time_t time_in, FILETIME *out)
198 {
199   long long x = time_in * NSPERSEC + FACTOR;
200   out->dwHighDateTime = x >> 32;
201   out->dwLowDateTime = x;
202 }
203
204 /* Cygwin internal */
205 void __stdcall
206 timespec_to_filetime (const struct timespec *time_in, FILETIME *out)
207 {
208   if (time_in->tv_nsec == UTIME_OMIT)
209     out->dwHighDateTime = out->dwLowDateTime = 0;
210   else
211     {
212       long long x = time_in->tv_sec * NSPERSEC +
213                             time_in->tv_nsec / (1000000000/NSPERSEC) + FACTOR;
214       out->dwHighDateTime = x >> 32;
215       out->dwLowDateTime = x;
216     }
217 }
218
219 /* Cygwin internal */
220 void __stdcall
221 timeval_to_filetime (const struct timeval *time_in, FILETIME *out)
222 {
223   long long x = time_in->tv_sec * NSPERSEC +
224                         time_in->tv_usec * (NSPERSEC/1000000) + FACTOR;
225   out->dwHighDateTime = x >> 32;
226   out->dwLowDateTime = x;
227 }
228
229 /* Cygwin internal */
230 static timeval __stdcall
231 time_t_to_timeval (time_t in)
232 {
233   timeval res;
234   res.tv_sec = in;
235   res.tv_usec = 0;
236   return res;
237 }
238
239 /* Cygwin internal */
240 static const struct timespec *
241 timeval_to_timespec (const struct timeval *tvp, struct timespec *tmp)
242 {
243   if (!tvp)
244     return NULL;
245
246   tmp[0].tv_sec = tvp[0].tv_sec;
247   tmp[0].tv_nsec = tvp[0].tv_usec * 1000;
248   if (tmp[0].tv_nsec < 0)
249     tmp[0].tv_nsec = 0;
250   else if (tmp[0].tv_nsec > 999999999)
251     tmp[0].tv_nsec = 999999999;
252
253   tmp[1].tv_sec = tvp[1].tv_sec;
254   tmp[1].tv_nsec = tvp[1].tv_usec * 1000;
255   if (tmp[1].tv_nsec < 0)
256     tmp[1].tv_nsec = 0;
257   else if (tmp[1].tv_nsec > 999999999)
258     tmp[1].tv_nsec = 999999999;
259
260   return tmp;
261 }
262
263 /* Cygwin internal */
264 /* Convert a Win32 time to "UNIX" format. */
265 long __stdcall
266 to_time_t (FILETIME *ptr)
267 {
268   /* A file time is the number of 100ns since jan 1 1601
269      stuffed into two long words.
270      A time_t is the number of seconds since jan 1 1970.  */
271
272   long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
273
274   /* pass "no time" as epoch */
275   if (x == 0)
276     return 0;
277
278   x -= FACTOR;                  /* number of 100ns between 1601 and 1970 */
279   x /= (long long) NSPERSEC;            /* number of 100ns in a second */
280   return x;
281 }
282
283 /* Cygwin internal */
284 /* Convert a Win32 time to "UNIX" timestruc_t format. */
285 void __stdcall
286 to_timestruc_t (FILETIME *ptr, timestruc_t *out)
287 {
288   /* A file time is the number of 100ns since jan 1 1601
289      stuffed into two long words.
290      A timestruc_t is the number of seconds and microseconds since jan 1 1970
291      stuffed into a time_t and a long.  */
292
293   long rem;
294   long long x = ((long long) ptr->dwHighDateTime << 32) + ((unsigned)ptr->dwLowDateTime);
295
296   /* pass "no time" as epoch */
297   if (x == 0)
298     {
299       out->tv_sec = 0;
300       out->tv_nsec = 0;
301       return;
302     }
303
304   x -= FACTOR;                  /* number of 100ns between 1601 and 1970 */
305   rem = x % ((long long)NSPERSEC);
306   x /= (long long) NSPERSEC;            /* number of 100ns in a second */
307   out->tv_nsec = rem * 100;     /* as tv_nsec is in nanoseconds */
308   out->tv_sec = x;
309 }
310
311 /* Cygwin internal */
312 /* Get the current time as a "UNIX" timestruc_t format. */
313 void __stdcall
314 time_as_timestruc_t (timestruc_t * out)
315 {
316   FILETIME filetime;
317
318   GetSystemTimeAsFileTime (&filetime);
319   to_timestruc_t (&filetime, out);
320 }
321
322 /* time: POSIX 4.5.1.1, C 4.12.2.4 */
323 /* Return number of seconds since 00:00 UTC on jan 1, 1970 */
324 extern "C" time_t
325 time (time_t * ptr)
326 {
327   time_t res;
328   FILETIME filetime;
329
330   GetSystemTimeAsFileTime (&filetime);
331   res = to_time_t (&filetime);
332   if (ptr)
333     *ptr = res;
334
335   syscall_printf ("%d = time (%x)", res, ptr);
336
337   return res;
338 }
339
340 int
341 utimens_worker (path_conv &win32, const struct timespec *tvp)
342 {
343   int res = -1;
344
345   if (win32.error)
346     set_errno (win32.error);
347   else
348     {
349       fhandler_base *fh = NULL;
350       bool fromfd = false;
351
352       cygheap_fdenum cfd (true);
353       while (cfd.next () >= 0)
354         if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE)
355             && RtlEqualUnicodeString (cfd->pc.get_nt_native_path (),
356                                       win32.get_nt_native_path (),
357                                       cfd->pc.objcaseinsensitive ()))
358           {
359             fh = cfd;
360             fromfd = true;
361             break;
362           }
363
364       if (!fh)
365         {
366           if (!(fh = build_fh_pc (win32)))
367             goto error;
368
369           if (fh->error ())
370             {
371               debug_printf ("got %d error from build_fh_pc", fh->error ());
372               set_errno (fh->error ());
373             }
374         }
375
376       res = fh->utimens (tvp);
377
378       if (!fromfd)
379         delete fh;
380     }
381
382 error:
383   syscall_printf ("%d = utimes (%S, %p)",
384                   res, win32.get_nt_native_path (), tvp);
385   return res;
386 }
387
388 /* utimes: POSIX/SUSv3 */
389 extern "C" int
390 utimes (const char *path, const struct timeval *tvp)
391 {
392   path_conv win32 (path, PC_POSIX | PC_SYM_FOLLOW, stat_suffixes);
393   struct timespec tmp[2];
394   return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
395 }
396
397 /* BSD */
398 extern "C" int
399 lutimes (const char *path, const struct timeval *tvp)
400 {
401   path_conv win32 (path, PC_POSIX | PC_SYM_NOFOLLOW, stat_suffixes);
402   struct timespec tmp[2];
403   return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
404 }
405
406 /* futimens: POSIX/SUSv4 */
407 extern "C" int
408 futimens (int fd, const struct timespec *tvp)
409 {
410   int res;
411
412   cygheap_fdget cfd (fd);
413   if (cfd < 0)
414     res = -1;
415   else if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE))
416     res = cfd->utimens (tvp);
417   else
418     res = utimens_worker (cfd->pc, tvp);
419   syscall_printf ("%d = futimens (%d, %p)", res, fd, tvp);
420   return res;
421 }
422
423 /* BSD */
424 extern "C" int
425 futimes (int fd, const struct timeval *tvp)
426 {
427   struct timespec tmp[2];
428   return futimens (fd,  timeval_to_timespec (tvp, tmp));
429 }
430
431 /* utime: POSIX 5.6.6.1 */
432 extern "C" int
433 utime (const char *path, const struct utimbuf *buf)
434 {
435   struct timeval tmp[2];
436
437   if (buf == 0)
438     return utimes (path, 0);
439
440   debug_printf ("incoming utime act %x", buf->actime);
441   tmp[0] = time_t_to_timeval (buf->actime);
442   tmp[1] = time_t_to_timeval (buf->modtime);
443
444   return utimes (path, tmp);
445 }
446
447 /* ftime: standards? */
448 extern "C" int
449 ftime (struct timeb *tp)
450 {
451   struct timeval tv;
452   struct timezone tz;
453
454   if (gettimeofday (&tv, &tz) < 0)
455     return -1;
456
457   tp->time = tv.tv_sec;
458   tp->millitm = tv.tv_usec / 1000;
459   tp->timezone = tz.tz_minuteswest;
460   tp->dstflag = tz.tz_dsttime;
461
462   return 0;
463 }
464
465 #define stupid_printf if (cygwin_finished_initializing) debug_printf
466 void
467 hires_ns::prime ()
468 {
469   LARGE_INTEGER ifreq;
470   if (!QueryPerformanceFrequency (&ifreq))
471     {
472       inited = -1;
473       return;
474     }
475
476   int priority = GetThreadPriority (GetCurrentThread ());
477
478   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
479   if (!QueryPerformanceCounter (&primed_pc))
480     {
481       SetThreadPriority (GetCurrentThread (), priority);
482       inited = -1;
483       return;
484     }
485
486   freq = (double) ((double) 1000000000. / (double) ifreq.QuadPart);
487   inited = true;
488   SetThreadPriority (GetCurrentThread (), priority);
489 }
490
491 LONGLONG
492 hires_ns::nsecs ()
493 {
494   if (!inited)
495     prime ();
496   if (inited < 0)
497     {
498       set_errno (ENOSYS);
499       return (long long) -1;
500     }
501
502   LARGE_INTEGER now;
503   if (!QueryPerformanceCounter (&now))
504     {
505       set_errno (ENOSYS);
506       return -1;
507     }
508
509   // FIXME: Use round() here?
510   now.QuadPart = (LONGLONG) (freq * (double) (now.QuadPart - primed_pc.QuadPart));
511   return now.QuadPart;
512 }
513
514 LONGLONG
515 hires_ms::timeGetTime_ns ()
516 {
517   LARGE_INTEGER t;
518
519   /* This is how timeGetTime is implemented in winmm.dll.
520      The real timeGetTime subtracts and adds some values which are constant
521      over the lifetime of the process.  Since we don't need absolute accuracy
522      of the value returned by timeGetTime, only relative accuracy, we can skip
523      this step.  However, if we ever find out that we need absolute accuracy,
524      here's how it works in it's full beauty:
525
526      - At process startup, winmm initializes two calibration values:
527
528        DWORD tick_count_start;
529        LARGE_INTEGER int_time_start;
530        do
531          {
532            tick_count_start = GetTickCount ();
533            do
534              {
535                int_time_start.HighPart = SharedUserData.InterruptTime.High1Time;
536                int_time_start.LowPart = SharedUserData.InterruptTime.LowPart;
537              }
538            while (int_time_start.HighPart
539                   != SharedUserData.InterruptTime.High2Time);
540          }
541        while (tick_count_start != GetTickCount ();
542
543      - timeGetTime computes its return value in the loop as below, and then:
544
545        t.QuadPart -= int_time_start.QuadPart;
546        t.QuadPart /= 10000;
547        t.LowPart += tick_count_start;
548        return t.LowPart;
549   */
550   do
551     {
552       t.HighPart = SharedUserData.InterruptTime.High1Time;
553       t.LowPart = SharedUserData.InterruptTime.LowPart;
554     }
555   while (t.HighPart != SharedUserData.InterruptTime.High2Time);
556   /* We use the value in full 100ns resolution in the calling functions
557      anyway, so we can skip dividing by 10000 here. */
558   return t.QuadPart;
559 }
560
561 void
562 hires_ms::prime ()
563 {
564   if (!inited)
565     {
566       int priority = GetThreadPriority (GetCurrentThread ());
567       SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
568       initime_ns = systime_ns () - timeGetTime_ns ();
569       inited = true;
570       SetThreadPriority (GetCurrentThread (), priority);
571     }
572   return;
573 }
574
575 LONGLONG
576 hires_ms::nsecs ()
577 {
578   if (!inited)
579     prime ();
580
581   LONGLONG t = systime_ns ();
582   LONGLONG res = initime_ns + timeGetTime_ns ();
583   if (llabs (res - t) > JITTER)
584     {
585       inited = false;
586       prime ();
587       res = initime_ns + timeGetTime_ns ();
588     }
589   return res;
590 }
591
592 extern "C" int
593 clock_gettime (clockid_t clk_id, struct timespec *tp)
594 {
595   if (CLOCKID_IS_PROCESS (clk_id))
596     {
597       pid_t pid = CLOCKID_TO_PID (clk_id);
598       HANDLE hProcess;
599       KERNEL_USER_TIMES kut;
600       ULONG sizeof_kut = sizeof (KERNEL_USER_TIMES);
601       long long x;
602
603       if (pid == 0)
604         pid = getpid ();
605
606       pinfo p (pid);
607       if (!p->exists ())
608         {
609           set_errno (EINVAL);
610           return -1;
611         }
612
613       hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, 0, p->dwProcessId);
614       NtQueryInformationProcess (hProcess, ProcessTimes, &kut, sizeof_kut, &sizeof_kut);
615
616       x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
617       tp->tv_sec = x / (long long) NSPERSEC;
618       tp->tv_nsec = (x % (long long) NSPERSEC) * 100LL;
619
620       CloseHandle (hProcess);
621       return 0;
622     }
623
624   if (CLOCKID_IS_THREAD (clk_id))
625     {
626       long thr_id = CLOCKID_TO_THREADID (clk_id);
627       HANDLE hThread;
628       KERNEL_USER_TIMES kut;
629       ULONG sizeof_kut = sizeof (KERNEL_USER_TIMES);
630       long long x;
631
632       if (thr_id == 0)
633         thr_id = pthread::self ()->getsequence_np ();
634
635       hThread = OpenThread (THREAD_QUERY_INFORMATION, 0, thr_id);
636       if (!hThread)
637         {
638           set_errno (EINVAL);
639           return -1;
640         }
641
642       NtQueryInformationThread (hThread, ThreadTimes, &kut, sizeof_kut, &sizeof_kut);
643
644       x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
645       tp->tv_sec = x / (long long) NSPERSEC;
646       tp->tv_nsec = (x % (long long) NSPERSEC) * 100LL;
647
648       CloseHandle (hThread);
649       return 0;
650     }
651
652   switch (clk_id)
653     {
654       case CLOCK_REALTIME:
655         {
656           LONGLONG now = gtod.nsecs ();
657           if (now == (LONGLONG) -1)
658             return -1;
659           tp->tv_sec = now / NSPERSEC;
660           tp->tv_nsec = (now % NSPERSEC) * (1000000000 / NSPERSEC);
661           break;
662         }
663
664       case CLOCK_MONOTONIC:
665         {
666           LONGLONG now = ntod.nsecs ();
667           if (now == (LONGLONG) -1)
668             return -1;
669
670           tp->tv_sec = now / 1000000000;
671           tp->tv_nsec = (now % 1000000000);
672           break;
673         }
674
675       default:
676         set_errno (EINVAL);
677         return -1;
678     }
679
680   return 0;
681 }
682
683 extern "C" int
684 clock_settime (clockid_t clk_id, const struct timespec *tp)
685 {
686   struct timeval tv;
687
688   if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id))
689     /* According to POSIX, the privileges to set a particular clock
690      * are implementation-defined.  On Linux, CPU-time clocks are not
691      * settable; do the same here.
692      */
693     {
694       set_errno (EPERM);
695       return -1;
696     }
697
698   if (clk_id != CLOCK_REALTIME)
699     {
700       set_errno (EINVAL);
701       return -1;
702     }
703
704   tv.tv_sec = tp->tv_sec;
705   tv.tv_usec = tp->tv_nsec / 1000;
706
707   return settimeofday (&tv, NULL);
708 }
709
710 static DWORD minperiod; // FIXME: Maintain period after a fork.
711
712 LONGLONG
713 hires_ns::resolution ()
714 {
715   if (!inited)
716     prime ();
717   if (inited < 0)
718     {
719       set_errno (ENOSYS);
720       return (long long) -1;
721     }
722
723   return (LONGLONG) freq;
724 }
725
726 UINT
727 hires_ms::resolution ()
728 {
729   if (!minperiod)
730     {
731       NTSTATUS status;
732       ULONG coarsest, finest, actual;
733
734       status = NtQueryTimerResolution (&coarsest, &finest, &actual);
735       if (NT_SUCCESS (status))
736         minperiod = (DWORD) actual;
737       else
738         {
739           /* Try to empirically determine current timer resolution */
740           int priority = GetThreadPriority (GetCurrentThread ());
741           SetThreadPriority (GetCurrentThread (),
742                              THREAD_PRIORITY_TIME_CRITICAL);
743           LONGLONG period = 0;
744           for (int i = 0; i < 4; i++)
745             {
746               LONGLONG now;
747               LONGLONG then = timeGetTime_ns ();
748               while ((now = timeGetTime_ns ()) == then)
749                 continue;
750               then = now;
751               while ((now = timeGetTime_ns ()) == then)
752                 continue;
753               period += now - then;
754             }
755           SetThreadPriority (GetCurrentThread (), priority);
756           period /= 4L;
757           minperiod = (DWORD) period;
758         }
759     }
760   return minperiod;
761 }
762
763 extern "C" int
764 clock_getres (clockid_t clk_id, struct timespec *tp)
765 {
766   if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id))
767     {
768       ULONG coarsest, finest, actual;
769
770       NtQueryTimerResolution (&coarsest, &finest, &actual);
771       tp->tv_sec = coarsest / NSPERSEC;
772       tp->tv_nsec = (coarsest % NSPERSEC) * 100;
773       return 0;
774     }
775
776   switch (clk_id)
777     {
778       case CLOCK_REALTIME:
779         {
780           DWORD period = gtod.resolution ();
781           tp->tv_sec = period / NSPERSEC;
782           tp->tv_nsec = (period % NSPERSEC) * 100;
783           break;
784         }
785
786       case CLOCK_MONOTONIC:
787         {
788           LONGLONG period = ntod.resolution ();
789           tp->tv_sec = period / 1000000000;
790           tp->tv_nsec = period % 1000000000;
791           break;
792         }
793
794       default:
795         set_errno (EINVAL);
796         return -1;
797     }
798
799   return 0;
800 }
801
802 extern "C" int
803 clock_setres (clockid_t clk_id, struct timespec *tp)
804 {
805   static NO_COPY bool period_set;
806   int status;
807
808   if (clk_id != CLOCK_REALTIME)
809     {
810       set_errno (EINVAL);
811       return -1;
812     }
813
814   /* Convert to 100ns to match OS resolution.  The OS uses ULONG values
815      to express resolution in 100ns units, so the coarsest timer resolution
816      is < 430 secs.  Actually the coarsest timer resolution is only slightly
817      beyond 15ms, but this might change in future OS versions, so we play nice
818      here. */
819   ULONGLONG period = (tp->tv_sec * 10000000ULL) + ((tp->tv_nsec) / 100ULL);
820
821   /* clock_setres is non-POSIX/non-Linux.  On QNX, the function always
822      rounds the incoming value to the nearest supported value. */
823   ULONG coarsest, finest, actual;
824   if (NT_SUCCESS (NtQueryTimerResolution (&coarsest, &finest, &actual)))
825     {
826       if (period > coarsest)
827         period = coarsest;
828       else if (finest > period)
829         period = finest;
830     }
831
832   if (period_set
833       && NT_SUCCESS (NtSetTimerResolution (minperiod, FALSE, &actual)))
834     period_set = false;
835
836   status = NtSetTimerResolution (period, TRUE, &actual);
837   if (!NT_SUCCESS (status))
838     {
839       __seterrno_from_nt_status (status);
840       return -1;
841     }
842   minperiod = actual;
843   period_set = true;
844   return 0;
845 }
846
847 extern "C" int
848 clock_getcpuclockid (pid_t pid, clockid_t *clk_id)
849 {
850   if (pid != 0 && !pinfo (pid)->exists ())
851     return (ESRCH);
852   *clk_id = (clockid_t) PID_TO_CLOCKID (pid);
853   return 0;
854 }