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>
This commit is contained in:
Corinna Vinschen 2018-11-27 13:47:02 +01:00
parent f4d6ef2d41
commit c05df02725
20 changed files with 541 additions and 297 deletions

View File

@ -254,6 +254,7 @@ DLL_OFILES:= \
autoload.o \
base64.o \
bsdlib.o \
clock.o \
ctype.o \
cxx.o \
cygheap.o \

View File

@ -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;

View File

@ -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

286
winsup/cygwin/clock.cc Normal file
View File

@ -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];
}

149
winsup/cygwin/clock.h Normal file
View File

@ -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__*/

View File

@ -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"

View File

@ -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;

View File

@ -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__*/

View File

@ -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

View File

@ -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. */

View File

@ -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>

View File

@ -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");

View File

@ -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 */

View File

@ -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

View File

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

View File

@ -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;
}

View File

@ -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);

View File

@ -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))
clk_t *clock = get_clock (clk_id);
if (!clock)
{
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);
x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
tp->tv_sec = x / NS100PERSEC;
tp->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
CloseHandle (hProcess);
return 0;
set_errno (EINVAL);
return -1;
}
if (CLOCKID_IS_THREAD (clk_id))
__try
{
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;
return clock->nsecs (clk_id, tp);
}
switch (clk_id)
{
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 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 ()
{
if (inited <= 0)
prime ();
return (freq <= 1.0) ? 1LL : (LONGLONG) freq;
}
UINT
hires_ms::resolution ()
{
if (!minperiod)
{
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;
}
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))
clk_t *clock = get_clock (clk_id);
if (!clock)
{
ULONG coarsest, finest, actual;
NtQueryTimerResolution (&coarsest, &finest, &actual);
tp->tv_sec = coarsest / NS100PERSEC;
tp->tv_nsec = (coarsest % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
return 0;
set_errno (EINVAL);
return -1;
}
switch (clk_id)
__try
{
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;
clock->resolution (tp);
}
__except (EFAULT)
{
return -1;
}
__endtry
return 0;
}

View File

@ -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,
},
};

View File

@ -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
};