Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog24
-rw-r--r--winsup/cygwin/autoload.cc38
-rw-r--r--winsup/cygwin/hires.h3
-rw-r--r--winsup/cygwin/ntdll.h18
-rw-r--r--winsup/cygwin/path.cc5
-rw-r--r--winsup/cygwin/times.cc136
6 files changed, 164 insertions, 60 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 9a05e8d9f..008bef9a0 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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>
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 3cb68bafe..c0ab2ed26 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -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)
diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h
index 5f87453d6..42151197f 100644
--- a/winsup/cygwin/hires.h
+++ b/winsup/cygwin/hires.h
@@ -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;}
};
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 54c56f027..cd8e1f106 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -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,
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 4a7c11692..3a74dfa6a 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -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
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
index c911cfe54..19c03fdf8 100644
--- a/winsup/cygwin/times.cc
+++ b/winsup/cygwin/times.cc
@@ -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;
}