Cygwin: posix timers: implement timer_getoverrun
- set DELAYTIMER_MAX to INT_MAX - make sure to set siginfo_t::si_overrun, as on Linux Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
parent
961be8d726
commit
9e295a8d19
|
@ -1484,6 +1484,7 @@ timegm NOSIGFE
|
||||||
timelocal SIGFE
|
timelocal SIGFE
|
||||||
timer_create SIGFE
|
timer_create SIGFE
|
||||||
timer_delete SIGFE
|
timer_delete SIGFE
|
||||||
|
timer_getoverrun SIGFE
|
||||||
timer_gettime SIGFE
|
timer_gettime SIGFE
|
||||||
timer_settime SIGFE
|
timer_settime SIGFE
|
||||||
times SIGFE
|
times SIGFE
|
||||||
|
|
|
@ -27,6 +27,7 @@ details. */
|
||||||
#include "child_info.h"
|
#include "child_info.h"
|
||||||
#include "ntdll.h"
|
#include "ntdll.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
/* Definitions for code simplification */
|
/* Definitions for code simplification */
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
@ -1473,6 +1474,8 @@ sigpacket::process ()
|
||||||
|
|
||||||
if (handler == SIG_IGN)
|
if (handler == SIG_IGN)
|
||||||
{
|
{
|
||||||
|
if (si.si_code == SI_TIMER)
|
||||||
|
((timer_tracker *) si.si_tid)->disarm_event ();
|
||||||
sigproc_printf ("signal %d ignored", si.si_signo);
|
sigproc_printf ("signal %d ignored", si.si_signo);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1496,6 +1499,8 @@ sigpacket::process ()
|
||||||
|| si.si_signo == SIGCONT || si.si_signo == SIGWINCH
|
|| si.si_signo == SIGCONT || si.si_signo == SIGWINCH
|
||||||
|| si.si_signo == SIGURG)
|
|| si.si_signo == SIGURG)
|
||||||
{
|
{
|
||||||
|
if (si.si_code == SI_TIMER)
|
||||||
|
((timer_tracker *) si.si_tid)->disarm_event ();
|
||||||
sigproc_printf ("signal %d default is currently ignore", si.si_signo);
|
sigproc_printf ("signal %d default is currently ignore", si.si_signo);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1620,6 +1625,13 @@ _cygtls::call_signal_handler ()
|
||||||
|
|
||||||
sigset_t this_oldmask = set_process_mask_delta ();
|
sigset_t this_oldmask = set_process_mask_delta ();
|
||||||
|
|
||||||
|
if (infodata.si_code == SI_TIMER)
|
||||||
|
{
|
||||||
|
timer_tracker *tt = (timer_tracker *)
|
||||||
|
infodata.si_tid;
|
||||||
|
infodata.si_overrun = tt->disarm_event ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Save information locally on stack to pass to handler. */
|
/* Save information locally on stack to pass to handler. */
|
||||||
int thissig = sig;
|
int thissig = sig;
|
||||||
siginfo_t thissi = infodata;
|
siginfo_t thissi = infodata;
|
||||||
|
|
|
@ -501,12 +501,13 @@ details. */
|
||||||
329: Export sched_getcpu.
|
329: Export sched_getcpu.
|
||||||
330: Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE,
|
330: Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE,
|
||||||
CLOCK_BOOTTIME.
|
CLOCK_BOOTTIME.
|
||||||
|
331: Add timer_getoverrun, DELAYTIMER_MAX.
|
||||||
|
|
||||||
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
|
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
|
||||||
sigaltstack, sethostname. */
|
sigaltstack, sethostname. */
|
||||||
|
|
||||||
#define CYGWIN_VERSION_API_MAJOR 0
|
#define CYGWIN_VERSION_API_MAJOR 0
|
||||||
#define CYGWIN_VERSION_API_MINOR 330
|
#define CYGWIN_VERSION_API_MINOR 331
|
||||||
|
|
||||||
/* There is also a compatibity version number associated with the shared memory
|
/* There is also a compatibity version number associated with the shared memory
|
||||||
regions. It is incremented when incompatible changes are made to the shared
|
regions. It is incremented when incompatible changes are made to the shared
|
||||||
|
|
|
@ -184,7 +184,7 @@ details. */
|
||||||
|
|
||||||
/* Maximum number of timer expiration overruns. Not yet implemented. */
|
/* Maximum number of timer expiration overruns. Not yet implemented. */
|
||||||
#undef DELAYTIMER_MAX
|
#undef DELAYTIMER_MAX
|
||||||
/* #define DELAYTIMER_MAX >= _POSIX_DELAYTIMER_MAX */
|
#define DELAYTIMER_MAX __INT_MAX__
|
||||||
|
|
||||||
/* Maximum length of a host name. */
|
/* Maximum length of a host name. */
|
||||||
#undef HOST_NAME_MAX
|
#undef HOST_NAME_MAX
|
||||||
|
|
|
@ -24,6 +24,11 @@ What's new:
|
||||||
|
|
||||||
- Support Linux-specific linkat(2) flag AT_EMPTY_PATH.
|
- Support Linux-specific linkat(2) flag AT_EMPTY_PATH.
|
||||||
|
|
||||||
|
- Support overrun counter for posix timers (via timer_getoverrun() or
|
||||||
|
siginfo_t::si_overrun).
|
||||||
|
|
||||||
|
- New API: timer_getoverrun.
|
||||||
|
|
||||||
|
|
||||||
What changed:
|
What changed:
|
||||||
-------------
|
-------------
|
||||||
|
|
|
@ -20,6 +20,7 @@ details. */
|
||||||
#include "dtable.h"
|
#include "dtable.h"
|
||||||
#include "cygheap.h"
|
#include "cygheap.h"
|
||||||
#include "cygwait.h"
|
#include "cygwait.h"
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
#define _SA_NORESTART 0x8000
|
#define _SA_NORESTART 0x8000
|
||||||
|
|
||||||
|
@ -611,6 +612,12 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_my_tls.lock ();
|
_my_tls.lock ();
|
||||||
|
if (_my_tls.infodata.si_code == SI_TIMER)
|
||||||
|
{
|
||||||
|
timer_tracker *tt = (timer_tracker *)
|
||||||
|
_my_tls.infodata.si_tid;
|
||||||
|
_my_tls.infodata.si_overrun = tt->disarm_event ();
|
||||||
|
}
|
||||||
if (info)
|
if (info)
|
||||||
*info = _my_tls.infodata;
|
*info = _my_tls.infodata;
|
||||||
res = _my_tls.infodata.si_signo;
|
res = _my_tls.infodata.si_signo;
|
||||||
|
|
|
@ -17,6 +17,10 @@ details. */
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#define EVENT_DISARMED 0
|
||||||
|
#define EVENT_ARMED -1
|
||||||
|
#define EVENT_LOCK 1
|
||||||
|
|
||||||
timer_tracker NO_COPY ttstart (CLOCK_REALTIME, NULL);
|
timer_tracker NO_COPY ttstart (CLOCK_REALTIME, NULL);
|
||||||
|
|
||||||
class lock_timer_tracker
|
class lock_timer_tracker
|
||||||
|
@ -79,6 +83,9 @@ timer_tracker::timer_tracker (clockid_t c, const sigevent *e)
|
||||||
clock_id = c;
|
clock_id = c;
|
||||||
magic = TT_MAGIC;
|
magic = TT_MAGIC;
|
||||||
hcancel = NULL;
|
hcancel = NULL;
|
||||||
|
event_running = EVENT_DISARMED;
|
||||||
|
overrun_count_curr = 0;
|
||||||
|
overrun_count = 0;
|
||||||
if (this != &ttstart)
|
if (this != &ttstart)
|
||||||
{
|
{
|
||||||
lock_timer_tracker here;
|
lock_timer_tracker here;
|
||||||
|
@ -96,6 +103,57 @@ timespec_to_us (const timespec& ts)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 0 if arming successful, -1 if a signal is already queued.
|
||||||
|
If so, it also increments overrun_count. */
|
||||||
|
LONG
|
||||||
|
timer_tracker::arm_event ()
|
||||||
|
{
|
||||||
|
LONG ret;
|
||||||
|
|
||||||
|
while ((ret = InterlockedCompareExchange (&event_running, EVENT_ARMED,
|
||||||
|
EVENT_DISARMED)) == EVENT_LOCK)
|
||||||
|
yield ();
|
||||||
|
if (ret == EVENT_ARMED)
|
||||||
|
InterlockedIncrement64 (&overrun_count);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG
|
||||||
|
timer_tracker::disarm_event ()
|
||||||
|
{
|
||||||
|
LONG ret;
|
||||||
|
|
||||||
|
while ((ret = InterlockedCompareExchange (&event_running, EVENT_LOCK,
|
||||||
|
EVENT_ARMED)) == EVENT_LOCK)
|
||||||
|
yield ();
|
||||||
|
if (ret == EVENT_ARMED)
|
||||||
|
{
|
||||||
|
LONG64 ov_cnt;
|
||||||
|
|
||||||
|
InterlockedExchange64 (&ov_cnt, overrun_count);
|
||||||
|
if (ov_cnt > DELAYTIMER_MAX || ov_cnt < 0)
|
||||||
|
overrun_count_curr = DELAYTIMER_MAX;
|
||||||
|
else
|
||||||
|
overrun_count_curr = ov_cnt;
|
||||||
|
ret = overrun_count_curr;
|
||||||
|
InterlockedExchange64 (&overrun_count, 0);
|
||||||
|
InterlockedExchange (&event_running, EVENT_DISARMED);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
notify_thread_wrapper (void *arg)
|
||||||
|
{
|
||||||
|
timer_tracker *tt = (timer_tracker *) arg;
|
||||||
|
sigevent_t *evt = tt->sigevt ();
|
||||||
|
void * (*notify_func) (void *) = (void * (*) (void *))
|
||||||
|
evt->sigev_notify_function;
|
||||||
|
|
||||||
|
tt->disarm_event ();
|
||||||
|
return notify_func (evt->sigev_value.sival_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
timer_tracker::thread_func ()
|
timer_tracker::thread_func ()
|
||||||
{
|
{
|
||||||
|
@ -117,7 +175,10 @@ timer_tracker::thread_func ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sleepto_us = now;
|
int64_t num_intervals = (now - cur_sleepto_us) / interval_us;
|
||||||
|
InterlockedAdd64 (&overrun_count, num_intervals);
|
||||||
|
cur_sleepto_us += num_intervals * interval_us;
|
||||||
|
sleepto_us = cur_sleepto_us;
|
||||||
sleep_ms = 0;
|
sleep_ms = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,16 +200,27 @@ timer_tracker::thread_func ()
|
||||||
{
|
{
|
||||||
case SIGEV_SIGNAL:
|
case SIGEV_SIGNAL:
|
||||||
{
|
{
|
||||||
|
if (arm_event ())
|
||||||
|
{
|
||||||
|
debug_printf ("%p timer signal already queued", this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
siginfo_t si = {0};
|
siginfo_t si = {0};
|
||||||
si.si_signo = evp.sigev_signo;
|
si.si_signo = evp.sigev_signo;
|
||||||
si.si_sigval.sival_ptr = evp.sigev_value.sival_ptr;
|
|
||||||
si.si_code = SI_TIMER;
|
si.si_code = SI_TIMER;
|
||||||
|
si.si_tid = (timer_t) this;
|
||||||
|
si.si_sigval.sival_ptr = evp.sigev_value.sival_ptr;
|
||||||
debug_printf ("%p sending signal %d", this, evp.sigev_signo);
|
debug_printf ("%p sending signal %d", this, evp.sigev_signo);
|
||||||
sig_send (myself_nowait, si);
|
sig_send (myself_nowait, si);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SIGEV_THREAD:
|
case SIGEV_THREAD:
|
||||||
{
|
{
|
||||||
|
if (arm_event ())
|
||||||
|
{
|
||||||
|
debug_printf ("%p timer thread already queued", this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
pthread_t notify_thread;
|
pthread_t notify_thread;
|
||||||
debug_printf ("%p starting thread", this);
|
debug_printf ("%p starting thread", this);
|
||||||
pthread_attr_t *attr;
|
pthread_attr_t *attr;
|
||||||
|
@ -160,16 +232,13 @@ timer_tracker::thread_func ()
|
||||||
pthread_attr_init(attr = &default_attr);
|
pthread_attr_init(attr = &default_attr);
|
||||||
pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED);
|
pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rc = pthread_create (¬ify_thread, attr,
|
int rc = pthread_create (¬ify_thread, attr,
|
||||||
(void * (*) (void *)) evp.sigev_notify_function,
|
notify_thread_wrapper, this);
|
||||||
evp.sigev_value.sival_ptr);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
debug_printf ("thread creation failed, %E");
|
debug_printf ("thread creation failed, %E");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// FIXME: pthread_join?
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,9 +288,6 @@ timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalu
|
||||||
if (timespec_bad (value->it_value) || timespec_bad (value->it_interval))
|
if (timespec_bad (value->it_value) || timespec_bad (value->it_interval))
|
||||||
__leave;
|
__leave;
|
||||||
|
|
||||||
long long now = in_flags & TIMER_ABSTIME ?
|
|
||||||
0 : get_clock (clock_id)->usecs ();
|
|
||||||
|
|
||||||
lock_timer_tracker here;
|
lock_timer_tracker here;
|
||||||
cancel ();
|
cancel ();
|
||||||
|
|
||||||
|
@ -232,8 +298,23 @@ timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalu
|
||||||
interval_us = sleepto_us = 0;
|
interval_us = sleepto_us = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sleepto_us = now + timespec_to_us (value->it_value);
|
|
||||||
interval_us = timespec_to_us (value->it_interval);
|
interval_us = timespec_to_us (value->it_interval);
|
||||||
|
if (in_flags & TIMER_ABSTIME)
|
||||||
|
{
|
||||||
|
int64_t now = get_clock (clock_id)->usecs ();
|
||||||
|
|
||||||
|
sleepto_us = timespec_to_us (value->it_value);
|
||||||
|
if (sleepto_us <= now)
|
||||||
|
{
|
||||||
|
int64_t ov_cnt = (now - sleepto_us + (interval_us + 1))
|
||||||
|
/ interval_us;
|
||||||
|
InterlockedAdd64 (&overrun_count, ov_cnt);
|
||||||
|
sleepto_us += ov_cnt * interval_us;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sleepto_us = get_clock (clock_id)->usecs ()
|
||||||
|
+ timespec_to_us (value->it_value);
|
||||||
it_interval = value->it_interval;
|
it_interval = value->it_interval;
|
||||||
if (!hcancel)
|
if (!hcancel)
|
||||||
hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
|
hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
|
||||||
|
@ -285,6 +366,9 @@ void
|
||||||
timer_tracker::fixup_after_fork ()
|
timer_tracker::fixup_after_fork ()
|
||||||
{
|
{
|
||||||
ttstart.hcancel = ttstart.syncthread = NULL;
|
ttstart.hcancel = ttstart.syncthread = NULL;
|
||||||
|
ttstart.event_running = EVENT_DISARMED;
|
||||||
|
ttstart.overrun_count_curr = 0;
|
||||||
|
ttstart.overrun_count = 0;
|
||||||
for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */)
|
for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */)
|
||||||
{
|
{
|
||||||
timer_tracker *deleteme = tt->next;
|
timer_tracker *deleteme = tt->next;
|
||||||
|
@ -372,6 +456,26 @@ timer_settime (timer_t timerid, int flags,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
timer_getoverrun (timer_t timerid)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
timer_tracker *tt = (timer_tracker *) timerid;
|
||||||
|
if (!tt->is_timer_tracker ())
|
||||||
|
{
|
||||||
|
set_errno (EINVAL);
|
||||||
|
__leave;
|
||||||
|
}
|
||||||
|
ret = tt->getoverrun ();
|
||||||
|
}
|
||||||
|
__except (EFAULT) {}
|
||||||
|
__endtry
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" int
|
extern "C" int
|
||||||
timer_delete (timer_t timerid)
|
timer_delete (timer_t timerid)
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,6 +22,9 @@ class timer_tracker
|
||||||
HANDLE syncthread;
|
HANDLE syncthread;
|
||||||
int64_t interval_us;
|
int64_t interval_us;
|
||||||
int64_t sleepto_us;
|
int64_t sleepto_us;
|
||||||
|
LONG event_running;
|
||||||
|
LONG overrun_count_curr;
|
||||||
|
LONG64 overrun_count;
|
||||||
|
|
||||||
bool cancel ();
|
bool cancel ();
|
||||||
|
|
||||||
|
@ -29,10 +32,14 @@ class timer_tracker
|
||||||
timer_tracker (clockid_t, const sigevent *);
|
timer_tracker (clockid_t, const sigevent *);
|
||||||
~timer_tracker ();
|
~timer_tracker ();
|
||||||
inline bool is_timer_tracker () const { return magic == TT_MAGIC; }
|
inline bool is_timer_tracker () const { return magic == TT_MAGIC; }
|
||||||
|
inline sigevent_t *sigevt () { return &evp; }
|
||||||
|
inline int getoverrun () const { return overrun_count_curr; }
|
||||||
|
|
||||||
void gettime (itimerspec *);
|
void gettime (itimerspec *);
|
||||||
int settime (int, const itimerspec *, itimerspec *);
|
int settime (int, const itimerspec *, itimerspec *);
|
||||||
int clean_and_unhook ();
|
int clean_and_unhook ();
|
||||||
|
LONG arm_event ();
|
||||||
|
LONG disarm_event ();
|
||||||
|
|
||||||
DWORD thread_func ();
|
DWORD thread_func ();
|
||||||
static void fixup_after_fork ();
|
static void fixup_after_fork ();
|
||||||
|
|
|
@ -45,6 +45,15 @@ Support Linux-specific open(2) flag O_PATH.
|
||||||
- Support Linux-specific linkat(2) flag AT_EMPTY_PATH.
|
- Support Linux-specific linkat(2) flag AT_EMPTY_PATH.
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>
|
||||||
|
Support overrun counter for posix timers (via timer_getoverrun() or
|
||||||
|
siginfo_t::si_overrun).
|
||||||
|
</para></listitem>
|
||||||
|
|
||||||
|
<listitem><para>
|
||||||
|
New API: timer_getoverrun.
|
||||||
|
</para></listitem>
|
||||||
|
|
||||||
<listitem><para>
|
<listitem><para>
|
||||||
clock_nanosleep, pthread_condattr_setclock and timer_create now support
|
clock_nanosleep, pthread_condattr_setclock and timer_create now support
|
||||||
all clocks, except CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
|
all clocks, except CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
|
||||||
|
|
|
@ -1003,6 +1003,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
|
||||||
time
|
time
|
||||||
timer_create (see chapter "Implementation Notes")
|
timer_create (see chapter "Implementation Notes")
|
||||||
timer_delete
|
timer_delete
|
||||||
|
timer_getoverrun
|
||||||
timer_gettime
|
timer_gettime
|
||||||
timer_settime
|
timer_settime
|
||||||
times
|
times
|
||||||
|
@ -1587,7 +1588,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
|
||||||
pthread_mutex_consistent
|
pthread_mutex_consistent
|
||||||
putmsg
|
putmsg
|
||||||
setnetent
|
setnetent
|
||||||
timer_getoverrun
|
|
||||||
ulimit
|
ulimit
|
||||||
waitid
|
waitid
|
||||||
</screen>
|
</screen>
|
||||||
|
|
Loading…
Reference in New Issue