From 25737c53986a1fd18748017692a4af7eaad5639f Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 13 Jun 2017 00:51:47 +0100 Subject: [PATCH] Incorporate changes from Dasynq upstream. --- src/dasynq/dasynq-childproc.h | 18 ++--- src/dasynq/dasynq-itimer.h | 17 +++- src/dasynq/dasynq-kqueue.h | 34 +++++--- src/dasynq/dasynq-posixtimer.h | 16 +++- src/dasynq/dasynq-timerbase.h | 144 +++++++++++++++++++++++++-------- src/dasynq/dasynq-timerfd.h | 22 ++++- src/dasynq/dasynq.h | 25 ++++-- 7 files changed, 206 insertions(+), 70 deletions(-) diff --git a/src/dasynq/dasynq-childproc.h b/src/dasynq/dasynq-childproc.h index de663db..3b37e4b 100644 --- a/src/dasynq/dasynq-childproc.h +++ b/src/dasynq/dasynq-childproc.h @@ -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 ChildProcEvents : public Base @@ -157,12 +155,12 @@ template class ChildProcEvents : public Base template 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); } }; diff --git a/src/dasynq/dasynq-itimer.h b/src/dasynq/dasynq-itimer.h index 4045097..d2599fb 100644 --- a/src/dasynq/dasynq-itimer.h +++ b/src/dasynq/dasynq-itimer.h @@ -115,9 +115,12 @@ template class ITimerEvents : public timer_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 guard(Base::lock); auto &ts = timer_queue.node_data(timer_id); @@ -139,9 +142,12 @@ template class ITimerEvents : public timer_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 ITimerEvents : public timer_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); diff --git a/src/dasynq/dasynq-kqueue.h b/src/dasynq/dasynq-kqueue.h index a098a08..4f586b4 100644 --- a/src/dasynq/dasynq-kqueue.h +++ b/src/dasynq/dasynq-kqueue.h @@ -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 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 siginfo_t * sig_capture_templ::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); diff --git a/src/dasynq/dasynq-posixtimer.h b/src/dasynq/dasynq-posixtimer.h index 8131489..85a0304 100644 --- a/src/dasynq/dasynq-posixtimer.h +++ b/src/dasynq/dasynq-posixtimer.h @@ -147,9 +147,11 @@ template class PosixTimerEvents : public timer_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 guard(Base::lock); timer_queue_t &timer_queue = queue_for_clock(clock); @@ -174,9 +176,12 @@ template class PosixTimerEvents : public timer_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 PosixTimerEvents : public timer_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; diff --git a/src/dasynq/dasynq-timerbase.h b/src/dasynq/dasynq-timerbase.h index bc1b91c..b45ecb0 100644 --- a/src/dasynq/dasynq-timerbase.h +++ b/src/dasynq/dasynq-timerbase.h @@ -1,25 +1,125 @@ #ifndef DASYNQ_TIMERBASE_H_INCLUDED #define DASYNQ_TIMERBASE_H_INCLUDED +#include + #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::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; +using timer_queue_t = NaryHeap; 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 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 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) { diff --git a/src/dasynq/dasynq-timerfd.h b/src/dasynq/dasynq-timerfd.h index 8e49272..d92ab0f 100644 --- a/src/dasynq/dasynq-timerfd.h +++ b/src/dasynq/dasynq-timerfd.h @@ -62,9 +62,12 @@ template class TimerFdEvents : public timer_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 guard(Base::lock); auto &ts = queue.node_data(timer_id); @@ -175,9 +178,12 @@ template class TimerFdEvents : public timer_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 TimerFdEvents : public timer_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 TimerFdEvents : public timer_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; diff --git a/src/dasynq/dasynq.h b/src/dasynq/dasynq.h index 836139e..746fae6 100644 --- a/src/dasynq/dasynq.h +++ b/src/dasynq/dasynq.h @@ -669,6 +669,7 @@ class event_loop public: using loop_traits_t = LoopTraits; + using time_val = dasynq::time_val; private: template using EventDispatch = dprivate::EventDispatch; @@ -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 event_loop_n; @@ -2029,23 +2037,24 @@ class timer : private base_timer_watcher 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); } -- 2.25.1