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:
parent
de0ec284a3
commit
1f10a00ba7
|
@ -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
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
Loading…
Reference in New Issue