Cygwin: timers: use spinlock to prime hires_ns thread-safe

The current method to make hires_ns priming thread-safe isn't
thread-safe.  Rather than hoping that running the thread in
TIME_CRITICAL priority is doing the right thing, use a spinlock.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2018-11-26 17:47:53 +01:00
parent 161d0fd27b
commit 5eaa64f9d8
2 changed files with 13 additions and 15 deletions

View File

@ -40,7 +40,7 @@ details. */
class hires_ns class hires_ns
{ {
int inited; LONG inited;
LARGE_INTEGER primed_pc; LARGE_INTEGER primed_pc;
double freq; double freq;
void prime (); void prime ();

View File

@ -24,6 +24,7 @@ details. */
#include "thread.h" #include "thread.h"
#include "cygtls.h" #include "cygtls.h"
#include "ntdll.h" #include "ntdll.h"
#include "spinlock.h"
hires_ms NO_COPY gtod; hires_ms NO_COPY gtod;
@ -465,19 +466,16 @@ ftime (struct timeb *tp)
void void
hires_ns::prime () hires_ns::prime ()
{ {
LARGE_INTEGER ifreq; spinlock hspin (inited, 1);
if (!hspin)
{
LARGE_INTEGER ifreq;
/* On XP or later the perf counter functions will always succeed. */ /* On XP or later the perf counter functions will always succeed. */
QueryPerformanceFrequency (&ifreq); QueryPerformanceFrequency (&ifreq);
freq = (double) ((double) NSPERSEC / (double) ifreq.QuadPart);
int priority = GetThreadPriority (GetCurrentThread ()); QueryPerformanceCounter (&primed_pc);
}
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
QueryPerformanceCounter (&primed_pc);
freq = (double) ((double) NSPERSEC / (double) ifreq.QuadPart);
inited = true;
SetThreadPriority (GetCurrentThread (), priority);
} }
LONGLONG LONGLONG
@ -485,7 +483,7 @@ hires_ns::nsecs (bool monotonic)
{ {
LARGE_INTEGER now; LARGE_INTEGER now;
if (!inited) if (inited <= 0)
prime (); prime ();
QueryPerformanceCounter (&now); QueryPerformanceCounter (&now);
// FIXME: Use round() here? // FIXME: Use round() here?
@ -627,7 +625,7 @@ static ULONG minperiod; // FIXME: Maintain period after a fork.
LONGLONG LONGLONG
hires_ns::resolution () hires_ns::resolution ()
{ {
if (!inited) if (inited <= 0)
prime (); prime ();
return (freq <= 1.0) ? 1LL : (LONGLONG) freq; return (freq <= 1.0) ? 1LL : (LONGLONG) freq;
} }