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:
parent
f4d6ef2d41
commit
c05df02725
|
@ -254,6 +254,7 @@ DLL_OFILES:= \
|
|||
autoload.o \
|
||||
base64.o \
|
||||
bsdlib.o \
|
||||
clock.o \
|
||||
ctype.o \
|
||||
cxx.o \
|
||||
cygheap.o \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
|
@ -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__*/
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__*/
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue