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).