]> sourceware.org Git - newlib-cygwin.git/commitdiff
Cygwin: posix timers: implement timer_getoverrun
authorCorinna Vinschen <corinna@vinschen.de>
Sat, 12 Jan 2019 20:19:52 +0000 (21:19 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Sat, 12 Jan 2019 20:26:07 +0000 (21:26 +0100)
- 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>
winsup/cygwin/common.din
winsup/cygwin/exceptions.cc
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/limits.h
winsup/cygwin/release/2.12.0
winsup/cygwin/signal.cc
winsup/cygwin/timer.cc
winsup/cygwin/timer.h
winsup/doc/new-features.xml
winsup/doc/posix.xml

index d1d95554203a76143e878a0be3134f358ad6897e..a6363e1ba0e792473d72c4459b4439762b5da18c 100644 (file)
@@ -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
index 419b0976ffdd2e94f19f9d8827737a50c22ab688..8c1b3b4e6f226f4fd2e46a9bcd4d9be06668418f 100644 (file)
@@ -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;
index bb1fa9746cce1d64a159411403abfa27d5682597..1bcec331f09e3cfb0797a64b5711dd36deb1c38a 100644 (file)
@@ -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
index 3550c4fcb82589062b410b4f9b0c4e5fa09eb2e8..524a469e47b50166ea8d742f38f8afebd48c5687 100644 (file)
@@ -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
index b772782383e7f000d340f6e951f70883ac45ae40..15f07e02114cc9d33d6e3d806cc58d43fe2f2fba 100644 (file)
@@ -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:
 -------------
index b3e257b239df128ca2df05ec01d8b179dc6e9705..74d6eb675c074a4aed46184190d0bb6d8c8a1355 100644 (file)
@@ -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;
index 0aeba5830482b9cc40d2c5dac0eac8f2be6f7dce..e38decb9a80d883f558e84a3fb8d80d7c1d79fbb 100644 (file)
@@ -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;
@@ -372,6 +456,26 @@ timer_settime (timer_t timerid, int flags,
   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
 timer_delete (timer_t timerid)
 {
index 0442c37d1fdcb816a485c4f7dbbd1b19303ee87d..f75cd487cc96a39daf00d9ece81a982872a2bd3c 100644 (file)
@@ -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 ();
index 6af7270f9ea22cc819681a2961f82100c39f6273..2e1645fbe0401d60661341adc9cb440eb42c7497 100644 (file)
@@ -45,6 +45,15 @@ Support Linux-specific open(2) flag O_PATH.
 - Support Linux-specific linkat(2) flag AT_EMPTY_PATH.
 </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>
 clock_nanosleep, pthread_condattr_setclock and timer_create now support
 all clocks, except CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
index afa1ca409a6f9c8152f19c0a00963b4e2f1e30b7..021b5962c14fc65dcdd65c875daef64e150f4ce1 100644 (file)
@@ -1003,6 +1003,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     time
     timer_create               (see chapter "Implementation Notes")
     timer_delete
+    timer_getoverrun
     timer_gettime
     timer_settime
     times
@@ -1587,7 +1588,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
     pthread_mutex_consistent
     putmsg
     setnetent
-    timer_getoverrun
     ulimit
     waitid
 </screen>
This page took 0.178257 seconds and 5 git commands to generate.