]> sourceware.org Git - newlib-cygwin.git/commitdiff
* autoload.cc (winmm): Remove time functions. Don't treat
authorCorinna Vinschen <corinna@vinschen.de>
Tue, 29 Mar 2011 10:21:30 +0000 (10:21 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 29 Mar 2011 10:21:30 +0000 (10:21 +0000)
unloadable wave functions as fatal.
* hires.h (hires_ms::timeGetTime_ns): New private method.
(hires_ms::dmsecs): Call timeGetTime_ns here.
* ntdll.h (struct _KSYSTEM_TIME): Define.
(KUSER_SHARED_DATA): Redefine to allow access to InterruptTime.
(SharedUserData): Define here.
(NtQueryTimerResolution): Declare.
(NtSetTimerResolution): Declare.
* path.cc (SharedUserData): Move to ntdll.h.
* times.cc (hires_ms::timeGetTime_ns): New private method.
Use throughout instead of timeGetTime.  Document entire functionality
of timeGetTime in case we need it.
(hires_ms::resolution): Try a call to NtQueryTimerResolution
to fetch current period.  Fall back to heuristic if that fails.
Cast to DWORD in assignments to minperiod.
(clock_setres): Align period to possible values per a call to
NtQueryTimerResolution.  Explain why.  Replace calls to timeBeginPeriod
and timeEndPeriod with underlying call to NtSetTimerResolution.  Use
status code from NtSetTimerResolution to compute errno.
Convert period to ULONGLONG and store 100ns value to simplify code.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/hires.h
winsup/cygwin/ntdll.h
winsup/cygwin/path.cc
winsup/cygwin/times.cc

index 9a05e8d9f1492e2c2d8cfc7015eae0a48e2fbc11..008bef9a0f676d57046d295ce467459cb236aeac 100644 (file)
@@ -1,3 +1,27 @@
+2011-03-29  Corinna Vinschen  <corinna@vinschen.de>
+
+       * autoload.cc (winmm): Remove time functions.  Don't treat
+       unloadable wave functions as fatal.
+       * hires.h (hires_ms::timeGetTime_ns): New private method.
+       (hires_ms::dmsecs): Call timeGetTime_ns here.
+       * ntdll.h (struct _KSYSTEM_TIME): Define.
+       (KUSER_SHARED_DATA): Redefine to allow access to InterruptTime.
+       (SharedUserData): Define here.
+       (NtQueryTimerResolution): Declare.
+       (NtSetTimerResolution): Declare.
+       * path.cc (SharedUserData): Move to ntdll.h.
+       * times.cc (hires_ms::timeGetTime_ns): New private method.
+       Use throughout instead of timeGetTime.  Document entire functionality
+       of timeGetTime in case we need it.
+       (hires_ms::resolution): Try a call to NtQueryTimerResolution
+       to fetch current period.  Fall back to heuristic if that fails.
+       Cast to DWORD in assignments to minperiod.
+       (clock_setres): Align period to possible values per a call to
+       NtQueryTimerResolution.  Explain why.  Replace calls to timeBeginPeriod
+       and timeEndPeriod with underlying call to NtSetTimerResolution.  Use
+       status code from NtSetTimerResolution to compute errno.
+       Convert period to ULONGLONG and store 100ns value to simplify code.
+
 2011-03-29  Yaakov Selkowitz  <yselkowitz@users.sourceforge.net>
            Corinna Vinschen  <corinna@vinschen.de>
 
index 3cb68bafe1f3549650645473742cc7a7d391155a..c0ab2ed26b2243f90db0d39b246018cc1b8041e4 100644 (file)
@@ -455,27 +455,23 @@ LoadDLLfunc (SetProcessWindowStation, 4, user32)
 LoadDLLfunc (SetThreadDesktop, 4, user32)
 LoadDLLfunc (ShowWindowAsync, 8, user32)
 
-LoadDLLfuncEx3 (timeBeginPeriod, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (timeEndPeriod, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (timeGetDevCaps, 8, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (timeGetTime, 0, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInAddBuffer, 12, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInClose, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInGetNumDevs, 0, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInOpen, 24, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInPrepareHeader, 12, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInReset, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInStart, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveInUnprepareHeader, 12, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutClose, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutGetNumDevs, 0, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutGetVolume, 8, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutOpen, 24, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutPrepareHeader, 12, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutReset, 4, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutSetVolume, 8, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutUnprepareHeader, 12, winmm, 0, 0, 1)
-LoadDLLfuncEx3 (waveOutWrite, 12, winmm, 0, 0, 1)
+LoadDLLfuncEx3 (waveInAddBuffer, 12, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInClose, 4, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInGetNumDevs, 0, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInOpen, 24, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInPrepareHeader, 12, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInReset, 4, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInStart, 4, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveInUnprepareHeader, 12, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutClose, 4, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutGetNumDevs, 0, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutGetVolume, 8, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutOpen, 24, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutPrepareHeader, 12, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutReset, 4, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutSetVolume, 8, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutUnprepareHeader, 12, winmm, 1, 0, 1)
+LoadDLLfuncEx3 (waveOutWrite, 12, winmm, 1, 0, 1)
 
 LoadDLLfunc (accept, 12, ws2_32)
 LoadDLLfunc (bind, 12, ws2_32)
index 5f87453d611036276b66b2d3c63088c6aee0c78d..42151197f0035beabc3a63e3ef112aa3f34fbe3b 100644 (file)
@@ -43,12 +43,13 @@ class hires_ns : public hires_base
 class hires_ms : public hires_base
 {
   LONGLONG initime_ns;
+  LONGLONG timeGetTime_ns ();
   void prime ();
  public:
   LONGLONG nsecs ();
   LONGLONG usecs () {return nsecs () / 10LL;}
   LONGLONG msecs () {return nsecs () / 10000LL;}
-  UINT dmsecs () { return timeGetTime (); }
+  UINT dmsecs () { return timeGetTime_ns () / 10000LL; }
   UINT resolution ();
   LONGLONG uptime () {return (nsecs () - initime_ns) / 10000LL;}
 };
index 54c56f0278dd548aad01c61b80c02df6b0f8c555..cd8e1f1065faaf0e250898bbe3b9741019847264 100644 (file)
@@ -599,9 +599,18 @@ typedef struct _TEB
   /* A lot more follows... */
 } TEB, *PTEB;
 
+typedef struct _KSYSTEM_TIME
+{
+  ULONG LowPart;
+  LONG High1Time;
+  LONG High2Time;
+} KSYSTEM_TIME, *PKSYSTEM_TIME;
+
 typedef struct _KUSER_SHARED_DATA
 {
-  BYTE Reserved1[0x2dc];
+  BYTE Reserved1[0x08];
+  KSYSTEM_TIME InterruptTime;
+  BYTE Reserved2[0x2c8];
   ULONG DismountCount;
   /* A lot more follows... */
 } KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
@@ -889,6 +898,11 @@ typedef enum _EVENT_INFORMATION_CLASS
 #define NtCurrentProcess() ((HANDLE) 0xffffffff)
 #define NtCurrentThread()  ((HANDLE) 0xfffffffe)
 
+/* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
+   user address space.  We need it here to access the current DismountCount. */
+static KUSER_SHARED_DATA &SharedUserData
+                        = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
+
 extern "C"
 {
   NTSTATUS NTAPI NtAdjustPrivilegesToken (HANDLE, BOOLEAN, PTOKEN_PRIVILEGES,
@@ -970,6 +984,7 @@ extern "C"
   NTSTATUS NTAPI NtQuerySecurityObject (HANDLE, SECURITY_INFORMATION,
                                        PSECURITY_DESCRIPTOR, ULONG, PULONG);
   NTSTATUS NTAPI NtQuerySymbolicLinkObject (HANDLE, PUNICODE_STRING, PULONG);
+  NTSTATUS NTAPI NtQueryTimerResolution (PULONG, PULONG, PULONG);
   NTSTATUS NTAPI NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS,
                                       PVOID, ULONG, PULONG);
   NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *,
@@ -984,6 +999,7 @@ extern "C"
                                       FILE_INFORMATION_CLASS);
   NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION,
                                      PSECURITY_DESCRIPTOR);
+  NTSTATUS NTAPI NtSetTimerResolution (ULONG, BOOLEAN, PULONG);
   NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG);
   NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
   NTSTATUS NTAPI NtWriteFile (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID,
index 4a7c116926ff5abdcefe9b839414a6afb4a50cf0..3a74dfa6a121ff262a0cc4a99b4b9f4f90d2b888 100644 (file)
@@ -3460,11 +3460,6 @@ static PFAST_CWD *fast_cwd_ptr
 static int fast_cwd_version
   __attribute__((section (".cygwin_dll_common"), shared)) = 1;
 
-/* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
-   user address space.  We need it here to access the current DismountCount. */
-static KUSER_SHARED_DATA &SharedUserData
-                        = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
-
 #define peek32(x)      (*(uint32_t *)(x))
 
 /* This function scans the code in ntdll.dll to find the address of the
index c911cfe5421fab11d8ceb347573897514286eabf..19c03fdf83c70e64736afbab3719e6b56dab2d39 100644 (file)
@@ -666,6 +666,53 @@ hires_ns::nsecs ()
   return now.QuadPart;
 }
 
+LONGLONG
+hires_ms::timeGetTime_ns ()
+{
+  LARGE_INTEGER t;
+
+  /* This is how timeGetTime is implemented in winmm.dll.
+     The real timeGetTime subtracts and adds some values which are constant
+     over the lifetime of the process.  Since we don't need absolute accuracy
+     of the value returned by timeGetTime, only relative accuracy, we can skip
+     this step.  However, if we ever find out that we need absolute accuracy,
+     here's how it works in it's full beauty:
+     
+     - At process startup, winmm initializes two calibration values:
+
+       DWORD tick_count_start;
+       LARGE_INTEGER int_time_start;
+       do
+        {
+          tick_count_start = GetTickCount ()
+          do
+            {
+              int_time_start.HighPart = SharedUserData.InterruptTime.High1Time;
+              int_time_start.LowPart = SharedUserData.InterruptTime.LowPart;
+            }
+          while (int_time_start.HighPart
+                 != SharedUserData.InterruptTime.High2Time);
+        }
+       while (tick_count_start != GetTickCount ();
+
+     - timeGetTime computes its return value in the loop as below, and then:
+
+       t.QuadPart -= int_time_start.QuadPart;
+       t.QuadPart /= 10000;
+       t.LowPart += tick_count_start;
+       return t.LowPart;
+  */
+  do
+    {
+      t.HighPart = SharedUserData.InterruptTime.High1Time;
+      t.LowPart = SharedUserData.InterruptTime.LowPart;
+    }
+  while (t.HighPart != SharedUserData.InterruptTime.High2Time);
+  /* We use the value in full 100ns resolution in the calling functions
+     anyway, so we can skip dividing by 10000 here. */
+  return t.QuadPart;
+}
+
 void
 hires_ms::prime ()
 {
@@ -673,7 +720,7 @@ hires_ms::prime ()
     {
       int priority = GetThreadPriority (GetCurrentThread ());
       SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
-      initime_ns = systime_ns () - (((LONGLONG) timeGetTime ()) * 10000LL);
+      initime_ns = systime_ns () - timeGetTime_ns ();
       inited = true;
       SetThreadPriority (GetCurrentThread (), priority);
     }
@@ -687,12 +734,12 @@ hires_ms::nsecs ()
     prime ();
 
   LONGLONG t = systime_ns ();
-  LONGLONG res = initime_ns + (((LONGLONG) timeGetTime ()) * 10000LL);
+  LONGLONG res = initime_ns + timeGetTime_ns ();
   if (res < (t - 40 * 10000LL))
     {
       inited = false;
       prime ();
-      res = initime_ns + (((LONGLONG) timeGetTime ()) * 10000LL);
+      res = initime_ns + timeGetTime_ns ();
     }
   return res;
 }
@@ -734,7 +781,7 @@ clock_gettime (clockid_t clk_id, struct timespec *tp)
 static DWORD minperiod;        // FIXME: Maintain period after a fork.
 
 LONGLONG
-hires_ns::resolution()
+hires_ns::resolution ()
 {
   if (!inited)
     prime ();
@@ -752,24 +799,34 @@ hires_ms::resolution ()
 {
   if (!minperiod)
     {
-      /* Try to empirically determine current timer resolution */
-      int priority = GetThreadPriority (GetCurrentThread ());
-      SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
-      DWORD period = 0;
-      for (int i = 0; i < 4; i++)
+      NTSTATUS status;
+      ULONG coarsest, finest, actual;
+
+      status = NtQueryTimerResolution (&coarsest, &finest, &actual);
+      if (NT_SUCCESS (status))
+       minperiod = (DWORD) actual / 10000L;
+      else
        {
-         DWORD now;
-         DWORD then = timeGetTime ();
-         while ((now = timeGetTime ()) == then)
-           continue;
-         then = now;
-         while ((now = timeGetTime ()) == then)
-           continue;
-         period += now - then;
+         /* Try to empirically determine current timer resolution */
+         int priority = GetThreadPriority (GetCurrentThread ());
+         SetThreadPriority (GetCurrentThread (),
+                            THREAD_PRIORITY_TIME_CRITICAL);
+         LONGLONG period = 0;
+         for (int i = 0; i < 4; i++)
+           {
+             LONGLONG now;
+             LONGLONG then = timeGetTime_ns ();
+             while ((now = timeGetTime_ns ()) == then)
+               continue;
+             then = now;
+             while ((now = timeGetTime_ns ()) == then)
+               continue;
+             period += now - then;
+           }
+         SetThreadPriority (GetCurrentThread (), priority);
+         period /= 40000L;
+         minperiod = (DWORD) period;
        }
-      SetThreadPriority (GetCurrentThread (), priority);
-      period /= 4;
-      minperiod = period;
     }
   return minperiod;
 }
@@ -807,28 +864,43 @@ extern "C" int
 clock_setres (clockid_t clk_id, struct timespec *tp)
 {
   static NO_COPY bool period_set;
+  int status;
+
   if (clk_id != CLOCK_REALTIME)
     {
       set_errno (EINVAL);
       return -1;
     }
 
-  if (period_set)
-    timeEndPeriod (minperiod);
-
-  DWORD period = (tp->tv_sec * 1000) + ((tp->tv_nsec) / 1000000);
-
-  if (timeBeginPeriod (period))
+  /* Convert to 100ns to match OS resolution.  The OS uses ULONG values
+     to express resolution in 100ns units, so the coarsest timer resolution
+     is < 430 secs.  Actually the coarsest timer resolution is only slightly
+     beyond 15ms, but this might change in future OS versions, so we play nice
+     here. */
+  ULONGLONG period = (tp->tv_sec * 10000000ULL) + ((tp->tv_nsec) / 100ULL);
+
+  /* clock_setres is non-POSIX/non-Linux.  On QNX, the function always
+     rounds the incoming value to the nearest supported value. */
+  ULONG coarsest, finest, actual;
+  if (NT_SUCCESS (NtQueryTimerResolution (&coarsest, &finest, &actual)))
     {
-      minperiod = period;
-      period_set = true;
+      if (period > coarsest)
+       period = coarsest;
+      else if (finest > period)
+       period = finest;
     }
-  else
+
+  if (period_set
+      && NT_SUCCESS (NtSetTimerResolution (minperiod * 10000L, FALSE, &actual)))
+    period_set = false;
+
+  status = NtSetTimerResolution (period, TRUE, &actual);
+  if (!NT_SUCCESS (status))
     {
-      __seterrno ();
-      timeBeginPeriod (minperiod);
+      __seterrno_from_nt_status (status);
       return -1;
     }
-
+  minperiod = actual / 10000L;
+  period_set = true;
   return 0;
 }
This page took 0.040729 seconds and 5 git commands to generate.