}
};
-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
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);
}
};
// 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);
}
// 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);
}
}
+ 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);
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;
#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);
// 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);
}
// 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;
}
}
+ 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;
#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)
}
};
-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
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;
}
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) {
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);
// 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);
}
// 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:
}
}
+ 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;
public:
using loop_traits_t = LoopTraits;
+ using time_val = dasynq::time_val;
private:
template <typename T, typename U> using EventDispatch = dprivate::EventDispatch<T,U>;
}
}
- 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);
}
{
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;
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);
}