Incorporate changes from Dasynq upstream.
authorDavin McCall <davmac@davmac.org>
Mon, 12 Jun 2017 23:51:47 +0000 (00:51 +0100)
committerDavin McCall <davmac@davmac.org>
Mon, 12 Jun 2017 23:58:55 +0000 (00:58 +0100)
src/dasynq/dasynq-childproc.h
src/dasynq/dasynq-itimer.h
src/dasynq/dasynq-kqueue.h
src/dasynq/dasynq-posixtimer.h
src/dasynq/dasynq-timerbase.h
src/dasynq/dasynq-timerfd.h
src/dasynq/dasynq.h

index de663dbaaa6119b57e7d39dba8842ba179b4341d..3b37e4b49c5c1674a33e80a0b2f7dc7f4356406e 100644 (file)
@@ -81,15 +81,13 @@ class pid_map
     }
 };
 
-inline namespace {
-    void sigchld_handler(int signum)
-    {
-        // If SIGCHLD has no handler (is ignored), SIGCHLD signals will
-        // not be queued for terminated child processes. (On Linux, the
-        // default disposition for SIGCHLD is to be ignored but *not* have
-        // this behavior, which seems inconsistent. Setting a handler doesn't
-        // hurt in any case).
-    }
+inline void sigchld_handler(int signum)
+{
+    // If SIGCHLD has no handler (is ignored), SIGCHLD signals will
+    // not be queued for terminated child processes. (On Linux, the
+    // default disposition for SIGCHLD is to be ignored but *not* have
+    // this behavior, which seems inconsistent. Setting a handler doesn't
+    // hurt in any case).
 }
 
 template <class Base> class ChildProcEvents : public Base
@@ -157,12 +155,12 @@ template <class Base> class ChildProcEvents : public Base
     
     template <typename T> void init(T *loop_mech)
     {
-        loop_mech->addSignalWatch(SIGCHLD, nullptr);
         struct sigaction chld_action;
         chld_action.sa_handler = sigchld_handler;
         sigemptyset(&chld_action.sa_mask);
         chld_action.sa_flags = 0;
         sigaction(SIGCHLD, &chld_action, nullptr);
+        loop_mech->addSignalWatch(SIGCHLD, nullptr);
         Base::init(loop_mech);
     }
 };
index 4045097ea6877a32a7bb518e5ef531da78c2aad8..d2599fbaf839fdaf1f3b04e83f3891e440fa1d1e 100644 (file)
@@ -115,9 +115,12 @@ template <class Base> class ITimerEvents : public timer_base<Base>
     
     // starts (if not started) a timer to timeout at the given time. Resets the expiry count to 0.
     //   enable: specifies whether to enable reporting of timeouts/intervals
-    void setTimer(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimer(timer_handle_t &timer_id, const time_val &timeouttv, const time_val &intervaltv,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         std::lock_guard<decltype(Base::lock)> guard(Base::lock);
 
         auto &ts = timer_queue.node_data(timer_id);
@@ -139,9 +142,12 @@ template <class Base> class ITimerEvents : public timer_base<Base>
     }
 
     // Set timer relative to current time:    
-    void setTimerRel(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimerRel(timer_handle_t &timer_id, const time_val &timeouttv, const time_val &intervaltv,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         // TODO consider caching current time somehow; need to decide then when to update cached value.
         struct timespec curtime;
         get_curtime(curtime);
@@ -191,6 +197,13 @@ template <class Base> class ITimerEvents : public timer_base<Base>
         }
     }
 
+    void get_time(time_val &tv, clock_type clock, bool force_update) noexcept
+    {
+        timespec ts;
+        get_time(ts, clock, force_update);
+        tv = ts;
+    }
+
     void get_time(timespec &ts, clock_type clock, bool force_update) noexcept
     {
         get_curtime(ts);
index a098a084db4db5a3f3f5a4e230aaba7f1b605beb..4f586b48475b8213d730e48a46b0c5f8fa78d96a 100644 (file)
@@ -107,7 +107,7 @@ static inline int sigtimedwait(const sigset_t *ssp, siginfo_t *info, struct time
 static inline void prepare_signal(int signo) { }
 static inline void unprep_signal(int signo) { }
 
-static bool get_siginfo(int signo, siginfo_t *siginfo)
+inline bool get_siginfo(int signo, siginfo_t *siginfo)
 {
     struct timespec timeout;
     timeout.tv_sec = 0;
@@ -121,33 +121,43 @@ static bool get_siginfo(int signo, siginfo_t *siginfo)
 #else
 
 // If we have no sigtimedwait implementation, we have to retrieve signal data by establishing a
-// signal handler:
+// signal handler.
 
-static siginfo_t * siginfo_p;
-
-static void signalHandler(int signo, siginfo_t *siginfo, void *v)
+// We need to declare and define a non-static data variable, "siginfo_p", in this header, without
+// violating the "one definition rule". The only way to do that is via a template, even though we
+// don't otherwise need a template here:
+template <typename T = decltype(nullptr)> class sig_capture_templ
 {
-    *siginfo_p = *siginfo;
-}
+    public:
+    static siginfo_t * siginfo_p;
+
+    static void signalHandler(int signo, siginfo_t *siginfo, void *v)
+    {
+        *siginfo_p = *siginfo;
+    }
+};
+template <typename T> siginfo_t * sig_capture_templ<T>::siginfo_p = nullptr;
+
+using sig_capture = sig_capture_templ<>;
 
-static inline void prepare_signal(int signo)
+inline void prepare_signal(int signo)
 {
     struct sigaction the_action;
-    the_action.sa_sigaction = signalHandler;
+    the_action.sa_sigaction = sig_capture::signalHandler;
     the_action.sa_flags = SA_SIGINFO;
     sigfillset(&the_action.sa_mask);
 
     sigaction(signo, &the_action, nullptr);
 }
 
-static inline void unprep_signal(int signo)
+inline void unprep_signal(int signo)
 {
     signal(signo, SIG_DFL);
 }
 
-static inline bool get_siginfo(int signo, siginfo_t *siginfo)
+inline bool get_siginfo(int signo, siginfo_t *siginfo)
 {
-    siginfo_p = siginfo;
+    sig_capture::siginfo_p = siginfo;
 
     sigset_t mask;
     sigfillset(&mask);
index 813148969184ee0593533d6d735193522af5875f..85a0304f39636208ac73de5caf84b1d71bb00f87 100644 (file)
@@ -147,9 +147,11 @@ template <class Base> class PosixTimerEvents : public timer_base<Base>
 
     // starts (if not started) a timer to timeout at the given time. Resets the expiry count to 0.
     //   enable: specifies whether to enable reporting of timeouts/intervals
-    void setTimer(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimer(timer_handle_t &timer_id, time_val &timeouttv, struct timespec &interval,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+
         std::lock_guard<decltype(Base::lock)> guard(Base::lock);
 
         timer_queue_t &timer_queue = queue_for_clock(clock);
@@ -174,9 +176,12 @@ template <class Base> class PosixTimerEvents : public timer_base<Base>
     }
 
     // Set timer relative to current time:
-    void setTimerRel(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimerRel(timer_handle_t &timer_id, const time_val &timeouttv, const time_val &intervaltv,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         // TODO consider caching current time somehow; need to decide then when to update cached value.
         struct timespec curtime;
         int posix_clock_id = (clock == clock_type::MONOTONIC) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
@@ -232,6 +237,13 @@ template <class Base> class PosixTimerEvents : public timer_base<Base>
         }
     }
 
+    void get_time(timeval &tv, clock_type clock, bool force_update) noexcept
+    {
+        timespec ts;
+        get_time(ts, clock, force_update);
+        tv = ts;
+    }
+
     void get_time(timespec &ts, clock_type clock, bool force_update) noexcept
     {
         int posix_clock_id = (clock == clock_type::MONOTONIC) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
index bc1b91c398ec98c921cdc015b99c4bfda451d603..b45ecb0f9e456d8bb98f095bb16942d590d661e0 100644 (file)
 #ifndef DASYNQ_TIMERBASE_H_INCLUDED
 #define DASYNQ_TIMERBASE_H_INCLUDED
 
+#include <utility>
+
 #include "dasynq-naryheap.h"
 
 namespace dasynq {
 
-class TimerData
+// time_val provides a wrapper around struct timespec, which overloads operators appropriately.
+class time_val
 {
+    struct timespec time;
+
     public:
-    struct timespec interval_time; // interval (if 0, one-off timer)
+    using second_t = decltype(time.tv_sec);
+    using nsecond_t = decltype(time.tv_nsec);
+
+    time_val()
+    {
+        // uninitialised!
+    }
+
+    time_val(const struct timespec &t)
+    {
+        time = t;
+    }
+
+    time_val(second_t s, nsecond_t ns)
+    {
+        time.tv_sec = s;
+        time.tv_nsec = ns;
+    }
+
+    second_t seconds() const { return time.tv_sec; }
+    nsecond_t nseconds() const { return time.tv_nsec; }
+
+    second_t & seconds() { return time.tv_sec; }
+    nsecond_t & nseconds() { return time.tv_nsec; }
+
+    //void set_seconds(second_t s) { time.tv_sec = s; }
+    //void set_nseconds(nsecond_t ns) { time.tv_nsec = ns; }
+    //void dec_seconds() { time.tv_sec--; }
+    //void inc_seconds() { time.tv_sec++; }
+
+    operator timespec() const
+    {
+       return time;
+    }
+};
+
+inline time_val operator-(const time_val &t1, const time_val &t2)
+{
+    time_val diff;
+    diff.seconds() = t1.seconds() - t2.seconds();
+    if (t1.nseconds() > t2.nseconds()) {
+        diff.nseconds() = t1.nseconds() - t2.nseconds();
+    }
+    else {
+        diff.nseconds() = 1000000000 - t2.nseconds() + t1.nseconds();
+        diff.seconds()--;
+    }
+    return diff;
+}
+
+inline time_val operator+(const time_val &t1, const time_val &t2)
+{
+    auto ns = t1.nseconds() + t2.nseconds();
+    auto s = t1.seconds() + t2.seconds();
+    static_assert(std::numeric_limits<decltype(ns)>::max() >= 2000000000, "type too small");
+    if (ns >= 1000000000) {
+        ns -= 1000000000;
+        s++;
+    }
+    return time_val(s, ns);
+}
+
+inline time_val &operator+=(time_val &t1, const time_val &t2)
+{
+    auto nsum = t1.nseconds() + t2.nseconds();
+    t1.seconds() = t1.seconds() + t2.seconds();
+    if (nsum >= 1000000000) {
+        nsum -= 1000000000;
+        t1.seconds()++;
+    }
+    t1.nseconds() = nsum;
+    return t1;
+}
+
+inline bool operator<(const time_val &t1, const time_val &t2)
+{
+    if (t1.seconds() < t2.seconds()) return true;
+    if (t1.seconds() == t2.seconds() && t1.nseconds() < t2.nseconds()) return true;
+    return false;
+}
+
+inline bool operator==(const time_val &t1, const time_val &t2)
+{
+    return (t1.seconds() == t2.seconds() && t1.nseconds() == t2.nseconds());
+}
+
+using std::rel_ops::operator !=;
+using std::rel_ops::operator <=;
+using std::rel_ops::operator >;
+using std::rel_ops::operator >=;
+
+// Data corresponding to a single timer
+class timer_data
+{
+    public:
+    time_val interval_time; // interval (if 0, one-off timer)
     int expiry_count;  // number of times expired
     bool enabled;   // whether timer reports events
     void *userdata;
 
-    TimerData(void *udata = nullptr) : interval_time({0,0}), expiry_count(0), enabled(true), userdata(udata)
+    timer_data(void *udata = nullptr) : interval_time(0,0), expiry_count(0), enabled(true), userdata(udata)
     {
         // constructor
     }
 };
 
-class CompareTimespec
+class compare_timespec
 {
     public:
     bool operator()(const struct timespec &a, const struct timespec &b)
@@ -36,7 +136,7 @@ class CompareTimespec
     }
 };
 
-using timer_queue_t = NaryHeap<TimerData, struct timespec, CompareTimespec>;
+using timer_queue_t = NaryHeap<timer_data, struct timespec, compare_timespec>;
 using timer_handle_t = timer_queue_t::handle_t;
 
 static inline void init_timer_handle(timer_handle_t &hnd) noexcept
@@ -139,11 +239,11 @@ template <typename Base> class timer_base : public Base
         while (timeout->tv_sec < curtime.tv_sec || (timeout->tv_sec == curtime.tv_sec &&
                 timeout->tv_nsec <= curtime.tv_nsec)) {
             auto & thandle = queue.get_root();
-            TimerData &data = queue.node_data(thandle);
-            timespec &interval = data.interval_time;
+            timer_data &data = queue.node_data(thandle);
+            time_val &interval = data.interval_time;
             data.expiry_count++;
             queue.pull_root();
-            if (interval.tv_sec == 0 && interval.tv_nsec == 0) {
+            if (interval.seconds() == 0 && interval.nseconds() == 0) {
                 // Non periodic timer
                 if (data.enabled) {
                     data.enabled = false;
@@ -157,38 +257,16 @@ template <typename Base> class timer_base : public Base
             }
             else {
                 // First calculate the overrun in time:
-                struct timespec diff;
-                diff.tv_sec = curtime.tv_sec - timeout->tv_sec;
-                if (curtime.tv_nsec > timeout->tv_nsec) {
-                    diff.tv_nsec = curtime.tv_nsec - timeout->tv_nsec;
-                }
-                else {
-                    diff.tv_nsec = 1000000000 - timeout->tv_nsec + curtime.tv_nsec;
-                    diff.tv_sec--;
-                }
+                time_val overrun = time_val(curtime) - time_val(*timeout);
 
                 // Now we have to divide the time overrun by the period to find the
                 // interval overrun. This requires a division of a value not representable
                 // as a long...
                 struct timespec rem;
-                data.expiry_count += divide_timespec(diff, interval, rem);
+                data.expiry_count += divide_timespec(overrun, interval, rem);
 
                 // new time is current time + interval - remainder:
-                struct timespec newtime = curtime;
-                newtime.tv_sec += interval.tv_sec;
-                newtime.tv_nsec += interval.tv_nsec;
-                if (newtime.tv_nsec > 1000000000) {
-                    newtime.tv_nsec -= 1000000000;
-                    newtime.tv_sec++;
-                }
-                newtime.tv_sec -= rem.tv_sec;
-                if (rem.tv_nsec > newtime.tv_nsec) {
-                    newtime.tv_nsec += 1000000000 - rem.tv_nsec;
-                    newtime.tv_sec--;
-                }
-                else {
-                    newtime.tv_nsec -= rem.tv_nsec;
-                }
+                time_val newtime = curtime + interval - rem;
 
                 queue.insert(thandle, newtime);
                 if (data.enabled) {
index 8e49272a8988e9f2763c0d501e9dbd209a6e3fdb..d92ab0f090febf2db7949d1983a9f61cf7b9a6ef 100644 (file)
@@ -62,9 +62,12 @@ template <class Base> class TimerFdEvents : public timer_base<Base>
         set_timer_from_queue(fd, queue);
     }
 
-    void setTimer(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimer(timer_handle_t & timer_id, const time_val &timeouttv, const time_val &intervaltv,
             timer_queue_t &queue, int fd, bool enable) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         std::lock_guard<decltype(Base::lock)> guard(Base::lock);
 
         auto &ts = queue.node_data(timer_id);
@@ -175,9 +178,12 @@ template <class Base> class TimerFdEvents : public timer_base<Base>
 
     // starts (if not started) a timer to timeout at the given time. Resets the expiry count to 0.
     //   enable: specifies whether to enable reporting of timeouts/intervals
-    void setTimer(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimer(timer_handle_t & timer_id, const time_val &timeouttv, const time_val &intervaltv,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         switch (clock) {
         case clock_type::SYSTEM:
             setTimer(timer_id, timeout, interval, wallclock_queue, systemtime_fd, enable);
@@ -191,9 +197,12 @@ template <class Base> class TimerFdEvents : public timer_base<Base>
     }
 
     // Set timer relative to current time:    
-    void setTimerRel(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval,
+    void setTimerRel(timer_handle_t & timer_id, const time_val &timeouttv, const time_val &intervaltv,
             bool enable, clock_type clock = clock_type::MONOTONIC) noexcept
     {
+        timespec timeout = timeouttv;
+        timespec interval = intervaltv;
+
         clockid_t sclock;
         switch (clock) {
         case clock_type::SYSTEM:
@@ -241,6 +250,13 @@ template <class Base> class TimerFdEvents : public timer_base<Base>
         }
     }
 
+    void get_time(time_val &tv, clock_type clock, bool force_update) noexcept
+    {
+        timespec ts;
+        get_time(ts, clock, force_update);
+        tv = ts;
+    }
+
     void get_time(timespec &ts, clock_type clock, bool force_update) noexcept
     {
         int posix_clock_id = (clock == clock_type::MONOTONIC) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
index 836139e93ea2ba0b2a38b05f0acdc22cb401c47b..746fae6efd1dd82171dd2fc0fedd344373f03e37 100644 (file)
@@ -669,6 +669,7 @@ class event_loop
 
     public:
     using loop_traits_t = LoopTraits;
+    using time_val = dasynq::time_val;
     
     private:
     template <typename T, typename U> using EventDispatch = dprivate::EventDispatch<T,U>;
@@ -949,24 +950,26 @@ class event_loop
         }
     }
     
-    void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout, clock_type clock) noexcept
+    void setTimer(BaseTimerWatcher *callBack, const timespec &timeout, clock_type clock) noexcept
     {
         struct timespec interval {0, 0};
         loop_mech.setTimer(callBack->timer_handle, timeout, interval, true, clock);
     }
     
-    void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval, clock_type clock) noexcept
+    void setTimer(BaseTimerWatcher *callBack, const timespec &timeout, const timespec &interval,
+            clock_type clock) noexcept
     {
         loop_mech.setTimer(callBack->timer_handle, timeout, interval, true, clock);
     }
 
-    void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout, clock_type clock) noexcept
+    void setTimerRel(BaseTimerWatcher *callBack, const timespec &timeout, clock_type clock) noexcept
     {
         struct timespec interval {0, 0};
         loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true, clock);
     }
     
-    void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval, clock_type clock) noexcept
+    void setTimerRel(BaseTimerWatcher *callBack, const timespec &timeout,
+            const timespec &interval, clock_type clock) noexcept
     {
         loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true, clock);
     }
@@ -1369,6 +1372,11 @@ class event_loop
     {
         loop_mech.get_time(ts, clock, force_update);
     }
+
+    void get_time(time_val &tv, clock_type clock, bool force_update = false) noexcept
+    {
+        loop_mech.get_time(tv, clock, force_update);
+    }
 };
 
 typedef event_loop<null_mutex> event_loop_n;
@@ -2029,23 +2037,24 @@ class timer : private base_timer_watcher<typename EventLoop::mutex_t>
         eloop.registerTimer(this, clock);
     }
     
-    void arm_timer(EventLoop &eloop, struct timespec &timeout) noexcept
+    void arm_timer(EventLoop &eloop, const timespec &timeout) noexcept
     {
         eloop.setTimer(this, timeout, base_t::clock);
     }
     
-    void arm_timer(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept
+    void arm_timer(EventLoop &eloop, const timespec &timeout, const timespec &interval) noexcept
     {
         eloop.setTimer(this, timeout, interval, base_t::clock);
     }
 
     // Arm timer, relative to now:
-    void arm_timer_rel(EventLoop &eloop, struct timespec &timeout) noexcept
+    void arm_timer_rel(EventLoop &eloop, const timespec &timeout) noexcept
     {
         eloop.setTimerRel(this, timeout, base_t::clock);
     }
     
-    void arm_timer_rel(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept
+    void arm_timer_rel(EventLoop &eloop, const timespec &timeout,
+            const timespec &interval) noexcept
     {
         eloop.setTimerRel(this, timeout, interval, base_t::clock);
     }