Cygwin: posix timers: fix overrun count always being 1 too big

Combine with a bit of cleanup:
- Drop overrun_event_running in favor of overrun_count being -1.
- Fix include guard in posix_timer.h.
- Drop ununsed function timespec_to_us.
- Don't use Interlocked functions without need.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
Corinna Vinschen 2019-01-22 18:20:18 +01:00
parent de0ec284a3
commit 1f10a00ba7
2 changed files with 21 additions and 37 deletions

View File

@ -17,8 +17,7 @@ details. */
#include "posix_timer.h" #include "posix_timer.h"
#include <sys/param.h> #include <sys/param.h>
#define OVR_EVENT_DISARMED 0 #define OVR_DISARMED -1LL
#define OVR_EVENT_ARMED 1
timer_tracker NO_COPY itimer_tracker (CLOCK_REALTIME, NULL); timer_tracker NO_COPY itimer_tracker (CLOCK_REALTIME, NULL);
@ -34,15 +33,15 @@ timer_tracker::cancel ()
{ {
res = WaitForSingleObject (sync_thr, INFINITE); res = WaitForSingleObject (sync_thr, INFINITE);
if (res != WAIT_OBJECT_0) if (res != WAIT_OBJECT_0)
system_printf ("WFSO returned unexpected value %u, %E", res); debug_printf ("WFSO returned unexpected value %u, %E", res);
} }
return true; return true;
} }
timer_tracker::timer_tracker (clockid_t c, const sigevent *e) timer_tracker::timer_tracker (clockid_t c, const sigevent *e)
: magic (TT_MAGIC), clock_id (c), timer (NULL), cancel_evt (NULL), : magic (TT_MAGIC), clock_id (c), timer (NULL), cancel_evt (NULL),
sync_thr (NULL), interval (0), exp_ts (0), overrun_event_running (0), sync_thr (NULL), interval (0), exp_ts (0), overrun_count_curr (0),
overrun_count_curr (0), overrun_count (0) overrun_count (OVR_DISARMED)
{ {
srwlock = SRWLOCK_INIT; srwlock = SRWLOCK_INIT;
if (e != NULL) if (e != NULL)
@ -66,25 +65,14 @@ timer_tracker::~timer_tracker ()
ReleaseSRWLockExclusive (&srwlock); ReleaseSRWLockExclusive (&srwlock);
} }
static inline int64_t
timespec_to_us (const timespec& ts)
{
int64_t res = ts.tv_sec;
res *= USPERSEC;
res += (ts.tv_nsec + (NSPERSEC/USPERSEC) - 1) / (NSPERSEC/USPERSEC);
return res;
}
/* Returns 0 if arming successful, -1 if a signal is already queued. /* Returns 0 if arming successful, -1 if a signal is already queued.
If so, it also increments overrun_count. Only call under lock! */ If so, it also increments overrun_count. Only call under lock! */
LONG bool
timer_tracker::arm_overrun_event () timer_tracker::arm_overrun_event (LONG64 exp_cnt)
{ {
LONG ret; bool ret = (overrun_count != OVR_DISARMED);
ret = InterlockedExchange (&overrun_event_running, OVR_EVENT_ARMED); overrun_count += exp_cnt;
if (ret == OVR_EVENT_ARMED)
ret = InterlockedIncrement64 (&overrun_count);
return ret; return ret;
} }
@ -94,18 +82,17 @@ timer_tracker::disarm_overrun_event ()
LONG ret; LONG ret;
AcquireSRWLockExclusive (&srwlock); AcquireSRWLockExclusive (&srwlock);
ret = InterlockedExchange (&overrun_event_running, OVR_EVENT_DISARMED); if (overrun_count != OVR_DISARMED)
if (ret == OVR_EVENT_ARMED)
{ {
LONG64 ov_cnt; LONG64 ov_cnt;
InterlockedExchange64 (&ov_cnt, overrun_count); ov_cnt = overrun_count;
if (ov_cnt > DELAYTIMER_MAX || ov_cnt < 0) if (ov_cnt > DELAYTIMER_MAX || ov_cnt < 0)
overrun_count_curr = DELAYTIMER_MAX; overrun_count_curr = DELAYTIMER_MAX;
else else
overrun_count_curr = ov_cnt; overrun_count_curr = ov_cnt;
ret = overrun_count_curr; ret = overrun_count_curr;
InterlockedExchange64 (&overrun_count, 0); overrun_count = OVR_DISARMED;
} }
ReleaseSRWLockExclusive (&srwlock); ReleaseSRWLockExclusive (&srwlock);
return ret; return ret;
@ -150,18 +137,17 @@ timer_tracker::thread_func ()
ReleaseSRWLockExclusive (&srwlock); ReleaseSRWLockExclusive (&srwlock);
goto out; goto out;
} }
LONG64 exp_cnt = 0;
if (interval) if (interval)
{ {
/* Compute expiration count. */ /* Compute expiration count. */
LONG64 now = get_clock_now (); LONG64 now = get_clock_now ();
LONG64 ts = get_exp_ts (); LONG64 ts = get_exp_ts ();
LONG64 exp_cnt;
/* Make concessions for unexact realtime clock */ /* Make concessions for unexact realtime clock */
if (ts > now) if (ts > now)
ts = now - 1; ts = now - 1;
exp_cnt = (now - ts) / interval; exp_cnt = (now - ts + interval - 1) / interval;
InterlockedAdd64 (&overrun_count, exp_cnt);
ts += interval * exp_cnt; ts += interval * exp_cnt;
set_exp_ts (ts); set_exp_ts (ts);
/* NtSetTimer allows periods of up to 24 days only. If the time /* NtSetTimer allows periods of up to 24 days only. If the time
@ -180,7 +166,7 @@ timer_tracker::thread_func ()
{ {
case SIGEV_SIGNAL: case SIGEV_SIGNAL:
{ {
if (arm_overrun_event ()) if (arm_overrun_event (exp_cnt))
{ {
debug_printf ("%p timer signal already queued", this); debug_printf ("%p timer signal already queued", this);
break; break;
@ -196,7 +182,7 @@ timer_tracker::thread_func ()
} }
case SIGEV_THREAD: case SIGEV_THREAD:
{ {
if (arm_overrun_event ()) if (arm_overrun_event (exp_cnt))
{ {
debug_printf ("%p timer thread already queued", this); debug_printf ("%p timer thread already queued", this);
break; break;
@ -227,7 +213,7 @@ timer_tracker::thread_func ()
{ {
memset (&time_spec, 0, sizeof time_spec); memset (&time_spec, 0, sizeof time_spec);
exp_ts = 0; exp_ts = 0;
overrun_event_running = OVR_EVENT_DISARMED; overrun_count = OVR_DISARMED;
ReleaseSRWLockExclusive (&srwlock); ReleaseSRWLockExclusive (&srwlock);
goto out; goto out;
} }
@ -383,8 +369,7 @@ timer_tracker::settime (int flags, const itimerspec *new_value,
set_exp_ts (ts); set_exp_ts (ts);
time_spec = *new_value; time_spec = *new_value;
overrun_count_curr = 0; overrun_count_curr = 0;
overrun_count = 0; overrun_count = OVR_DISARMED;
overrun_event_running = OVR_EVENT_DISARMED;
/* Note: Advanced Power Settings -> Sleep -> Allow Wake Timers /* Note: Advanced Power Settings -> Sleep -> Allow Wake Timers
since W10 1709 */ since W10 1709 */
Resume = (clock_id == CLOCK_REALTIME_ALARM Resume = (clock_id == CLOCK_REALTIME_ALARM

View File

@ -6,8 +6,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifndef __TIMER_H__ #ifndef __POSIX_TIMER_H__
#define __TIMER_H__ #define __POSIX_TIMER_H__
#define TT_MAGIC 0x513e4a1c #define TT_MAGIC 0x513e4a1c
class timer_tracker class timer_tracker
@ -22,7 +22,6 @@ class timer_tracker
HANDLE sync_thr; HANDLE sync_thr;
LONG64 interval; LONG64 interval;
LONG64 exp_ts; LONG64 exp_ts;
LONG overrun_event_running;
LONG overrun_count_curr; LONG overrun_count_curr;
LONG64 overrun_count; LONG64 overrun_count;
@ -42,7 +41,7 @@ class timer_tracker
LONG64 get_interval () const { return interval; } LONG64 get_interval () const { return interval; }
void set_exp_ts (LONG64 ts) { exp_ts = ts; } void set_exp_ts (LONG64 ts) { exp_ts = ts; }
LONG arm_overrun_event (); bool arm_overrun_event (LONG64);
LONG disarm_overrun_event (); LONG disarm_overrun_event ();
int gettime (itimerspec *, bool); int gettime (itimerspec *, bool);
@ -52,4 +51,4 @@ class timer_tracker
static void fixup_after_fork (); static void fixup_after_fork ();
}; };
#endif /* __TIMER_H__ */ #endif /* __POSIX_TIMER_H__ */