Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2019-01-12 23:19:52 +0300
committerCorinna Vinschen <corinna@vinschen.de>2019-01-12 23:26:07 +0300
commit9e295a8d193e138808931816f5858761ff08f402 (patch)
tree62d319602869f3a2ee4991a4234b1eafc8ffe28c /winsup/cygwin
parent961be8d726a81918d8d34c9dae603e7820a2416f (diff)
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>
Diffstat (limited to 'winsup/cygwin')
-rw-r--r--winsup/cygwin/common.din1
-rw-r--r--winsup/cygwin/exceptions.cc12
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rw-r--r--winsup/cygwin/include/limits.h2
-rw-r--r--winsup/cygwin/release/2.12.05
-rw-r--r--winsup/cygwin/signal.cc7
-rw-r--r--winsup/cygwin/timer.cc124
-rw-r--r--winsup/cygwin/timer.h7
8 files changed, 149 insertions, 12 deletions
diff --git a/winsup/cygwin/common.din b/winsup/cygwin/common.din
index d1d955542..a6363e1ba 100644
--- a/winsup/cygwin/common.din
+++ b/winsup/cygwin/common.din
@@ -1484,6 +1484,7 @@ timegm NOSIGFE
timelocal SIGFE
timer_create SIGFE
timer_delete SIGFE
+timer_getoverrun SIGFE
timer_gettime SIGFE
timer_settime SIGFE
times SIGFE
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 419b0976f..8c1b3b4e6 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -27,6 +27,7 @@ details. */
#include "child_info.h"
#include "ntdll.h"
#include "exception.h"
+#include "timer.h"
/* Definitions for code simplification */
#ifdef __x86_64__
@@ -1473,6 +1474,8 @@ sigpacket::process ()
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);
goto done;
}
@@ -1496,6 +1499,8 @@ sigpacket::process ()
|| si.si_signo == SIGCONT || si.si_signo == SIGWINCH
|| 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);
goto done;
}
@@ -1620,6 +1625,13 @@ _cygtls::call_signal_handler ()
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. */
int thissig = sig;
siginfo_t thissi = infodata;
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index bb1fa9746..1bcec331f 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -501,12 +501,13 @@ details. */
329: Export sched_getcpu.
330: Add CLOCK_REALTIME_COARSE, CLOCK_MONOTONIC_RAW, CLOCK_MONOTONIC_COARSE,
CLOCK_BOOTTIME.
+ 331: Add timer_getoverrun, DELAYTIMER_MAX.
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 330
+#define CYGWIN_VERSION_API_MINOR 331
/* There is also a compatibity version number associated with the shared memory
regions. It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/include/limits.h b/winsup/cygwin/include/limits.h
index 3550c4fcb..524a469e4 100644
--- a/winsup/cygwin/include/limits.h
+++ b/winsup/cygwin/include/limits.h
@@ -184,7 +184,7 @@ details. */
/* Maximum number of timer expiration overruns. Not yet implemented. */
#undef DELAYTIMER_MAX
-/* #define DELAYTIMER_MAX >= _POSIX_DELAYTIMER_MAX */
+#define DELAYTIMER_MAX __INT_MAX__
/* Maximum length of a host name. */
#undef HOST_NAME_MAX
diff --git a/winsup/cygwin/release/2.12.0 b/winsup/cygwin/release/2.12.0
index b77278238..15f07e021 100644
--- a/winsup/cygwin/release/2.12.0
+++ b/winsup/cygwin/release/2.12.0
@@ -24,6 +24,11 @@ What's new:
- 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:
-------------
diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc
index b3e257b23..74d6eb675 100644
--- a/winsup/cygwin/signal.cc
+++ b/winsup/cygwin/signal.cc
@@ -20,6 +20,7 @@ details. */
#include "dtable.h"
#include "cygheap.h"
#include "cygwait.h"
+#include "timer.h"
#define _SA_NORESTART 0x8000
@@ -611,6 +612,12 @@ sigwait_common (const sigset_t *set, siginfo_t *info, PLARGE_INTEGER waittime)
else
{
_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)
*info = _my_tls.infodata;
res = _my_tls.infodata.si_signo;
diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc
index 0aeba5830..e38decb9a 100644
--- a/winsup/cygwin/timer.cc
+++ b/winsup/cygwin/timer.cc
@@ -17,6 +17,10 @@ details. */
#include "timer.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);
class lock_timer_tracker
@@ -79,6 +83,9 @@ timer_tracker::timer_tracker (clockid_t c, const sigevent *e)
clock_id = c;
magic = TT_MAGIC;
hcancel = NULL;
+ event_running = EVENT_DISARMED;
+ overrun_count_curr = 0;
+ overrun_count = 0;
if (this != &ttstart)
{
lock_timer_tracker here;
@@ -96,6 +103,57 @@ timespec_to_us (const timespec& ts)
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
timer_tracker::thread_func ()
{
@@ -117,7 +175,10 @@ timer_tracker::thread_func ()
}
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;
}
@@ -139,16 +200,27 @@ timer_tracker::thread_func ()
{
case SIGEV_SIGNAL:
{
+ if (arm_event ())
+ {
+ debug_printf ("%p timer signal already queued", this);
+ break;
+ }
siginfo_t si = {0};
si.si_signo = evp.sigev_signo;
- si.si_sigval.sival_ptr = evp.sigev_value.sival_ptr;
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);
sig_send (myself_nowait, si);
break;
}
case SIGEV_THREAD:
{
+ if (arm_event ())
+ {
+ debug_printf ("%p timer thread already queued", this);
+ break;
+ }
pthread_t notify_thread;
debug_printf ("%p starting thread", this);
pthread_attr_t *attr;
@@ -160,16 +232,13 @@ timer_tracker::thread_func ()
pthread_attr_init(attr = &default_attr);
pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED);
}
-
int rc = pthread_create (&notify_thread, attr,
- (void * (*) (void *)) evp.sigev_notify_function,
- evp.sigev_value.sival_ptr);
+ notify_thread_wrapper, this);
if (rc)
{
debug_printf ("thread creation failed, %E");
return 0;
}
- // FIXME: pthread_join?
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))
__leave;
- long long now = in_flags & TIMER_ABSTIME ?
- 0 : get_clock (clock_id)->usecs ();
-
lock_timer_tracker here;
cancel ();
@@ -232,8 +298,23 @@ timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalu
interval_us = sleepto_us = 0;
else
{
- sleepto_us = now + timespec_to_us (value->it_value);
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;
if (!hcancel)
hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
@@ -285,6 +366,9 @@ void
timer_tracker::fixup_after_fork ()
{
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 */)
{
timer_tracker *deleteme = tt->next;
@@ -373,6 +457,26 @@ timer_settime (timer_t timerid, int flags,
}
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
timer_delete (timer_t timerid)
{
int ret = -1;
diff --git a/winsup/cygwin/timer.h b/winsup/cygwin/timer.h
index 0442c37d1..f75cd487c 100644
--- a/winsup/cygwin/timer.h
+++ b/winsup/cygwin/timer.h
@@ -22,6 +22,9 @@ class timer_tracker
HANDLE syncthread;
int64_t interval_us;
int64_t sleepto_us;
+ LONG event_running;
+ LONG overrun_count_curr;
+ LONG64 overrun_count;
bool cancel ();
@@ -29,10 +32,14 @@ class timer_tracker
timer_tracker (clockid_t, const sigevent *);
~timer_tracker ();
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 *);
int settime (int, const itimerspec *, itimerspec *);
int clean_and_unhook ();
+ LONG arm_event ();
+ LONG disarm_event ();
DWORD thread_func ();
static void fixup_after_fork ();