public inbox for cygwin-cvs@sourceware.org
help / color / mirror / Atom feed
* [newlib-cygwin] Cygwin: implement extensible clock interface
@ 2018-11-29 10:12 Corinna Vinschen
  0 siblings, 0 replies; only message in thread
From: Corinna Vinschen @ 2018-11-29 10:12 UTC (permalink / raw)
  To: cygwin-cvs

https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=c05df02725c5986d029eeec63beb467bdd6286ef

commit c05df02725c5986d029eeec63beb467bdd6286ef
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Tue Nov 27 13:47:02 2018 +0100

    Cygwin: implement extensible clock interface
    
    - Drop hires_[nm]s clocks, rename hires.h to clock.h.
    
    - Implement clk_t class as an extensible clock class in new file clock.cc.
    
    - Introduce get_clock(clock_id) returning a pointer to the clk_t instance
      for clock_id.  Provide the following methods along the lines of the former
      hires classes:
    
    	void		clk_t::nsecs (struct timespec *);
    	ULONGLONG	clk_t::nsecs ();
    	LONGLONG	clk_t::usecs ();
    	LONGLONG	clk_t::msecs ();
    	void 		clk_t::resolution (struct timespec *);
    
    - Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE
      and CLOCK_BOOTTIME clocks.
    
    - Allow clock_nanosleep, pthread_condattr_setclock and timer_create to use
      all new clocks (both clocks should be usable with a small tweak, though).
    
    - Bump DLL major version to 2.12.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 winsup/cygwin/Makefile.in              |   1 +
 winsup/cygwin/aio.cc                   |   5 +-
 winsup/cygwin/autoload.cc              |   8 +
 winsup/cygwin/clock.cc                 | 286 +++++++++++++++++++++++++++++++++
 winsup/cygwin/clock.h                  | 149 +++++++++++++++++
 winsup/cygwin/cygheap.h                |   2 +-
 winsup/cygwin/fhandler_socket_unix.cc  |   6 +-
 winsup/cygwin/hires.h                  |  64 --------
 winsup/cygwin/include/cygwin/version.h |  10 +-
 winsup/cygwin/ntdll.h                  |   3 +-
 winsup/cygwin/sched.cc                 |   2 +-
 winsup/cygwin/select.cc                |   4 +-
 winsup/cygwin/signal.cc                |  23 ++-
 winsup/cygwin/strace.cc                |  10 +-
 winsup/cygwin/sysconf.cc               |   2 +-
 winsup/cygwin/thread.cc                |  12 +-
 winsup/cygwin/timer.cc                 |  13 +-
 winsup/cygwin/times.cc                 | 218 ++++---------------------
 winsup/cygwin/wincap.cc                |  12 ++
 winsup/cygwin/wincap.h                 |   4 +
 20 files changed, 539 insertions(+), 295 deletions(-)

diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index a232836..fb0195f 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -254,6 +254,7 @@ DLL_OFILES:= \
 	autoload.o \
 	base64.o \
 	bsdlib.o \
+	clock.o \
 	ctype.o \
 	cxx.o \
 	cygheap.o \
diff --git a/winsup/cygwin/aio.cc b/winsup/cygwin/aio.cc
index 7d5d982..b245bdd 100644
--- a/winsup/cygwin/aio.cc
+++ b/winsup/cygwin/aio.cc
@@ -7,7 +7,6 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include "hires.h"
 #include "path.h"
 #include "fhandler.h"
 #include "dtable.h"
@@ -803,12 +802,12 @@ retry:
       return -1;
     }
 
-  time0 = ntod.nsecs ();
+  time0 = get_clock (CLOCK_MONOTONIC)->nsecs ();
   /* Note wait below is abortable even w/ empty sigmask and infinite timeout */
   res = sigtimedwait (&sigmask, &si, timeout ? &to : NULL);
   if (res == -1)
     return -1; /* Return with errno set by failed sigtimedwait() */
-  time1 = ntod.nsecs ();
+  time1 = get_clock (CLOCK_MONOTONIC)->nsecs ();
 
   /* Adjust timeout to account for time just waited */
   time1 -= time0;
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 4fac3e3..5a0e400 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -586,6 +586,14 @@ LoadDLLfunc (GetSystemTimePreciseAsFileTime, 4, kernel32)
 LoadDLLfuncEx (PrefetchVirtualMemory, 16, kernel32, 1)
 LoadDLLfunc (SetThreadGroupAffinity, 12, kernel32)
 
+/* MSDN claims these are exported by kernel32.dll, but only
+   QueryUnbiasedInterruptTime actually is.  The others are only
+   available via KernelBase.dll. */
+LoadDLLfunc (QueryInterruptTime, 4, KernelBase)
+LoadDLLfunc (QueryInterruptTimePrecise, 4, KernelBase)
+LoadDLLfunc (QueryUnbiasedInterruptTime, 4, KernelBase)
+LoadDLLfunc (QueryUnbiasedInterruptTimePrecise, 4, KernelBase)
+
 /* ldap functions are cdecl! */
 #pragma push_macro ("mangle")
 #undef mangle
diff --git a/winsup/cygwin/clock.cc b/winsup/cygwin/clock.cc
new file mode 100644
index 0000000..99d0a28
--- /dev/null
+++ b/winsup/cygwin/clock.cc
@@ -0,0 +1,286 @@
+#include "winsup.h"
+#include <realtimeapiset.h>
+#include "pinfo.h"
+#include "clock.h"
+#include "miscfuncs.h"
+#include "spinlock.h"
+
+static LONGLONG
+system_qpc_resolution ()
+{
+  LARGE_INTEGER qpf;
+
+  QueryPerformanceFrequency (&qpf);
+  return qpf.QuadPart;
+}
+
+static LONGLONG
+system_tickcount_resolution ()
+{
+  ULONG coarsest = 0, finest, actual;
+
+  if (!coarsest)
+    {
+      /* The actual resolution of the OS timer is a system-wide setting which
+       can be changed any time, by any process.  The only fixed value we
+       can rely on is the coarsest value. */
+      NtQueryTimerResolution (&coarsest, &finest, &actual);
+    }
+  return NS100PERSEC / coarsest;
+}
+
+void
+clk_t::init ()
+{
+  spinlock spin (inited, 1);
+  if (!spin)
+    ticks_per_sec = system_tickcount_resolution ();
+}
+
+void
+clk_realtime_t::init ()
+{
+  spinlock spin (inited, 1);
+  if (!spin)
+    ticks_per_sec = wincap.has_precise_system_time ()
+		    ? system_qpc_resolution ()
+		    : system_tickcount_resolution ();
+}
+
+void
+clk_monotonic_t::init ()
+{
+  spinlock spin (inited, 1);
+  if (!spin)
+    ticks_per_sec = system_qpc_resolution ();
+}
+
+int
+clk_realtime_coarse_t::now (clockid_t clockid, struct timespec *ts)
+{
+  LARGE_INTEGER now;
+
+  GetSystemTimeAsFileTime ((LPFILETIME) &now);
+  /* Add conversion factor for UNIX vs. Windows base time */
+  now.QuadPart -= FACTOR;
+  ts->tv_sec = now.QuadPart / NS100PERSEC;
+  ts->tv_nsec = (now.QuadPart % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
+  return 0;
+}
+
+int
+clk_realtime_t::now (clockid_t clockid, struct timespec *ts)
+{
+  LARGE_INTEGER now;
+
+  wincap.has_precise_system_time ()
+      ? GetSystemTimePreciseAsFileTime ((LPFILETIME) &now)
+      : GetSystemTimeAsFileTime ((LPFILETIME) &now);
+  /* Add conversion factor for UNIX vs. Windows base time */
+  now.QuadPart -= FACTOR;
+  ts->tv_sec = now.QuadPart / NS100PERSEC;
+  ts->tv_nsec = (now.QuadPart % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
+  return 0;
+}
+
+int
+clk_process_t::now (clockid_t clockid, struct timespec *ts)
+{
+  pid_t pid = CLOCKID_TO_PID (clockid);
+  HANDLE hProcess;
+  KERNEL_USER_TIMES kut;
+  int64_t x;
+
+  if (pid == 0)
+    pid = myself->pid;
+
+  pinfo p (pid);
+  if (!p || !p->exists ())
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+
+  hProcess = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, 0,
+			  p->dwProcessId);
+  NtQueryInformationProcess (hProcess, ProcessTimes,
+			     &kut, sizeof kut, NULL);
+
+  x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
+  ts->tv_sec = x / NS100PERSEC;
+  ts->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
+  CloseHandle (hProcess);
+  return 0;
+}
+
+int
+clk_thread_t::now (clockid_t clockid, struct timespec *ts)
+{
+  long thr_id = CLOCKID_TO_THREADID (clockid);
+  HANDLE hThread;
+  KERNEL_USER_TIMES kut;
+  int64_t x;
+
+  if (thr_id == 0)
+    thr_id = pthread::self ()->getsequence_np ();
+
+  hThread = OpenThread (THREAD_QUERY_LIMITED_INFORMATION, 0, thr_id);
+  if (!hThread)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+
+  NtQueryInformationThread (hThread, ThreadTimes,
+			    &kut, sizeof kut, NULL);
+
+  x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
+  ts->tv_sec = x / NS100PERSEC;
+  ts->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
+  CloseHandle (hThread);
+  return 0;
+}
+
+extern "C" void WINAPI QueryUnbiasedInterruptTimePrecise (PULONGLONG);
+extern "C" void WINAPI QueryInterruptTimePrecise (PULONGLONG);
+
+int
+clk_monotonic_t::now (clockid_t clockid, struct timespec *ts)
+{
+  if (wincap.has_precise_interrupt_time ())
+    {
+      /* Suspend time not taken into account, as on Linux */
+      ULONGLONG now;
+
+      QueryUnbiasedInterruptTimePrecise (&now);
+      ts->tv_sec = now / NS100PERSEC;
+      now %= NS100PERSEC;
+      ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
+    }
+  else
+    {
+      /* https://stackoverflow.com/questions/24330496.  Skip rounding since
+         its almost always wrong when working with timestamps */
+      UINT64 bias;
+      LARGE_INTEGER now;
+      struct timespec bts;
+
+      if (inited <= 0)
+	init ();
+      do
+	{
+	  bias = SharedUserData.InterruptTimeBias;
+	  QueryPerformanceCounter(&now);
+	}
+      while (bias != SharedUserData.InterruptTimeBias);
+      /* Convert perf counter to timespec */
+      ts->tv_sec = now.QuadPart / ticks_per_sec;
+      now.QuadPart %= ticks_per_sec;
+      ts->tv_nsec = (now.QuadPart * NSPERSEC) / ticks_per_sec;
+      /* Convert bias to timespec */
+      bts.tv_sec = bias / NS100PERSEC;
+      bias %= NS100PERSEC;
+      bts.tv_nsec = bias * (NSPERSEC/NS100PERSEC);
+      /* Subtract bias from perf */
+      ts_diff (bts, *ts);
+    }
+  return 0;
+}
+
+int
+clk_monotonic_coarse_t::now (clockid_t clockid, struct timespec *ts)
+{
+  if (wincap.has_unbiased_interrupt_time ())
+    {
+      /* Suspend time not taken into account, as on Linux */
+      ULONGLONG now;
+
+      QueryUnbiasedInterruptTime (&now);
+      ts->tv_sec = now / NS100PERSEC;
+      now %= NS100PERSEC;
+      ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
+    }
+  else
+    {
+      /* Vista-only: GetTickCount64 is biased but it's coarse and
+         monotonic. */
+      LONGLONG now;
+
+      if (inited <= 0)
+	init ();
+      now = GetTickCount64 ();
+      ts->tv_sec = now / ticks_per_sec;
+      now %= ticks_per_sec;
+      ts->tv_nsec = (now * NSPERSEC) / ticks_per_sec;
+    }
+  return 0;
+}
+
+int
+clk_boottime_t::now (clockid_t clockid, struct timespec *ts)
+{
+  /* Suspend time taken into account, as on Linux */
+  if (wincap.has_precise_interrupt_time ())
+    {
+      ULONGLONG now;
+
+      QueryInterruptTimePrecise (&now);
+      ts->tv_sec = now / NS100PERSEC;
+      now %= NS100PERSEC;
+      ts->tv_nsec = now * (NSPERSEC/NS100PERSEC);
+    }
+  else
+    {
+      LARGE_INTEGER now;
+
+      if (inited <= 0)
+	init ();
+      QueryPerformanceCounter (&now);
+      ts->tv_sec = now.QuadPart / ticks_per_sec;
+      now.QuadPart %= ticks_per_sec;
+      ts->tv_nsec = (now.QuadPart * NSPERSEC) / ticks_per_sec;
+    }
+  return 0;
+}
+
+void
+clk_t::resolution (struct timespec *ts)
+{
+  if (inited <= 0)
+    init ();
+  ts->tv_sec = 0;
+  ts->tv_nsec = NSPERSEC / ticks_per_sec;
+}
+
+static clk_realtime_coarse_t clk_realtime_coarse;
+static clk_realtime_t clk_realtime;
+static clk_process_t clk_process;
+static clk_thread_t clk_thread;
+static clk_monotonic_t clk_monotonic;
+static clk_monotonic_t clk_monotonic_raw;	/* same as clk_monotonic */
+static clk_monotonic_coarse_t clk_monotonic_coarse;
+static clk_boottime_t clk_boottime;
+
+clk_t *cyg_clock[MAX_CLOCKS] =
+{
+  &clk_realtime_coarse,
+  &clk_realtime,
+  &clk_process,
+  &clk_thread,
+  &clk_monotonic,
+  &clk_monotonic_raw,
+  &clk_monotonic_coarse,
+  &clk_boottime,
+};
+
+clk_t *
+get_clock (clockid_t clk_id)
+{
+  extern clk_t *cyg_clock[MAX_CLOCKS];
+  clockid_t clockid = CLOCKID (clk_id);
+  if (clk_id >= MAX_CLOCKS
+      && clockid != CLOCK_PROCESS_CPUTIME_ID
+      && clockid != CLOCK_THREAD_CPUTIME_ID)
+    return NULL;
+  return cyg_clock[clockid];
+}
diff --git a/winsup/cygwin/clock.h b/winsup/cygwin/clock.h
new file mode 100644
index 0000000..3c5bd5f
--- /dev/null
+++ b/winsup/cygwin/clock.h
@@ -0,0 +1,149 @@
+/* clock.h: Definitions for clock calculations
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __CLOCK_H__
+#define __CLOCK_H__
+
+#include <mmsystem.h>
+
+/* Must be a power of 2. */
+#define MAX_CLOCKS		 (8)
+
+/* Conversions for per-process and per-thread clocks */
+#define CLOCKID(cid) \
+		((cid) % MAX_CLOCKS)
+#define PID_TO_CLOCKID(pid) \
+		((pid) * MAX_CLOCKS + CLOCK_PROCESS_CPUTIME_ID)
+#define CLOCKID_TO_PID(cid) \
+		(((cid) - CLOCK_PROCESS_CPUTIME_ID) / MAX_CLOCKS)
+#define CLOCKID_IS_PROCESS(cid) \
+		(CLOCKID(cid) == CLOCK_PROCESS_CPUTIME_ID)
+#define THREADID_TO_CLOCKID(tid) \
+		((tid) * MAX_CLOCKS + CLOCK_THREAD_CPUTIME_ID)
+#define CLOCKID_TO_THREADID(cid) \
+		(((cid) - CLOCK_THREAD_CPUTIME_ID) / MAX_CLOCKS)
+#define CLOCKID_IS_THREAD(cid) \
+		(CLOCKID(cid) == CLOCK_THREAD_CPUTIME_ID)
+
+/* Largest delay in ms for sleep and alarm calls.
+   Allow actual delay to exceed requested delay by 10 s.
+   Express as multiple of 1000 (i.e. seconds) + max resolution
+   The tv_sec argument in timeval structures cannot exceed
+   CLOCK_DELAY_MAX / 1000 - 1, so that adding fractional part
+   and rounding won't exceed CLOCK_DELAY_MAX */
+#define CLOCK_DELAY_MAX ((((UINT_MAX - 10000) / 1000) * 1000) + 10)
+
+/* 100ns difference between Windows and UNIX timebase. */
+#define FACTOR (0x19db1ded53e8000LL)
+/* # of nanosecs per second. */
+#define NSPERSEC (1000000000LL)
+/* # of 100ns intervals per second. */
+#define NS100PERSEC (10000000LL)
+/* # of microsecs per second. */
+#define USPERSEC (1000000LL)
+/* # of millisecs per second. */
+#define MSPERSEC (1000L)
+
+class clk_t
+{
+ protected:
+  LONG inited;
+  LONGLONG ticks_per_sec;
+  virtual void init ();
+  virtual int now (clockid_t, struct timespec *) = 0;
+
+ public:
+  int nsecs (clockid_t _id, struct timespec *ts)
+  {
+    return now (_id, ts);
+  }
+  void resolution (struct timespec *);
+
+  /* shortcuts for non-process/thread clocks */
+  void nsecs (struct timespec *ts) { nsecs (0, ts); }
+  ULONGLONG nsecs ()
+  {
+    struct timespec ts;
+    nsecs (&ts);
+    return (ULONGLONG) ts.tv_sec * NSPERSEC + ts.tv_nsec;
+  }
+  LONGLONG n100secs ()
+  {
+    struct timespec ts;
+    nsecs (&ts);
+    return ts.tv_sec * NS100PERSEC + ts.tv_nsec / (NSPERSEC/NS100PERSEC);
+  }
+  LONGLONG usecs ()
+  {
+    struct timespec ts;
+    nsecs (&ts);
+    return ts.tv_sec * USPERSEC + ts.tv_nsec / (NSPERSEC/USPERSEC);
+  }
+  LONGLONG msecs ()
+  {
+    struct timespec ts;
+    nsecs (&ts);
+    return ts.tv_sec * MSPERSEC + ts.tv_nsec / (NSPERSEC/MSPERSEC);
+  }
+};
+
+class clk_realtime_coarse_t : public clk_t
+{
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_realtime_t : public clk_t
+{
+  virtual void init ();
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_process_t : public clk_t
+{
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_thread_t : public clk_t
+{
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_monotonic_t : public clk_t
+{
+ protected:
+  virtual void init ();
+ private:
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_monotonic_coarse_t : public clk_t
+{
+  virtual int now (clockid_t, struct timespec *);
+};
+
+class clk_boottime_t : public clk_monotonic_t
+{
+  virtual int now (clockid_t, struct timespec *);
+};
+
+clk_t *get_clock (clockid_t clk_id);
+
+/* Compute interval between two timespec timestamps: ts1  = ts1 - ts0. */
+static inline void
+ts_diff (const struct timespec &ts0, struct timespec &ts1)
+{
+  ts1.tv_nsec -= ts0.tv_nsec;
+  if (ts1.tv_nsec < 0)
+    {
+      ts1.tv_nsec += NSPERSEC;
+      --ts1.tv_sec;
+    }
+  ts1.tv_sec -= ts0.tv_sec;
+}
+
+#endif /*__CLOCK_H__*/
diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h
index abbf9ec..d8a2e79 100644
--- a/winsup/cygwin/cygheap.h
+++ b/winsup/cygwin/cygheap.h
@@ -6,7 +6,7 @@ This software is a copyrighted work licensed under the terms of the
 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
-#include "hires.h"
+#include "clock.h"
 #include "cygheap_malloc.h"
 #include "pwdgrp.h"
 
diff --git a/winsup/cygwin/fhandler_socket_unix.cc b/winsup/cygwin/fhandler_socket_unix.cc
index da83ecc..e71d2a7 100644
--- a/winsup/cygwin/fhandler_socket_unix.cc
+++ b/winsup/cygwin/fhandler_socket_unix.cc
@@ -24,7 +24,6 @@
 #include "fhandler.h"
 #include "dtable.h"
 #include "cygheap.h"
-#include "hires.h"
 #include "shared_info.h"
 #include "ntdll.h"
 #include "miscfuncs.h"
@@ -1269,7 +1268,7 @@ fhandler_socket_unix::wait_pipe_thread (PUNICODE_STRING pipe_name)
   pwbuf->NameLength = pipe_name->Length;
   pwbuf->TimeoutSpecified = TRUE;
   memcpy (pwbuf->Name, pipe_name->Buffer, pipe_name->Length);
-  stamp = ntod.nsecs ();
+  stamp = get_clock (CLOCK_MONOTONIC)->n100secs ();
   do
     {
       status = NtFsControlFile (npfsh, evt, NULL, NULL, &io, FSCTL_PIPE_WAIT,
@@ -1298,7 +1297,8 @@ fhandler_socket_unix::wait_pipe_thread (PUNICODE_STRING pipe_name)
 		  /* Another concurrent connect grabbed the pipe instance
 		     under our nose.  Fix the timeout value and go waiting
 		     again, unless the timeout has passed. */
-		  pwbuf->Timeout.QuadPart -= (stamp - ntod.nsecs ()) / 100LL;
+		  pwbuf->Timeout.QuadPart -=
+		    stamp - get_clock (CLOCK_MONOTONIC)->n100secs ();
 		  if (pwbuf->Timeout.QuadPart >= 0)
 		    {
 		      status = STATUS_IO_TIMEOUT;
diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h
deleted file mode 100644
index 10aed7b..0000000
--- a/winsup/cygwin/hires.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* hires.h: Definitions for hires clock calculations
-
-This file is part of Cygwin.
-
-This software is a copyrighted work licensed under the terms of the
-Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
-details. */
-
-#ifndef __HIRES_H__
-#define __HIRES_H__
-
-#include <mmsystem.h>
-
-/* Conversions for per-process and per-thread clocks */
-#define PID_TO_CLOCKID(pid) (pid * 8 + CLOCK_PROCESS_CPUTIME_ID)
-#define CLOCKID_TO_PID(cid) ((cid - CLOCK_PROCESS_CPUTIME_ID) / 8)
-#define CLOCKID_IS_PROCESS(cid) ((cid % 8) == CLOCK_PROCESS_CPUTIME_ID)
-#define THREADID_TO_CLOCKID(tid) (tid * 8 + CLOCK_THREAD_CPUTIME_ID)
-#define CLOCKID_TO_THREADID(cid) ((cid - CLOCK_THREAD_CPUTIME_ID) / 8)
-#define CLOCKID_IS_THREAD(cid) ((cid % 8) == CLOCK_THREAD_CPUTIME_ID)
-
-/* Largest delay in ms for sleep and alarm calls.
-   Allow actual delay to exceed requested delay by 10 s.
-   Express as multiple of 1000 (i.e. seconds) + max resolution
-   The tv_sec argument in timeval structures cannot exceed
-   HIRES_DELAY_MAX / 1000 - 1, so that adding fractional part
-   and rounding won't exceed HIRES_DELAY_MAX */
-#define HIRES_DELAY_MAX ((((UINT_MAX - 10000) / 1000) * 1000) + 10)
-
-/* 100ns difference between Windows and UNIX timebase. */
-#define FACTOR (0x19db1ded53e8000LL)
-/* # of nanosecs per second. */
-#define NSPERSEC (1000000000LL)
-/* # of 100ns intervals per second. */
-#define NS100PERSEC (10000000LL)
-/* # of microsecs per second. */
-#define USPERSEC (1000000LL)
-/* # of millisecs per second. */
-#define MSPERSEC (1000L)
-
-class hires_ns
-{
-  LONG inited;
-  LARGE_INTEGER primed_pc;
-  double freq;
-  void prime ();
- public:
-  LONGLONG nsecs (bool monotonic = false);
-  LONGLONG usecs () {return nsecs () / 1000LL;}
-  LONGLONG resolution();
-};
-
-class hires_ms
-{
- public:
-  LONGLONG nsecs ();
-  LONGLONG usecs () {return nsecs () / 10LL;}
-  LONGLONG msecs () {return nsecs () / 10000LL;}
-  UINT resolution ();
-};
-
-extern hires_ms gtod;
-extern hires_ns ntod;
-#endif /*__HIRES_H__*/
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 56b6269..bb1fa97 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -10,8 +10,8 @@ details. */
    the Cygwin shared library".  This version is used to track important
    changes to the DLL and is mainly informative in nature. */
 
-#define CYGWIN_VERSION_DLL_MAJOR 2011
-#define CYGWIN_VERSION_DLL_MINOR 3
+#define CYGWIN_VERSION_DLL_MAJOR 2012
+#define CYGWIN_VERSION_DLL_MINOR 0
 
 /* Major numbers before CYGWIN_VERSION_DLL_EPOCH are incompatible. */
 
@@ -498,13 +498,15 @@ details. */
   327: Export pthread_tryjoin_np, pthread_timedjoin_np.
   328: Export aio_cancel, aio_error, aio_fsync, aio_read, aio_return,
        aio_suspend, aio_write, lio_listio.
-  329: Export sched_getcpu..
+  329: Export sched_getcpu.
+  330: Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE,
+       CLOCK_BOOTTIME.
 
   Note that we forgot to bump the api for ualarm, strtoll, strtoull,
   sigaltstack, sethostname. */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 329
+#define CYGWIN_VERSION_API_MINOR 330
 
 /* There is also a compatibity version number associated with the shared memory
    regions.  It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index d64de1b..8d60ae7 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -793,7 +793,8 @@ typedef struct _KUSER_SHARED_DATA
   KSYSTEM_TIME InterruptTime;
   BYTE Reserved2[0x2c8];
   ULONG DismountCount;
-  /* A lot more follows... */
+  BYTE Reserved3[0xd0];
+  UINT64 InterruptTimeBias;
 } KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
 
 /* Checked on 64 bit. */
diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc
index 702d038..10168e6 100644
--- a/winsup/cygwin/sched.cc
+++ b/winsup/cygwin/sched.cc
@@ -12,7 +12,7 @@
 #include "miscfuncs.h"
 #include "cygerrno.h"
 #include "pinfo.h"
-#include "hires.h"
+#include "clock.h"
 /* for getpid */
 #include <unistd.h>
 #include <sys/param.h>
diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc
index a580ac6..0d82a59 100644
--- a/winsup/cygwin/select.cc
+++ b/winsup/cygwin/select.cc
@@ -159,7 +159,7 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   int ret = 0;
 
   /* Record the current time for later use. */
-  LONGLONG start_time = gtod.usecs ();
+  LONGLONG start_time = get_clock (CLOCK_REALTIME)->usecs ();
 
   select_stuff sel;
   sel.return_on_signal = 0;
@@ -210,7 +210,7 @@ select (int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
       if (us != -1LL && wait_state == select_stuff::select_set_zero)
 	{
 	  select_printf ("recalculating us");
-	  LONGLONG now = gtod.usecs ();
+	  LONGLONG now = get_clock (CLOCK_REALTIME)->usecs ();
 	  if (now >= (start_time + us))
 	    {
 	      select_printf ("timed out after verification");
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index de3e886..9e6fdc6 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -76,16 +76,9 @@ clock_nanosleep (clockid_t clk_id, int flags, const struct timespec *rqtp,
   /* support for CPU-time clocks is optional */
   if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id))
     return ENOTSUP;
-
-  switch (clk_id)
-    {
-    case CLOCK_REALTIME:
-    case CLOCK_MONOTONIC:
-      break;
-    default:
-      /* unknown or illegal clock ID */
-      return EINVAL;
-    }
+  /* All other valid clocks are valid */
+  if (clk_id >= MAX_CLOCKS)
+    return EINVAL;
 
   LARGE_INTEGER timeout;
 
@@ -103,14 +96,18 @@ clock_nanosleep (clockid_t clk_id, int flags, const struct timespec *rqtp,
 	  || (tp.tv_sec == rqtp->tv_sec && tp.tv_nsec > rqtp->tv_nsec))
 	return 0;
 
-      if (clk_id == CLOCK_REALTIME)
-	timeout.QuadPart += FACTOR;
-      else
+      switch (clk_id)
 	{
+	case CLOCK_REALTIME_COARSE:
+	case CLOCK_REALTIME:
+	  timeout.QuadPart += FACTOR;
+	  break;
+	default:
 	  /* other clocks need to be handled with a relative timeout */
 	  timeout.QuadPart -= tp.tv_sec * NS100PERSEC
 			      + tp.tv_nsec / (NSPERSEC/NS100PERSEC);
 	  timeout.QuadPart *= -1LL;
+	  break;
 	}
     }
   else /* !abstime */
diff --git a/winsup/cygwin/strace.cc b/winsup/cygwin/strace.cc
index b95b436..21c2d6d 100644
--- a/winsup/cygwin/strace.cc
+++ b/winsup/cygwin/strace.cc
@@ -82,8 +82,14 @@ strace::dll_info ()
 int
 strace::microseconds ()
 {
-  static hires_ns now NO_COPY;
-  return (int) now.usecs ();
+  /* Need a local clock instance because this function is called before
+     the global constructors of the inferior process have been called. */
+  static clk_monotonic_t clock_monotonic;
+  static LONGLONG process_start NO_COPY;
+
+  if (!process_start)
+    process_start = clock_monotonic.usecs ();
+  return (int) (clock_monotonic.usecs () - process_start);
 }
 
 static int __stdcall
diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc
index 753febc..216e514 100644
--- a/winsup/cygwin/sysconf.cc
+++ b/winsup/cygwin/sysconf.cc
@@ -19,7 +19,7 @@ details. */
 #include "ntdll.h"
 #include "tls_pbuf.h"
 #include "cpuid.h"
-#include "hires.h"
+#include "clock.h"
 
 static long
 get_open_max (int in)
diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc
index c47a597..f0f7b0a 100644
--- a/winsup/cygwin/thread.cc
+++ b/winsup/cygwin/thread.cc
@@ -2566,6 +2566,7 @@ pthread_convert_abstime (clockid_t clock_id, const struct timespec *abstime,
 		       / (NSPERSEC/NS100PERSEC);
   switch (clock_id)
     {
+    case CLOCK_REALTIME_COARSE:
     case CLOCK_REALTIME:
       timeout->QuadPart += FACTOR;
       break;
@@ -3035,14 +3036,9 @@ pthread_condattr_setclock (pthread_condattr_t *attr, clockid_t clock_id)
 {
   if (!pthread_condattr::is_good_object (attr))
     return EINVAL;
-  switch (clock_id)
-    {
-    case CLOCK_REALTIME:
-    case CLOCK_MONOTONIC:
-      break;
-    default:
-      return EINVAL;
-    }
+  if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id)
+      || clock_id >= MAX_CLOCKS)
+    return EINVAL;
   (*attr)->clock_id = clock_id;
   return 0;
 }
diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc
index 9d3d7dc..e1d78eb 100644
--- a/winsup/cygwin/timer.cc
+++ b/winsup/cygwin/timer.cc
@@ -127,7 +127,7 @@ timer_thread (VOID *x)
       LONG sleep_ms;
       /* Account for delays in starting thread
 	and sending the signal */
-      now = gtod.usecs ();
+      now = get_clock (tt->clock_id)->usecs ();
       sleep_us = sleepto_us - now;
       if (sleep_us > 0)
 	{
@@ -232,7 +232,8 @@ timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalu
       if (timespec_bad (value->it_value) || timespec_bad (value->it_interval))
 	__leave;
 
-      long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs ();
+      long long now = in_flags & TIMER_ABSTIME ?
+		      0 : get_clock (clock_id)->usecs ();
 
       lock_timer_tracker here;
       cancel ();
@@ -272,7 +273,7 @@ timer_tracker::gettime (itimerspec *ovalue)
   else
     {
       ovalue->it_interval = it_interval;
-      long long now = gtod.usecs ();
+      long long now = get_clock (clock_id)->usecs ();
       long long left_us = sleepto_us - now;
       if (left_us < 0)
        left_us = 0;
@@ -317,7 +318,7 @@ timer_create (clockid_t clock_id, struct sigevent *__restrict evp,
 	  return -1;
 	}
 
-      if (clock_id != CLOCK_REALTIME)
+      if (clock_id >= MAX_CLOCKS)
 	{
 	  set_errno (EINVAL);
 	  return -1;
@@ -466,8 +467,8 @@ alarm (unsigned int seconds)
  struct itimerspec newt = {}, oldt;
  /* alarm cannot fail, but only needs not be
     correct for arguments < 64k. Truncate */
- if (seconds > (HIRES_DELAY_MAX / 1000 - 1))
-   seconds = (HIRES_DELAY_MAX / 1000 - 1);
+ if (seconds > (CLOCK_DELAY_MAX / 1000 - 1))
+   seconds = (CLOCK_DELAY_MAX / 1000 - 1);
  newt.it_value.tv_sec = seconds;
  timer_settime ((timer_t) &ttstart, 0, &newt, &oldt);
  int ret = oldt.it_value.tv_sec + (oldt.it_value.tv_nsec > 0);
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
index c557e82..8908d44 100644
--- a/winsup/cygwin/times.cc
+++ b/winsup/cygwin/times.cc
@@ -26,10 +26,6 @@ details. */
 #include "ntdll.h"
 #include "spinlock.h"
 
-hires_ms NO_COPY gtod;
-
-hires_ns NO_COPY ntod;
-
 static inline void __attribute__ ((always_inline))
 get_system_time (PLARGE_INTEGER systime)
 {
@@ -171,10 +167,7 @@ gettimeofday (struct timeval *__restrict tv, void *__restrict tzvp)
 {
   struct timezone *tz = (struct timezone *) tzvp;
   static bool tzflag;
-  LONGLONG now = gtod.usecs ();
-
-  if (now == (LONGLONG) -1)
-    return -1;
+  LONGLONG now = get_clock (CLOCK_REALTIME)->usecs ();
 
   tv->tv_sec = now / USPERSEC;
   tv->tv_usec = now % USPERSEC;
@@ -462,135 +455,23 @@ ftime (struct timeb *tp)
   return 0;
 }
 
-#define stupid_printf if (cygwin_finished_initializing) debug_printf
-void
-hires_ns::prime ()
-{
-  spinlock hspin (inited, 1);
-  if (!hspin)
-    {
-      LARGE_INTEGER ifreq;
-
-      /* On XP or later the perf counter functions will always succeed. */
-      QueryPerformanceFrequency (&ifreq);
-      freq = (double) ((double) NSPERSEC / (double) ifreq.QuadPart);
-      QueryPerformanceCounter (&primed_pc);
-    }
-}
-
-LONGLONG
-hires_ns::nsecs (bool monotonic)
-{
-  LARGE_INTEGER now;
-
-  if (inited <= 0)
-    prime ();
-  QueryPerformanceCounter (&now);
-  // FIXME: Use round() here?
-  now.QuadPart = (LONGLONG) (freq * (double)
-		 (now.QuadPart - (monotonic ? 0LL : primed_pc.QuadPart)));
-  return now.QuadPart;
-}
-
-LONGLONG
-hires_ms::nsecs ()
-{
-  LARGE_INTEGER systime;
-  get_system_time (&systime);
-  /* Add conversion factor for UNIX vs. Windows base time */
-  return systime.QuadPart - FACTOR;
-}
-
 extern "C" int
 clock_gettime (clockid_t clk_id, struct timespec *tp)
 {
-  if (CLOCKID_IS_PROCESS (clk_id))
-    {
-      pid_t pid = CLOCKID_TO_PID (clk_id);
-      HANDLE hProcess;
-      KERNEL_USER_TIMES kut;
-      int64_t x;
-
-      if (pid == 0)
-	pid = getpid ();
-
-      pinfo p (pid);
-      if (!p || !p->exists ())
-	{
-	  set_errno (EINVAL);
-	  return -1;
-	}
-
-      hProcess = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, 0,
-			      p->dwProcessId);
-      NtQueryInformationProcess (hProcess, ProcessTimes,
-				 &kut, sizeof kut, NULL);
+  clk_t *clock = get_clock (clk_id);
 
-      x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
-      tp->tv_sec = x / NS100PERSEC;
-      tp->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
-
-      CloseHandle (hProcess);
-      return 0;
-    }
-
-  if (CLOCKID_IS_THREAD (clk_id))
+  if (!clock)
     {
-      long thr_id = CLOCKID_TO_THREADID (clk_id);
-      HANDLE hThread;
-      KERNEL_USER_TIMES kut;
-      int64_t x;
-
-      if (thr_id == 0)
-	thr_id = pthread::self ()->getsequence_np ();
-
-      hThread = OpenThread (THREAD_QUERY_LIMITED_INFORMATION, 0, thr_id);
-      if (!hThread)
-	{
-	  set_errno (EINVAL);
-	  return -1;
-	}
-
-      NtQueryInformationThread (hThread, ThreadTimes,
-				&kut, sizeof kut, NULL);
-
-      x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
-      tp->tv_sec = x / NS100PERSEC;
-      tp->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
-
-      CloseHandle (hThread);
-      return 0;
+      set_errno (EINVAL);
+      return -1;
     }
-
-  switch (clk_id)
+  __try
     {
-      case CLOCK_REALTIME:
-	{
-	  LONGLONG now = gtod.nsecs ();
-	  if (now == (LONGLONG) -1)
-	    return -1;
-	  tp->tv_sec = now / NS100PERSEC;
-	  tp->tv_nsec = (now % NS100PERSEC) * (NSPERSEC / NS100PERSEC);
-	  break;
-	}
-
-      case CLOCK_MONOTONIC:
-	{
-	  LONGLONG now = ntod.nsecs (true);
-	  if (now == (LONGLONG) -1)
-	    return -1;
-
-	  tp->tv_sec = now / NSPERSEC;
-	  tp->tv_nsec = (now % NSPERSEC);
-	  break;
-	}
-
-      default:
-	set_errno (EINVAL);
-	return -1;
+      return clock->nsecs (clk_id, tp);
     }
-
-  return 0;
+  __except (EFAULT) {}
+  __endtry
+  return -1;
 }
 
 extern "C" int
@@ -608,80 +489,45 @@ clock_settime (clockid_t clk_id, const struct timespec *tp)
       return -1;
     }
 
-  if (clk_id != CLOCK_REALTIME)
+  if (clk_id != CLOCK_REALTIME_COARSE && clk_id != CLOCK_REALTIME)
     {
       set_errno (EINVAL);
       return -1;
     }
 
-  tv.tv_sec = tp->tv_sec;
-  tv.tv_usec = tp->tv_nsec / 1000;
+  __try
+    {
+      tv.tv_sec = tp->tv_sec;
+      tv.tv_usec = tp->tv_nsec / 1000;
+    }
+  __except (EFAULT)
+    {
+      return -1;
+    }
+  __endtry
 
   return settimeofday (&tv, NULL);
 }
 
-static ULONG minperiod;	// FIXME: Maintain period after a fork.
-
-LONGLONG
-hires_ns::resolution ()
+extern "C" int
+clock_getres (clockid_t clk_id, struct timespec *tp)
 {
-  if (inited <= 0)
-    prime ();
-  return (freq <= 1.0) ? 1LL : (LONGLONG) freq;
-}
+  clk_t *clock = get_clock (clk_id);
 
-UINT
-hires_ms::resolution ()
-{
-  if (!minperiod)
+  if (!clock)
     {
-      ULONG coarsest, finest, actual;
-
-      NtQueryTimerResolution (&coarsest, &finest, &actual);
-      /* The actual resolution of the OS timer is a system-wide setting which
-	 can be changed any time, by any process.  The only fixed value we
-	 can rely on is the coarsest value. */
-      minperiod = coarsest;
+      set_errno (EINVAL);
+      return -1;
     }
-  return minperiod;
-}
-
-extern "C" int
-clock_getres (clockid_t clk_id, struct timespec *tp)
-{
-  if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id))
+  __try
     {
-      ULONG coarsest, finest, actual;
-
-      NtQueryTimerResolution (&coarsest, &finest, &actual);
-      tp->tv_sec = coarsest / NS100PERSEC;
-      tp->tv_nsec = (coarsest % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
-      return 0;
+      clock->resolution (tp);
     }
-
-  switch (clk_id)
+  __except (EFAULT)
     {
-      case CLOCK_REALTIME:
-	{
-	  DWORD period = gtod.resolution ();
-	  tp->tv_sec = period / NS100PERSEC;
-	  tp->tv_nsec = (period % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
-	  break;
-	}
-
-      case CLOCK_MONOTONIC:
-	{
-	  LONGLONG period = ntod.resolution ();
-	  tp->tv_sec = period / NSPERSEC;
-	  tp->tv_nsec = period % NSPERSEC;
-	  break;
-	}
-
-      default:
-	set_errno (EINVAL);
-	return -1;
+      return -1;
     }
-
+  __endtry
   return 0;
 }
 
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index 0d20d37..d5d8ef6 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -32,6 +32,8 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
     has_new_pebteb_region:false,
     has_broken_whoami:true,
     has_unprivileged_createsymlink:false,
+    has_unbiased_interrupt_time:false,
+    has_precise_interrupt_time:false,
   },
 };
 
@@ -50,6 +52,8 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
     has_new_pebteb_region:false,
     has_broken_whoami:true,
     has_unprivileged_createsymlink:false,
+    has_unbiased_interrupt_time:true,
+    has_precise_interrupt_time:false,
   },
 };
 
@@ -68,6 +72,8 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
     has_new_pebteb_region:false,
     has_broken_whoami:false,
     has_unprivileged_createsymlink:false,
+    has_unbiased_interrupt_time:true,
+    has_precise_interrupt_time:false,
   },
 };
 
@@ -86,6 +92,8 @@ wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
     has_new_pebteb_region:false,
     has_broken_whoami:false,
     has_unprivileged_createsymlink:false,
+    has_unbiased_interrupt_time:true,
+    has_precise_interrupt_time:true,
   },
 };
 
@@ -104,6 +112,8 @@ wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) =
     has_new_pebteb_region:true,
     has_broken_whoami:false,
     has_unprivileged_createsymlink:false,
+    has_unbiased_interrupt_time:true,
+    has_precise_interrupt_time:true,
   },
 };
 
@@ -122,6 +132,8 @@ wincaps wincap_10_1703 __attribute__((section (".cygwin_dll_common"), shared)) =
     has_new_pebteb_region:true,
     has_broken_whoami:false,
     has_unprivileged_createsymlink:true,
+    has_unbiased_interrupt_time:true,
+    has_precise_interrupt_time:true,
   },
 };
 
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 9dc0000..cc1c6ba 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -27,6 +27,8 @@ struct wincaps
     unsigned has_new_pebteb_region		: 1;
     unsigned has_broken_whoami			: 1;
     unsigned has_unprivileged_createsymlink	: 1;
+    unsigned has_unbiased_interrupt_time	: 1;
+    unsigned has_precise_interrupt_time		: 1;
   };
 };
 
@@ -74,6 +76,8 @@ public:
   bool	IMPLEMENT (has_new_pebteb_region)
   bool	IMPLEMENT (has_broken_whoami)
   bool	IMPLEMENT (has_unprivileged_createsymlink)
+  bool	IMPLEMENT (has_unbiased_interrupt_time)
+  bool	IMPLEMENT (has_precise_interrupt_time)
 
 #undef IMPLEMENT
 };


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2018-11-29 10:12 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-29 10:12 [newlib-cygwin] Cygwin: implement extensible clock interface Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).