From b49af36c0509a0febf28cfee4b7ae10c56f5166b Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sun, 19 Mar 2017 22:23:49 +0000 Subject: [PATCH] Update Dasynq library, and API usage throughout. --- src/control.cc | 38 ++-- src/control.h | 14 +- src/dasynq/dasynq-childproc.h | 3 + src/dasynq/dasynq-config.h | 32 +++ src/dasynq/dasynq-epoll.h | 7 - src/dasynq/dasynq-flags.h | 12 + src/dasynq/dasynq-interrupt.h | 98 ++++++++ src/dasynq/dasynq-itimer.h | 111 +++++----- src/dasynq/dasynq-kqueue.h | 102 ++++++--- src/dasynq/dasynq-svec.h | 3 +- src/dasynq/dasynq-timerbase.h | 46 ++++ src/dasynq/dasynq-timerfd.h | 335 ++++++++++++++++------------ src/dasynq/dasynq.h | 405 ++++++++++++++++++---------------- src/dinit-log.cc | 20 +- src/dinit.cc | 20 +- src/service.cc | 12 +- src/service.h | 8 +- 17 files changed, 787 insertions(+), 479 deletions(-) create mode 100644 src/dasynq/dasynq-config.h create mode 100644 src/dasynq/dasynq-interrupt.h create mode 100644 src/dasynq/dasynq-timerbase.h diff --git a/src/control.cc b/src/control.cc index 889870c..0580301 100644 --- a/src/control.cc +++ b/src/control.cc @@ -54,7 +54,7 @@ bool ControlConn::processPacket() char outbuf[] = { DINIT_RP_BADREQ }; if (! queuePacket(outbuf, 1)) return false; bad_conn_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); } return true; } @@ -78,7 +78,7 @@ bool ControlConn::processFindLoad(int pktType) char badreqRep[] = { DINIT_RP_BADREQ }; if (! queuePacket(badreqRep, 1)) return false; bad_conn_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); return true; } @@ -154,7 +154,7 @@ bool ControlConn::processStartStop(int pktType) char badreqRep[] = { DINIT_RP_BADREQ }; if (! queuePacket(badreqRep, 1)) return false; bad_conn_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); return true; } else { @@ -226,7 +226,7 @@ bool ControlConn::processUnpinService() char badreqRep[] = { DINIT_RP_BADREQ }; if (! queuePacket(badreqRep, 1)) return false; bad_conn_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); return true; } else { @@ -318,7 +318,7 @@ bool ControlConn::queuePacket(const char *pkt, unsigned size) noexcept // If the queue is empty, we can try to write the packet out now rather than queueing it. // If the write is unsuccessful or partial, we queue the remainder. if (was_empty) { - int wr = write(iob.getWatchedFd(), pkt, size); + int wr = write(iob.get_watched_fd(), pkt, size); if (wr == -1) { if (errno == EPIPE) { return false; @@ -332,7 +332,7 @@ bool ControlConn::queuePacket(const char *pkt, unsigned size) noexcept else { if ((unsigned)wr == size) { // Ok, all written. - iob.setWatches(in_flag); + iob.set_watches(in_flag); return true; } pkt += wr; @@ -343,7 +343,7 @@ bool ControlConn::queuePacket(const char *pkt, unsigned size) noexcept // Create a vector out of the (remaining part of the) packet: try { outbuf.emplace_back(pkt, pkt + size); - iob.setWatches(in_flag | OUT_EVENTS); + iob.set_watches(in_flag | OUT_EVENTS); return true; } catch (std::bad_alloc &baexc) { @@ -357,7 +357,7 @@ bool ControlConn::queuePacket(const char *pkt, unsigned size) noexcept return false; } else { - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); return true; } } @@ -373,7 +373,7 @@ bool ControlConn::queuePacket(std::vector &&pkt) noexcept if (was_empty) { outpkt_index = 0; // We can try sending the packet immediately: - int wr = write(iob.getWatchedFd(), pkt.data(), pkt.size()); + int wr = write(iob.get_watched_fd(), pkt.data(), pkt.size()); if (wr == -1) { if (errno == EPIPE) { return false; @@ -387,7 +387,7 @@ bool ControlConn::queuePacket(std::vector &&pkt) noexcept else { if ((unsigned)wr == pkt.size()) { // Ok, all written. - iob.setWatches(in_flag); + iob.set_watches(in_flag); return true; } outpkt_index = wr; @@ -396,7 +396,7 @@ bool ControlConn::queuePacket(std::vector &&pkt) noexcept try { outbuf.emplace_back(pkt); - iob.setWatches(in_flag | OUT_EVENTS); + iob.set_watches(in_flag | OUT_EVENTS); return true; } catch (std::bad_alloc &baexc) { @@ -410,7 +410,7 @@ bool ControlConn::queuePacket(std::vector &&pkt) noexcept return false; } else { - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); return true; } } @@ -424,7 +424,7 @@ bool ControlConn::rollbackComplete() noexcept bool ControlConn::dataReady() noexcept { - int fd = iob.getWatchedFd(); + int fd = iob.get_watched_fd(); int r = rbuf.fill(fd); @@ -455,11 +455,11 @@ bool ControlConn::dataReady() noexcept // Too big packet log(LogLevel::WARN, "Received too-large control package; dropping connection"); bad_conn_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); } else { int out_flags = (bad_conn_close || !outbuf.empty()) ? OUT_EVENTS : 0; - iob.setWatches(IN_EVENTS | out_flags); + iob.set_watches(IN_EVENTS | out_flags); } return false; @@ -471,14 +471,14 @@ bool ControlConn::sendData() noexcept if (oom_close) { // Send oom response char oomBuf[] = { DINIT_RP_OOM }; - write(iob.getWatchedFd(), oomBuf, 1); + write(iob.get_watched_fd(), oomBuf, 1); } return true; } vector & pkt = outbuf.front(); char *data = pkt.data(); - int written = write(iob.getWatchedFd(), data + outpkt_index, pkt.size() - outpkt_index); + int written = write(iob.get_watched_fd(), data + outpkt_index, pkt.size() - outpkt_index); if (written == -1) { if (errno == EPIPE) { // read end closed @@ -501,7 +501,7 @@ bool ControlConn::sendData() noexcept outpkt_index = 0; if (outbuf.empty() && ! oom_close) { if (! bad_conn_close) { - iob.setWatches(IN_EVENTS); + iob.set_watches(IN_EVENTS); } else { return true; @@ -514,7 +514,7 @@ bool ControlConn::sendData() noexcept ControlConn::~ControlConn() noexcept { - close(iob.getWatchedFd()); + close(iob.get_watched_fd()); iob.deregister(*loop); // Clear service listeners diff --git a/src/control.h b/src/control.h index 9f29633..e3b754a 100644 --- a/src/control.h +++ b/src/control.h @@ -47,16 +47,16 @@ extern int active_control_conns; class ServiceSet; class ServiceRecord; -class ControlConnWatcher : public EventLoop_t::BidiFdWatcher +class ControlConnWatcher : public EventLoop_t::bidi_fd_watcher { inline rearm receiveEvent(EventLoop_t &loop, int fd, int flags) noexcept; - rearm readReady(EventLoop_t &loop, int fd) noexcept override + rearm read_ready(EventLoop_t &loop, int fd) noexcept override { return receiveEvent(loop, fd, IN_EVENTS); } - rearm writeReady(EventLoop_t &loop, int fd) noexcept override + rearm write_ready(EventLoop_t &loop, int fd) noexcept override { return receiveEvent(loop, fd, OUT_EVENTS); } @@ -64,15 +64,15 @@ class ControlConnWatcher : public EventLoop_t::BidiFdWatcher public: EventLoop_t * eventLoop; - void setWatches(int flags) + void set_watches(int flags) { - EventLoop_t::BidiFdWatcher::setWatches(*eventLoop, flags); + EventLoop_t::bidi_fd_watcher::set_watches(*eventLoop, flags); } void registerWith(EventLoop_t &loop, int fd, int flags) { this->eventLoop = &loop; - BidiFdWatcher::addWatch(loop, fd, flags); + bidi_fd_watcher::add_watch(loop, fd, flags); } }; @@ -169,7 +169,7 @@ class ControlConn : private ServiceListener { bad_conn_close = true; oom_close = true; - iob.setWatches(OUT_EVENTS); + iob.set_watches(OUT_EVENTS); } // Process service event broadcast. diff --git a/src/dasynq/dasynq-childproc.h b/src/dasynq/dasynq-childproc.h index 722ebd8..62e5f63 100644 --- a/src/dasynq/dasynq-childproc.h +++ b/src/dasynq/dasynq-childproc.h @@ -1,3 +1,5 @@ +#include + namespace dasynq { // Map of pid_t to void *, with possibility of reserving entries so that mappings can @@ -161,6 +163,7 @@ template class ChildProcEvents : public Base sigemptyset(&chld_action.sa_mask); chld_action.sa_flags = 0; sigaction(SIGCHLD, &chld_action, nullptr); + Base::init(loop_mech); } }; diff --git a/src/dasynq/dasynq-config.h b/src/dasynq/dasynq-config.h new file mode 100644 index 0000000..0ef66cd --- /dev/null +++ b/src/dasynq/dasynq-config.h @@ -0,0 +1,32 @@ +#ifndef DASYNQ_CONFIG_H_INCLUDED +#define DASYNQ_CONFIG_H_INCLUDED + +#if defined(__OpenBSD__) || defined(__APPLE__) +#define DASYNQ_HAVE_KQUEUE 1 +#endif + +#if defined(__linux__) +#define DASYNQ_HAVE_EPOLL 1 +#endif + +// General feature availability + +#if defined(__OpenBSD__) || defined(__linux__) +#define HAVE_PIPE2 1 +#endif + + +// Allow optimisation of empty classes by including this in the body: +// May be included as the last entry for a class which is only +// _potentially_ empty. + +#ifdef __GNUC__ +#ifndef __clang__ +#define DASYNQ_EMPTY_BODY char empty[0]; // Make class instances take up no space (gcc) +#else +#define DASYNQ_EMPTY_BODY char empty[0] __attribute__((unused)); // Make class instances take up no space (clang) +#endif +#define DASYNQ_UNREACHABLE __builtin_unreachable() +#endif + +#endif diff --git a/src/dasynq/dasynq-epoll.h b/src/dasynq/dasynq-epoll.h index e92deb6..09775d2 100644 --- a/src/dasynq/dasynq-epoll.h +++ b/src/dasynq/dasynq-epoll.h @@ -328,13 +328,6 @@ template class EpollLoop : public Base processEvents(events, r); } - - // Interrupt any current poll operation (pullEvents/pullOneEvent), causing - // it to to return immediately. - void interruptWait() - { - // TODO - } }; } // end namespace diff --git a/src/dasynq/dasynq-flags.h b/src/dasynq/dasynq-flags.h index 4b0813b..847a6d7 100644 --- a/src/dasynq/dasynq-flags.h +++ b/src/dasynq/dasynq-flags.h @@ -1,3 +1,6 @@ +#ifndef DASYNQ_FLAGS_H_INCLUDED +#define DASYNQ_FLAGS_H_INCLUDED + namespace dasynq { // Event type bits @@ -10,4 +13,13 @@ constexpr unsigned int ONE_SHOT = 8; // Masks: constexpr unsigned int IO_EVENTS = IN_EVENTS | OUT_EVENTS; +// Different timer clock types +enum class clock_type +{ + SYSTEM, + MONOTONIC +}; + } + +#endif diff --git a/src/dasynq/dasynq-interrupt.h b/src/dasynq/dasynq-interrupt.h new file mode 100644 index 0000000..7a68fa1 --- /dev/null +++ b/src/dasynq/dasynq-interrupt.h @@ -0,0 +1,98 @@ +#ifndef DASYNQ_INTERRUPT_H_INCLUDED +#define DASYNQ_INTERRUPT_H_INCLUDED + +#include +#include + +#include "dasynq-config.h" +#include "dasynq-mutex.h" + +/* + * Mechanism for interrupting an event loop wait. + */ + +namespace dasynq { + +template class interrupt_channel; + +// In the non-multi-thread case, this doesn't need to be supported: +template class interrupt_channel : public Base +{ + public: + void interrupt_wait() + { + + } +}; + +template class interrupt_channel : public Base +{ +#ifdef HAVE_PIPE2 + int create_pipe(int filedes[2]) + { + return pipe2(filedes, O_CLOEXEC | O_NONBLOCK); + } +#else + int create_pipe(int filedes[2]) + { + int r = pipe(filedes); + if (r != -1) { + fcntl(filedes[0], F_SETFD, O_CLOEXEC); + fcntl(filedes[1], F_SETFD, O_CLOEXEC); + fcntl(filedes[0], F_SETFL, O_NONBLOCK); + fcntl(filedes[1], F_SETFL, O_NONBLOCK); + } + return r; + } +#endif + + int pipe_r_fd; + int pipe_w_fd; + + public: + + template void init(T *loop_mech) + { + int pipedes[2]; + if (create_pipe(pipedes) == -1) { + throw std::system_error(errno, std::system_category()); + } + + pipe_r_fd = pipedes[0]; + pipe_w_fd = pipedes[1]; + + try { + loop_mech->addFdWatch(pipe_r_fd, &pipe_r_fd, IN_EVENTS); + } + catch (...) { + close (pipe_r_fd); + close (pipe_w_fd); + throw; + } + + Base::init(loop_mech); + } + + template + void receiveFdEvent(T &loop_mech, typename Base::FD_r fd_r, void * userdata, int flags) + { + if (userdata == &pipe_r_fd) { + // try to clear the pipe + char buf[64]; + read(pipe_r_fd, buf, 64); + } + else { + Base::receiveFdEvent(loop_mech, fd_r, userdata, flags); + } + } + + void interrupt_wait() + { + char buf[1] = { 0 }; + write(pipe_w_fd, buf, 1); + } +}; + +} + +#endif /* DASYNQ_INTERRUPT_H_INCLUDED */ diff --git a/src/dasynq/dasynq-itimer.h b/src/dasynq/dasynq-itimer.h index c364bab..43833a1 100644 --- a/src/dasynq/dasynq-itimer.h +++ b/src/dasynq/dasynq-itimer.h @@ -1,57 +1,16 @@ #include #include -// #include - #include #include +#include "dasynq-timerbase.h" #include "dasynq-binaryheap.h" namespace dasynq { // Timer implementation based on the (basically obselete) POSIX itimer interface. -class TimerData -{ - public: - // initial time? - struct timespec 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) - { - // constructor - } -}; - -class CompareTimespec -{ - public: - bool operator()(const struct timespec &a, const struct timespec &b) - { - if (a.tv_sec < b.tv_sec) { - return true; - } - - if (a.tv_sec == b.tv_sec) { - return a.tv_nsec < b.tv_nsec; - } - - return false; - } -}; - -using timer_handle_t = BinaryHeap::handle_t; - -static void init_timer_handle(timer_handle_t &hnd) noexcept -{ - BinaryHeap::init_handle(hnd); -} - - template class ITimerEvents : public Base { private: @@ -59,6 +18,9 @@ template class ITimerEvents : public Base BinaryHeap timer_queue; +#if defined(__APPLE__) +#define itimerspec itimerval +#endif static int divide_timespec(const struct timespec &num, const struct timespec &den) { @@ -76,24 +38,43 @@ template class ITimerEvents : public Base newtime.it_interval = {0, 0}; } else { +#if defined(__APPLE__) + auto &rp = timer_queue.get_root_priority(); + newtime.it_value.tv_sec = rp.tv_sec; + newtime.it_value.tv_usec = rp.tv_nsec / 1000; +#else newtime.it_value = timer_queue.get_root_priority(); newtime.it_interval = {0, 0}; +#endif } - // timerfd_settime(timerfd_fd, TFD_TIMER_ABSTIME, &newtime, nullptr); - // TODO struct timespec curtime; +#if defined(__APPLE__) + struct timeval curtime_tv; + gettimeofday(&curtime_tv, nullptr); + curtime.tv_sec = curtime_tv.tv_sec; + curtime.tv_nsec = curtime_tv.tv_usec * 1000; +#else clock_gettime(CLOCK_MONOTONIC, &curtime); +#endif struct itimerval newalarm; newalarm.it_interval = {0, 0}; newalarm.it_value.tv_sec = newtime.it_value.tv_sec - curtime.tv_sec; +#if defined(__APPLE__) + newalarm.it_value.tv_usec = newtime.it_value.tv_usec - curtime.tv_nsec / 1000; +#else newalarm.it_value.tv_usec = (newtime.it_value.tv_nsec - curtime.tv_nsec) / 1000; +#endif if (newalarm.it_value.tv_usec < 0) { newalarm.it_value.tv_usec += 1000000; newalarm.it_value.tv_sec--; } setitimer(ITIMER_REAL, &newalarm, nullptr); } + +#if defined(__APPLE__) +#undef itimerspec +#endif protected: @@ -104,8 +85,15 @@ template class ITimerEvents : public Base { if (siginfo.get_signo() == SIGALRM) { struct timespec curtime; +#if defined(__APPLE__) + struct timeval curtime_tv; + gettimeofday(&curtime_tv, nullptr); + curtime.tv_sec = curtime_tv.tv_sec; + curtime.tv_nsec = curtime_tv.tv_usec * 1000; +#else clock_gettime(CLOCK_MONOTONIC, &curtime); // should we use the REALTIME clock instead? I have no idea :/ +#endif // Peek timer queue; calculate difference between current time and timeout struct timespec * timeout = &timer_queue.get_root_priority(); @@ -170,13 +158,6 @@ template class ITimerEvents : public Base template void init(T *loop_mech) { - /* - timerfd_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); - if (timerfd_fd == -1) { - throw std::system_error(errno, std::system_category()); - } - loop_mech->addFdWatch(timerfd_fd, &timerfd_fd, IN_EVENTS); - */ sigset_t sigmask; sigprocmask(SIG_UNBLOCK, nullptr, &sigmask); sigaddset(&sigmask, SIGALRM); @@ -185,18 +166,17 @@ template class ITimerEvents : public Base Base::init(loop_mech); } - // Add timer, return handle (TODO: clock id param?) - void addTimer(timer_handle_t &h, void *userdata) + void addTimer(timer_handle_t &h, void *userdata, clock_type clock = clock_type::MONOTONIC) { timer_queue.allocate(h, userdata); } - void removeTimer(timer_handle_t &timer_id) noexcept + void removeTimer(timer_handle_t &timer_id, clock_type clock = clock_type::MONOTONIC) noexcept { - removeTimer_nolock(timer_id); + removeTimer_nolock(timer_id, clock); } - void removeTimer_nolock(timer_handle_t &timer_id) noexcept + void removeTimer_nolock(timer_handle_t &timer_id, clock_type clock = clock_type::MONOTONIC) noexcept { if (timer_queue.is_queued(timer_id)) { timer_queue.remove(timer_id); @@ -206,7 +186,8 @@ template class ITimerEvents : public 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, bool enable) noexcept + void setTimer(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval, + bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { auto &ts = timer_queue.node_data(timer_id); ts.interval_time = interval; @@ -230,11 +211,19 @@ template class ITimerEvents : public Base } // Set timer relative to current time: - void setTimerRel(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval, bool enable) noexcept + void setTimerRel(timer_handle_t &timer_id, struct timespec &timeout, struct timespec &interval, + bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { // TODO consider caching current time somehow; need to decide then when to update cached value. struct timespec curtime; +#if defined(__APPLE__) + struct timeval curtime_tv; + gettimeofday(&curtime_tv, nullptr); + curtime.tv_sec = curtime_tv.tv_sec; + curtime.tv_nsec = curtime_tv.tv_usec * 1000; +#else clock_gettime(CLOCK_MONOTONIC, &curtime); +#endif curtime.tv_sec += timeout.tv_sec; curtime.tv_nsec += timeout.tv_nsec; if (curtime.tv_nsec > 1000000000) { @@ -245,12 +234,12 @@ template class ITimerEvents : public Base } // Enables or disabling report of timeouts (does not stop timer) - void enableTimer(timer_handle_t &timer_id, bool enable) noexcept + void enableTimer(timer_handle_t &timer_id, bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { - enableTimer_nolock(timer_id, enable); + enableTimer_nolock(timer_id, enable, clock); } - void enableTimer_nolock(timer_handle_t &timer_id, bool enable) noexcept + void enableTimer_nolock(timer_handle_t &timer_id, bool enable, clock_type = clock_type::MONOTONIC) noexcept { timer_queue.node_data(timer_id).enabled = enable; } diff --git a/src/dasynq/dasynq-kqueue.h b/src/dasynq/dasynq-kqueue.h index 4682f19..e2646a2 100644 --- a/src/dasynq/dasynq-kqueue.h +++ b/src/dasynq/dasynq-kqueue.h @@ -20,6 +20,8 @@ extern "C" { #include #include +#include "dasynq-config.h" + namespace dasynq { template class KqueueLoop; @@ -39,7 +41,7 @@ class KqueueTraits public: int get_signo() { return info.si_signo; } int get_sicode() { return info.si_code; } - char * get_ssiaddr() { return info.si_addr; } + void * get_ssiaddr() { return info.si_addr; } void set_signo(int signo) { info.si_signo = signo; } }; @@ -49,9 +51,7 @@ class KqueueTraits // File descriptor optional storage. If the mechanism can return the file descriptor, this // class will be empty, otherwise it can hold a file descriptor. class FD_s { - // Epoll doesn't return the file descriptor (it can, but it can't return both file - // descriptor and user data). - // TODO make true empty. + DASYNQ_EMPTY_BODY }; // File descriptor reference (passed to event callback). If the mechanism can return the @@ -79,7 +79,8 @@ class KqueueTraits // essentially an incomplete version of the same thing. Discussion with OpenBSD developer // Ted Unangst suggested that the siginfo_t structure returned might not always have all // fields set correctly. Furthermore there is a bug such that specifying a zero timeout (or -// indeed any timeout less than a tick) results in NO timeout. +// indeed any timeout less than a tick) results in NO timeout. We get around this by instead +// specifying an *invalid* timeout, which won't error out if a signal is pending. static inline int sigtimedwait(const sigset_t *ssp, siginfo_t *info, struct timespec *timeout) { // We know that we're only called with a timeout of 0 (which doesn't work properly) and @@ -88,6 +89,57 @@ static inline int sigtimedwait(const sigset_t *ssp, siginfo_t *info, struct time timeout->tv_nsec = 1000000001; return __thrsigdivert(*ssp, info, timeout); } + +static inline void prepare_signal(int signo) { } +static inline void unprep_signal(int signo) { } + +static bool get_siginfo(int signo, siginfo_t *siginfo) +{ + struct timespec timeout; + timeout.tv_sec = 0; + timeout.tv_nsec = 0; + + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, signo); + return (sigtimedwait(&mask, siginfo, &timeout) != -1); +} + +#elif defined(__APPLE__) + +static siginfo_t * siginfo_p; + +static void signalHandler(int signo, siginfo_t *siginfo, void *v) +{ + *siginfo_p = *siginfo; +} + +static inline void prepare_signal(int signo) +{ + struct sigaction the_action; + the_action.sa_sigaction = signalHandler; + the_action.sa_flags = SA_SIGINFO; + sigfillset(&the_action.sa_mask); + + sigaction(signo, &the_action, nullptr); +} + +static inline void unprep_signal(int signo) +{ + signal(signo, SIG_DFL); +} + +static inline bool get_siginfo(int signo, siginfo_t *siginfo) +{ + siginfo_p = siginfo; + + sigset_t mask; + sigfillset(&mask); + sigdelset(&mask, signo); + sigsuspend(&mask); + return true; +} + #endif template class KqueueLoop : public Base @@ -125,20 +177,13 @@ template class KqueueLoop : public Base for (int i = 0; i < r; i++) { if (events[i].filter == EVFILT_SIGNAL) { SigInfo siginfo; - sigset_t sset; - sigemptyset(&sset); - sigaddset(&sset, events[i].ident); - struct timespec timeout; - timeout.tv_sec = 0; - timeout.tv_nsec = 0; - if (sigtimedwait(&sset, &siginfo.info, &timeout) > 0) { - if (Base::receiveSignal(*this, siginfo, (void *)events[i].udata)) { - sigdelset(&sigmask, events[i].ident); - events[i].flags = EV_DISABLE; - } - else { - events[i].flags = EV_ENABLE; - } + if (get_siginfo(events[i].ident, &siginfo.info) + && Base::receiveSignal(*this, siginfo, (void *)events[i].udata)) { + sigdelset(&sigmask, events[i].ident); + events[i].flags = EV_DISABLE; + } + else { + events[i].flags = EV_ENABLE; } } else if (events[i].filter == EVFILT_READ || events[i].filter == EVFILT_WRITE) { @@ -271,6 +316,8 @@ template class KqueueLoop : public Base sigdataMap[signo] = userdata; sigaddset(&sigmask, signo); + prepare_signal(signo); + struct kevent evt; EV_SET(&evt, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, userdata); // TODO use EV_DISPATCH if available (not on OpenBSD) @@ -294,6 +341,7 @@ template class KqueueLoop : public Base void removeSignalWatch_nolock(int signo) noexcept { + unprep_signal(signo); sigdelset(&sigmask, signo); struct kevent evt; @@ -330,25 +378,28 @@ template class KqueueLoop : public Base // signals that have been registered - in many cases that will allow // us to skip the sigtimedwait call altogether. + // The check is not necessary on systems that don't queue signals. + +#if _POSIX_REALTIME_SIGNALS > 0 { std::lock_guard guard(Base::lock); + struct timespec timeout; timeout.tv_sec = 0; timeout.tv_nsec = 0; SigInfo siginfo; int rsigno = sigtimedwait(&sigmask, &siginfo.info, &timeout); while (rsigno > 0) { - // TODO avoid this hack for SIGCHLD somehow - if (rsigno != SIGCHLD) { + if (Base::receiveSignal(*this, siginfo, sigdataMap[rsigno])) { sigdelset(&sigmask, rsigno); // TODO accumulate and disable multiple filters with a single kevents call // rather than disabling each individually setFilterEnabled(EVFILT_SIGNAL, rsigno, false); } - Base::receiveSignal(*this, siginfo, sigdataMap[rsigno]); rsigno = sigtimedwait(&sigmask, &siginfo.info, &timeout); } } +#endif struct kevent events[16]; struct timespec ts; @@ -384,13 +435,6 @@ template class KqueueLoop : public Base processEvents(events, r); } - - // Interrupt any current poll operation (pullEvents/pullOneEvent), causing - // it to to return immediately. - void interruptWait() - { - // TODO - } }; } // end namespace diff --git a/src/dasynq/dasynq-svec.h b/src/dasynq/dasynq-svec.h index eb4259e..cddec09 100644 --- a/src/dasynq/dasynq-svec.h +++ b/src/dasynq/dasynq-svec.h @@ -1,8 +1,9 @@ #ifndef DASYNQ_SVEC_H_INCLUDED -#define DASYNC_SVEC_H_INCLUDED +#define DASYNQ_SVEC_H_INCLUDED #include #include +#include #include // Vector with possibility to shrink capacity arbitrarily diff --git a/src/dasynq/dasynq-timerbase.h b/src/dasynq/dasynq-timerbase.h new file mode 100644 index 0000000..7e7720a --- /dev/null +++ b/src/dasynq/dasynq-timerbase.h @@ -0,0 +1,46 @@ +#ifndef DASYNQ_TIMERBASE_H_INCLUDED +#define DASYNQ_TIMERBASE_H_INCLUDED + +namespace dasynq { + +class TimerData +{ + public: + struct timespec 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) + { + // constructor + } +}; + +class CompareTimespec +{ + public: + bool operator()(const struct timespec &a, const struct timespec &b) + { + if (a.tv_sec < b.tv_sec) { + return true; + } + + if (a.tv_sec == b.tv_sec) { + return a.tv_nsec < b.tv_nsec; + } + + return false; + } +}; + +using timer_handle_t = BinaryHeap::handle_t; + +static void init_timer_handle(timer_handle_t &hnd) noexcept +{ + BinaryHeap::init_handle(hnd); +} + +} + +#endif /* DASYNQ_TIMERBASE_H_INCLUDED */ diff --git a/src/dasynq/dasynq-timerfd.h b/src/dasynq/dasynq-timerfd.h index db597b8..f31cdc3 100644 --- a/src/dasynq/dasynq-timerfd.h +++ b/src/dasynq/dasynq-timerfd.h @@ -4,6 +4,7 @@ #include #include +#include "dasynq-timerbase.h" #include "dasynq-binaryheap.h" namespace dasynq { @@ -17,56 +18,17 @@ namespace dasynq { // we are given a handle; we need to use this to modify the watch. We delegate the // process of allocating a handle to a priority heap implementation (BinaryHeap). - -class TimerData -{ - public: - // initial time? - struct timespec 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) - { - // constructor - } -}; - -class CompareTimespec -{ - public: - bool operator()(const struct timespec &a, const struct timespec &b) - { - if (a.tv_sec < b.tv_sec) { - return true; - } - - if (a.tv_sec == b.tv_sec) { - return a.tv_nsec < b.tv_nsec; - } - - return false; - } -}; - -using timer_handle_t = BinaryHeap::handle_t; - -static void init_timer_handle(timer_handle_t &hnd) noexcept -{ - BinaryHeap::init_handle(hnd); -} - - template class TimerFdEvents : public Base { private: int timerfd_fd = -1; + int systemtime_fd = -1; - BinaryHeap timer_queue; - + using timer_queue_t = BinaryHeap; + timer_queue_t timer_queue; + timer_queue_t wallclock_queue; - static int divide_timespec(const struct timespec &num, const struct timespec &den) + static int divide_timespec(const struct timespec &num, const struct timespec &den) noexcept { // TODO return 0; @@ -74,79 +36,119 @@ template class TimerFdEvents : public Base // Set the timerfd timeout to match the first timer in the queue (disable the timerfd // if there are no active timers). - void set_timer_from_queue() + static void set_timer_from_queue(int fd, timer_queue_t &queue) noexcept { struct itimerspec newtime; - if (timer_queue.empty()) { + if (queue.empty()) { newtime.it_value = {0, 0}; newtime.it_interval = {0, 0}; } else { - newtime.it_value = timer_queue.get_root_priority(); + newtime.it_value = queue.get_root_priority(); newtime.it_interval = {0, 0}; } - timerfd_settime(timerfd_fd, TFD_TIMER_ABSTIME, &newtime, nullptr); + timerfd_settime(fd, TFD_TIMER_ABSTIME, &newtime, nullptr); } + void process_timer(clock_type clock, int fd, timer_queue_t &queue) noexcept + { + struct timespec curtime; + switch (clock) { + case clock_type::SYSTEM: + clock_gettime(CLOCK_REALTIME, &curtime); + break; + case clock_type::MONOTONIC: + clock_gettime(CLOCK_MONOTONIC, &curtime); + break; + default: + DASYNQ_UNREACHABLE; + } + + // Peek timer queue; calculate difference between current time and timeout + struct timespec * timeout = &queue.get_root_priority(); + while (timeout->tv_sec < curtime.tv_sec || (timeout->tv_sec == curtime.tv_sec && + timeout->tv_nsec <= curtime.tv_nsec)) { + // Increment expiry count + queue.node_data(queue.get_root()).expiry_count++; + // (a periodic timer may have overrun; calculated below). + + auto thandle = queue.get_root(); + TimerData &data = queue.node_data(thandle); + timespec &interval = data.interval_time; + if (interval.tv_sec == 0 && interval.tv_nsec == 0) { + // Non periodic timer + queue.pull_root(); + if (data.enabled) { + int expiry_count = data.expiry_count; + data.expiry_count = 0; + Base::receiveTimerExpiry(thandle, data.userdata, expiry_count); + } + if (queue.empty()) { + break; + } + } + else { + // Periodic timer TODO + // First calculate the overrun in time: + /* + struct timespec diff; + diff.tv_sec = curtime.tv_sec - timeout->tv_sec; + diff.tv_nsec = curtime.tv_nsec - timeout->tv_nsec; + if (diff.tv_nsec < 0) { + diff.tv_nsec += 1000000000; + diff.tv_sec--; + } + */ + // 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... + // TODO use divide_timespec + // TODO better not to remove from queue maybe, but instead mark as inactive, + // adjust timeout, and bubble into correct position + // call Base::receieveTimerEvent + // TODO + } + + // repeat until all expired timeouts processed + // timeout = &timer_queue[0].timeout; + // (shouldn't be necessary; address hasn't changed...) + } + // arm timerfd with timeout from head of queue + set_timer_from_queue(fd, queue); + } + + void setTimer(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval, + timer_queue_t &queue, int fd, bool enable) noexcept + { + auto &ts = queue.node_data(timer_id); + ts.interval_time = interval; + ts.expiry_count = 0; + ts.enabled = enable; + + if (queue.is_queued(timer_id)) { + // Already queued; alter timeout + if (queue.set_priority(timer_id, timeout)) { + set_timer_from_queue(fd, queue); + } + } + else { + if (queue.insert(timer_id, timeout)) { + set_timer_from_queue(fd, queue); + } + } + + // TODO locking (here and everywhere) + } + public: template void receiveFdEvent(T &loop_mech, typename Base::FD_r fd_r, void * userdata, int flags) { if (userdata == &timerfd_fd) { - struct timespec curtime; - clock_gettime(CLOCK_MONOTONIC, &curtime); // in theory, can't fail on Linux - - // Peek timer queue; calculate difference between current time and timeout - struct timespec * timeout = &timer_queue.get_root_priority(); - while (timeout->tv_sec < curtime.tv_sec || (timeout->tv_sec == curtime.tv_sec && - timeout->tv_nsec <= curtime.tv_nsec)) { - // Increment expiry count - timer_queue.node_data(timer_queue.get_root()).expiry_count++; - // (a periodic timer may have overrun; calculated below). - - auto thandle = timer_queue.get_root(); - TimerData &data = timer_queue.node_data(thandle); - timespec &interval = data.interval_time; - if (interval.tv_sec == 0 && interval.tv_nsec == 0) { - // Non periodic timer - timer_queue.pull_root(); - if (data.enabled) { - int expiry_count = data.expiry_count; - data.expiry_count = 0; - Base::receiveTimerExpiry(thandle, data.userdata, expiry_count); - } - if (timer_queue.empty()) { - break; - } - } - else { - // Periodic timer TODO - // First calculate the overrun in time: - /* - struct timespec diff; - diff.tv_sec = curtime.tv_sec - timeout->tv_sec; - diff.tv_nsec = curtime.tv_nsec - timeout->tv_nsec; - if (diff.tv_nsec < 0) { - diff.tv_nsec += 1000000000; - diff.tv_sec--; - } - */ - // 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... - // TODO use divide_timespec - // TODO better not to remove from queue maybe, but instead mark as inactive, - // adjust timeout, and bubble into correct position - // call Base::receieveTimerEvent - // TODO - } - - // repeat until all expired timeouts processed - // timeout = &timer_queue[0].timeout; - // (shouldn't be necessary; address hasn't changed...) - } - // arm timerfd with timeout from head of queue - set_timer_from_queue(); + process_timer(clock_type::MONOTONIC, timerfd_fd, timer_queue); + } + else if (userdata == &systemtime_fd) { + process_timer(clock_type::SYSTEM, systemtime_fd, wallclock_queue); } else { Base::receiveFdEvent(loop_mech, fd_r, userdata, flags); @@ -159,77 +161,134 @@ template class TimerFdEvents : public Base if (timerfd_fd == -1) { throw std::system_error(errno, std::system_category()); } - loop_mech->addFdWatch(timerfd_fd, &timerfd_fd, IN_EVENTS); - Base::init(loop_mech); + systemtime_fd = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC | TFD_NONBLOCK); + if (systemtime_fd == -1) { + close (timerfd_fd); + throw std::system_error(errno, std::system_category()); + } + + try { + loop_mech->addFdWatch(timerfd_fd, &timerfd_fd, IN_EVENTS); + loop_mech->addFdWatch(systemtime_fd, &systemtime_fd, IN_EVENTS); + Base::init(loop_mech); + } + catch (...) { + close(timerfd_fd); + close(systemtime_fd); + throw; + } } - // Add timer, return handle (TODO: clock id param?) - void addTimer(timer_handle_t &h, void *userdata) + // Add timer, store into given handle + void addTimer(timer_handle_t &h, void *userdata, clock_type clock = clock_type::MONOTONIC) { - timer_queue.allocate(h, userdata); + switch(clock) { + case clock_type::SYSTEM: + wallclock_queue.allocate(h, userdata); + break; + case clock_type::MONOTONIC: + timer_queue.allocate(h, userdata); + break; + default: + DASYNQ_UNREACHABLE; + } } - void removeTimer(timer_handle_t &timer_id) noexcept + void removeTimer(timer_handle_t &timer_id, clock_type clock = clock_type::MONOTONIC) noexcept { - removeTimer_nolock(timer_id); + removeTimer_nolock(timer_id, clock); } - void removeTimer_nolock(timer_handle_t &timer_id) noexcept + void removeTimer_nolock(timer_handle_t &timer_id, clock_type clock = clock_type::MONOTONIC) noexcept { - if (timer_queue.is_queued(timer_id)) { - timer_queue.remove(timer_id); + switch(clock) { + case clock_type::SYSTEM: + if (wallclock_queue.is_queued(timer_id)) { + wallclock_queue.remove(timer_id); + } + wallclock_queue.deallocate(timer_id); + break; + case clock_type::MONOTONIC: + if (timer_queue.is_queued(timer_id)) { + timer_queue.remove(timer_id); + } + timer_queue.deallocate(timer_id); + break; + default: + DASYNQ_UNREACHABLE; } - timer_queue.deallocate(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, bool enable) noexcept + void setTimer(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval, + bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { - auto &ts = timer_queue.node_data(timer_id); - ts.interval_time = interval; - ts.expiry_count = 0; - ts.enabled = enable; - - if (timer_queue.is_queued(timer_id)) { - // Already queued; alter timeout - if (timer_queue.set_priority(timer_id, timeout)) { - set_timer_from_queue(); - } - } - else { - if (timer_queue.insert(timer_id, timeout)) { - set_timer_from_queue(); - } + switch (clock) { + case clock_type::SYSTEM: + setTimer(timer_id, timeout, interval, wallclock_queue, systemtime_fd, enable); + break; + case clock_type::MONOTONIC: + setTimer(timer_id, timeout, interval, timer_queue, timerfd_fd, enable); + break; + default: + DASYNQ_UNREACHABLE; } - - // TODO locking (here and everywhere) } // Set timer relative to current time: - void setTimerRel(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval, bool enable) noexcept + void setTimerRel(timer_handle_t & timer_id, struct timespec &timeout, struct timespec &interval, + bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { + clockid_t sclock; + switch (clock) { + case clock_type::SYSTEM: + sclock = CLOCK_REALTIME; + break; + case clock_type::MONOTONIC: + sclock = CLOCK_MONOTONIC; + break; + default: + DASYNQ_UNREACHABLE; + } + // TODO consider caching current time somehow; need to decide then when to update cached value. struct timespec curtime; - clock_gettime(CLOCK_MONOTONIC, &curtime); + clock_gettime(sclock, &curtime); curtime.tv_sec += timeout.tv_sec; curtime.tv_nsec += timeout.tv_nsec; if (curtime.tv_nsec > 1000000000) { curtime.tv_nsec -= 1000000000; curtime.tv_sec++; } - setTimer(timer_id, curtime, interval, enable); + + setTimer(timer_id, curtime, interval, enable, clock); } // Enables or disabling report of timeouts (does not stop timer) - void enableTimer(timer_handle_t & timer_id, bool enable) noexcept + void enableTimer(timer_handle_t & timer_id, bool enable, clock_type clock = clock_type::MONOTONIC) noexcept { - enableTimer_nolock(timer_id, enable); + enableTimer_nolock(timer_id, enable, clock); } - void enableTimer_nolock(timer_handle_t & timer_id, bool enable) noexcept + void enableTimer_nolock(timer_handle_t & timer_id, bool enable, clock_type clock = clock_type::MONOTONIC) noexcept + { + switch (clock) { + case clock_type::SYSTEM: + wallclock_queue.node_data(timer_id).enabled = enable; + break; + case clock_type::MONOTONIC: + timer_queue.node_data(timer_id).enabled = enable; + break; + default: + DASYNQ_UNREACHABLE; + } + } + + ~TimerFdEvents() { - timer_queue.node_data(timer_id).enabled = enable; + close(timerfd_fd); + close(systemtime_fd); } }; diff --git a/src/dasynq/dasynq.h b/src/dasynq/dasynq.h index 560a44e..0232876 100644 --- a/src/dasynq/dasynq.h +++ b/src/dasynq/dasynq.h @@ -1,16 +1,11 @@ #ifndef DASYNQ_H_INCLUDED #define DASYNQ_H_INCLUDED -#if defined(__OpenBSD__) -#define DASYNQ_HAVE_KQUEUE 1 -#endif - -#if defined(__linux__) -#define DASYNQ_HAVE_EPOLL 1 -#endif +#include "dasynq-config.h" #include "dasynq-flags.h" #include "dasynq-binaryheap.h" +#include "dasynq-interrupt.h" #if defined(DASYNQ_CUSTOM_LOOP_IMPLEMENTATION) // Loop and LoopTraits defined already; used for testing @@ -19,7 +14,7 @@ #include "dasynq-itimer.h" #include "dasynq-childproc.h" namespace dasynq { - template using Loop = KqueueLoop>>; + template using Loop = KqueueLoop>>>; using LoopTraits = KqueueTraits; } #elif defined(DASYNQ_HAVE_EPOLL) @@ -27,7 +22,7 @@ namespace dasynq { #include "dasynq-timerfd.h" #include "dasynq-childproc.h" namespace dasynq { - template using Loop = EpollLoop>>; + template using Loop = EpollLoop>>>; using LoopTraits = EpollTraits; } #endif @@ -41,24 +36,30 @@ namespace dasynq { #include #include +#include "dasynq-mutex.h" -// TODO consider using atomic variables instead of explicit locking where appropriate +namespace dasynq { -// Allow optimisation of empty classes by including this in the body: -// May be included as the last entry for a class which is only -// _potentially_ empty. +#ifdef __APPLE__ +int pipe2(int filedes[2], int flags) +{ + if (pipe(filedes) == -1) { + return -1; + } -#ifdef __GNUC__ -#ifndef __clang__ -#define DASYNQ_EMPTY_BODY char empty[0]; // Make class instances take up no space (gcc) -#else -#define DASYNQ_EMPTY_BODY char empty[0] __attribute__((unused)); // Make class instances take up no space (clang) -#endif -#endif + if (flags & O_CLOEXEC) { + fcntl(filedes[0], F_SETFD, FD_CLOEXEC); + fcntl(filedes[1], F_SETFD, FD_CLOEXEC); + } -#include "dasynq-mutex.h" + if (flags & O_NONBLOCK) { + fcntl(filedes[0], F_SETFL, O_NONBLOCK); + fcntl(filedes[1], F_SETFL, O_NONBLOCK); + } -namespace dasynq { + return 0; +} +#endif namespace dprivate { class BaseWatcher; @@ -88,29 +89,18 @@ enum class rearm // TODO: add a REQUEUE option, which means, "I didn't complete input/output, run me again soon" }; -// Different timer clock types -enum class ClockType -{ - WALLTIME, - MONOTONIC -}; - -// Information about a received signal. -// This is essentially a wrapper for the POSIX siginfo_t; its existence allows for mechanisms that receive -// equivalent signal information in a different format (eg signalfd on Linux). -using SigInfo = LoopTraits::SigInfo; - // Forward declarations: -template class event_loop; +template class Loop = dasynq::Loop, typename LoopTraits = dasynq::LoopTraits> +class event_loop; namespace dprivate { // (non-public API) - template class FdWatcher; - template class BidiFdWatcher; - template class SignalWatcher; - template class ChildProcWatcher; - template class Timer; + template class fd_watcher; + template class bidi_fd_watcher; + template class signal_watcher; + template class child_proc_watcher; + template class timer; enum class WatchType { @@ -132,7 +122,7 @@ namespace dprivate { class BaseWatcher { template friend class EventDispatch; - template friend class dasynq::event_loop; + template class, typename> friend class dasynq::event_loop; protected: WatchType watchType; @@ -166,7 +156,7 @@ namespace dprivate { // It is guaranteed by the caller that: // - the dispatch method is not currently running // - the dispatch method will not be called. - virtual void watchRemoved() noexcept + virtual void watch_removed() noexcept { // TODO this "delete" behaviour could be dependent on a flag, perhaps? // delete this; @@ -174,27 +164,26 @@ namespace dprivate { }; // Base signal event - not part of public API - template + template class BaseSignalWatcher : public BaseWatcher { - template friend class EventDispatch; - friend class dasynq::event_loop; + friend class EventDispatch; + template class, typename> friend class dasynq::event_loop; protected: - SigInfo siginfo; + typename Traits::SigInfo siginfo; BaseSignalWatcher() : BaseWatcher(WatchType::SIGNAL) { } public: + using SigInfo = typename Traits::SigInfo; typedef SigInfo &SigInfo_p; - - virtual rearm received(event_loop &eloop, int signo, SigInfo_p siginfo) = 0; }; template class BaseFdWatcher : public BaseWatcher { template friend class EventDispatch; - friend class dasynq::event_loop; + template class, typename> friend class dasynq::event_loop; protected: int watch_fd; @@ -203,24 +192,20 @@ namespace dprivate { int watch_flags; // events being watched int event_flags; // events pending (queued) + // watch_flags: for a regular fd_watcher, this specifies the events that the watcher + // is watching (or was watching if disabled). For a bidi_fd_watcher, specifies + // the events that the watcher is currently watching (i.e. specifies which + // halves of the Bidi watcher are enabled). + BaseFdWatcher() noexcept : BaseWatcher(WatchType::FD) { } - - public: - virtual rearm fdEvent(event_loop &eloop, int fd, int flags) = 0; }; template class BaseBidiFdWatcher : public BaseFdWatcher { template friend class EventDispatch; - friend class dasynq::event_loop; - - // This should never actually get called: - rearm fdEvent(event_loop &eloop, int fd, int flags) final - { - return rearm::REARM; // should not be reachable. - }; - + template class, typename> friend class dasynq::event_loop; + protected: // The main instance is the "input" watcher only; we keep a secondary watcher @@ -229,26 +214,19 @@ namespace dprivate { int read_removed : 1; // read watch removed? int write_removed : 1; // write watch removed? - - public: - virtual rearm readReady(event_loop &eloop, int fd) noexcept = 0; - virtual rearm writeReady(event_loop &eloop, int fd) noexcept = 0; }; template class BaseChildWatcher : public BaseWatcher { template friend class EventDispatch; - friend class dasynq::event_loop; + template class, typename> friend class dasynq::event_loop; protected: pid_t watch_pid; int child_status; BaseChildWatcher() : BaseWatcher(WatchType::CHILD) { } - - public: - virtual rearm childStatus(event_loop &eloop, pid_t child, int status) = 0; }; @@ -256,7 +234,7 @@ namespace dprivate { class BaseTimerWatcher : public BaseWatcher { template friend class EventDispatch; - friend class dasynq::event_loop; + template class, typename> friend class dasynq::event_loop; protected: timer_handle_t timer_handle; @@ -266,12 +244,6 @@ namespace dprivate { { init_timer_handle(timer_handle); } - - public: - // Timer expired, and the given number of intervals have elapsed before - // expiry evenet was queued. Normally intervals == 1 to indicate no - // overrun. - virtual rearm timerExpiry(event_loop &eloop, int intervals) = 0; }; // Classes for implementing a fair(ish) wait queue. @@ -365,6 +337,9 @@ namespace dprivate { waitqueue_node * unqueue() { head = head->next; + if (head == nullptr) { + tail = nullptr; + } return head; } @@ -391,6 +366,7 @@ namespace dprivate { else { head = node; } + tail = node; } }; @@ -400,12 +376,12 @@ namespace dprivate { // into the queue when eventes are received (receiveXXX methods). template class EventDispatch : public Traits { - friend class event_loop; + template class, typename> friend class dasynq::event_loop; // queue data structure/pointer PrioQueue event_queue; - using BaseSignalWatcher = dasynq::dprivate::BaseSignalWatcher; + using BaseSignalWatcher = dasynq::dprivate::BaseSignalWatcher; using BaseFdWatcher = dasynq::dprivate::BaseFdWatcher; using BaseBidiFdWatcher = dasynq::dprivate::BaseBidiFdWatcher; using BaseChildWatcher = dasynq::dprivate::BaseChildWatcher; @@ -443,6 +419,8 @@ namespace dprivate { protected: T_Mutex lock; + + template void init(T *loop) { } // Receive a signal; return true to disable signal watch or false to leave enabled template @@ -466,6 +444,7 @@ namespace dprivate { bool is_multi_watch = bfdw->watch_flags & multi_watch; if (is_multi_watch) { BaseBidiFdWatcher *bbdw = static_cast(bwatcher); + bbdw->watch_flags &= ~flags; if (flags & IN_EVENTS && flags & OUT_EVENTS) { // Queue the secondary watcher first: queueWatcher(&bbdw->outWatcher); @@ -483,10 +462,10 @@ namespace dprivate { // as the event was delivered. However, the other direction should not be disabled // yet, so we need to re-enable: int in_out_mask = IN_EVENTS | OUT_EVENTS; - if (is_multi_watch && bfdw->event_flags != (bfdw->watch_flags & in_out_mask)) { + if (is_multi_watch && (bfdw->watch_flags & in_out_mask) != 0) { // We need to re-enable the other channel now: loop_mech.enableFdWatch_nolock(bfdw->watch_fd, userdata, - (bfdw->watch_flags & ~(bfdw->event_flags)) | ONE_SHOT); + (bfdw->watch_flags & in_out_mask) | ONE_SHOT); } } } @@ -539,7 +518,7 @@ namespace dprivate { release_watcher(watcher); lock.unlock(); - watcher->watchRemoved(); + watcher->watch_removed(); } } @@ -570,33 +549,38 @@ namespace dprivate { if (watcher->read_removed && watcher->write_removed) { lock.unlock(); - watcher->watchRemoved(); + watcher->watch_removed(); } else { lock.unlock(); } } + + public: + using mutex_t = T_Mutex; }; } -template class event_loop +template class Loop, typename LoopTraits> +class event_loop { - friend class dprivate::FdWatcher>; - friend class dprivate::BidiFdWatcher>; - friend class dprivate::SignalWatcher>; - friend class dprivate::ChildProcWatcher>; - friend class dprivate::Timer>; + using my_event_loop_t = event_loop; + friend class dprivate::fd_watcher; + friend class dprivate::bidi_fd_watcher; + friend class dprivate::signal_watcher; + friend class dprivate::child_proc_watcher; + friend class dprivate::timer; public: - using LoopTraits = dasynq::LoopTraits; + using loop_traits_t = LoopTraits; private: template using EventDispatch = dprivate::EventDispatch; template using waitqueue = dprivate::waitqueue; template using waitqueue_node = dprivate::waitqueue_node; using BaseWatcher = dprivate::BaseWatcher; - using BaseSignalWatcher = dprivate::BaseSignalWatcher; + using BaseSignalWatcher = dprivate::BaseSignalWatcher; using BaseFdWatcher = dprivate::BaseFdWatcher; using BaseBidiFdWatcher = dprivate::BaseBidiFdWatcher; using BaseChildWatcher = dprivate::BaseChildWatcher; @@ -823,42 +807,42 @@ template class event_loop releaseLock(qnode); } - void registerTimer(BaseTimerWatcher *callback) + void registerTimer(BaseTimerWatcher *callback, clock_type clock) { loop_mech.prepare_watcher(callback); try { - loop_mech.addTimer(callback->timer_handle, callback); + loop_mech.addTimer(callback->timer_handle, callback, clock); } catch (...) { loop_mech.release_watcher(callback); } } - void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout) + void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout, clock_type clock) { struct timespec interval {0, 0}; - loop_mech.setTimer(callBack->timer_handle, timeout, interval, true); + loop_mech.setTimer(callBack->timer_handle, timeout, interval, true, clock); } - void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval) + void setTimer(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval, clock_type clock) { - loop_mech.setTimer(callBack->timer_handle, timeout, interval, true); + loop_mech.setTimer(callBack->timer_handle, timeout, interval, true, clock); } - void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout) + void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout, clock_type clock) { struct timespec interval {0, 0}; - loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true); + loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true, clock); } - void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval) + void setTimerRel(BaseTimerWatcher *callBack, struct timespec &timeout, struct timespec &interval, clock_type clock) { - loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true); + loop_mech.setTimerRel(callBack->timer_handle, timeout, interval, true, clock); } - void deregister(BaseTimerWatcher *callback) + void deregister(BaseTimerWatcher *callback, clock_type clock) { - loop_mech.removeTimer(callback->timer_handle); + loop_mech.removeTimer(callback->timer_handle, clock); waitqueue_node qnode; getAttnLock(qnode); @@ -881,7 +865,7 @@ template class event_loop std::unique_lock ulock(wait_lock); attn_waitqueue.queue(&qnode); if (! attn_waitqueue.checkHead(qnode)) { - loop_mech.interruptWait(); + loop_mech.interrupt_wait(); while (! attn_waitqueue.checkHead(qnode)) { qnode.wait(ulock); } @@ -915,8 +899,9 @@ template class event_loop nhead->signal(); } else { - nhead = wait_waitqueue.getHead(); - if (nhead != nullptr) { + if (! wait_waitqueue.isEmpty()) { + auto nhead = wait_waitqueue.getHead(); + wait_waitqueue.unqueue(); attn_waitqueue.queue(nhead); nhead->signal(); } @@ -934,6 +919,7 @@ template class event_loop } } + // Process rearm return for fd_watcher, including the primary watcher of a bidi_fd_watcher rearm processFdRearm(BaseFdWatcher * bfw, rearm rearmType, bool is_multi_watch) { // Called with lock held; @@ -944,10 +930,18 @@ template class event_loop if (rearmType == rearm::REMOVE) { bdfw->read_removed = 1; - bdfw->watch_flags &= ~IN_EVENTS; - if (! LoopTraits::has_separate_rw_fd_watches) { + if (LoopTraits::has_separate_rw_fd_watches) { + bdfw->watch_flags &= ~IN_EVENTS; + loop_mech.removeFdWatch_nolock(bdfw->watch_fd, IN_EVENTS); + return bdfw->write_removed ? rearm::REMOVE : rearm::NOOP; + } + else { if (! bdfw->write_removed) { + if (bdfw->watch_flags & IN_EVENTS) { + bdfw->watch_flags &= ~IN_EVENTS; + loop_mech.enableFdWatch_nolock(bdfw->watch_fd, bdfw, bdfw->watch_flags); + } return rearm::NOOP; } else { @@ -956,9 +950,6 @@ template class event_loop return rearm::REMOVE; } } - else { - loop_mech.removeFdWatch_nolock(bdfw->watch_fd, IN_EVENTS); - } } else if (rearmType == rearm::DISARM) { // Nothing more to do @@ -968,9 +959,6 @@ template class event_loop if (! LoopTraits::has_separate_rw_fd_watches) { int watch_flags = bdfw->watch_flags; - // If this is a BidiFdWatch (multiwatch) then we do not want to re-enable a - // channel that has an event pending (is already queued): - watch_flags &= ~(bdfw->event_flags); loop_mech.enableFdWatch_nolock(bdfw->watch_fd, static_cast(bdfw), (watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); @@ -1001,14 +989,18 @@ template class event_loop // Called with lock held if (rearmType == rearm::REMOVE) { bdfw->write_removed = 1; - bdfw->watch_flags &= ~OUT_EVENTS; if (LoopTraits::has_separate_rw_fd_watches) { + bdfw->watch_flags &= ~OUT_EVENTS; loop_mech.removeFdWatch_nolock(bdfw->watch_fd, OUT_EVENTS); return bdfw->read_removed ? rearm::REMOVE : rearm::NOOP; } else { if (! bdfw->read_removed) { + if (bdfw->watch_flags & OUT_EVENTS) { + bdfw->watch_flags &= ~OUT_EVENTS; + loop_mech.enableFdWatch_nolock(bdfw->watch_fd, bdfw, bdfw->watch_flags); + } return rearm::NOOP; } else { @@ -1026,9 +1018,6 @@ template class event_loop if (! LoopTraits::has_separate_rw_fd_watches) { int watch_flags = bdfw->watch_flags; - // If this is a BidiFdWatch (multiwatch) then we do not want to re-enable a - // channel that has an event pending (is already queued): - watch_flags &= ~(bdfw->event_flags); loop_mech.enableFdWatch_nolock(bdfw->watch_fd, static_cast(bdfw), (watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); @@ -1107,7 +1096,7 @@ template class event_loop switch (pqueue->watchType) { case WatchType::SIGNAL: { BaseSignalWatcher *bsw = static_cast(pqueue); - rearmType = bsw->received(*this, bsw->siginfo.get_signo(), bsw->siginfo); + rearmType = ((signal_watcher *)bsw)->received(*this, bsw->siginfo.get_signo(), bsw->siginfo); break; } case WatchType::FD: { @@ -1115,28 +1104,28 @@ template class event_loop if (is_multi_watch) { // The primary watcher for a multi-watch watcher is queued for // read events. - rearmType = bbfw->readReady(*this, bfw->watch_fd); + rearmType = ((bidi_fd_watcher *)bbfw)->read_ready(*this, bfw->watch_fd); bbfw->event_flags &= ~IN_EVENTS; } else { - rearmType = bfw->fdEvent(*this, bfw->watch_fd, bfw->event_flags); + rearmType = ((fd_watcher *)bfw)->fd_event(*this, bfw->watch_fd, bfw->event_flags); bfw->event_flags = 0; } break; } case WatchType::CHILD: { BaseChildWatcher *bcw = static_cast(pqueue); - rearmType = bcw->childStatus(*this, bcw->watch_pid, bcw->child_status); + rearmType = ((child_proc_watcher *)bcw)->child_status(*this, bcw->watch_pid, bcw->child_status); break; } case WatchType::SECONDARYFD: { - rearmType = bbfw->writeReady(*this, bbfw->watch_fd); + rearmType = ((bidi_fd_watcher *)bbfw)->write_ready(*this, bbfw->watch_fd); bbfw->event_flags &= ~OUT_EVENTS; break; } case WatchType::TIMER: { BaseTimerWatcher *btw = static_cast(pqueue); - rearmType = btw->timerExpiry(*this, btw->intervals); + rearmType = ((timer *)btw)->timer_expiry(*this, btw->intervals); break; } default: ; @@ -1170,10 +1159,10 @@ template class event_loop if (rearmType == rearm::REMOVE) { ed.lock.unlock(); - // Note that for BidiFd watches, watchRemoved is only called on the primary watch. + // Note that for BidiFd watches, watch_removed is only called on the primary watch. // The process function called above only returns Rearm::REMOVE if both primary and // secondary watches have been removed. - (is_multi_watch ? bbfw : pqueue)->watchRemoved(); + (is_multi_watch ? bbfw : pqueue)->watch_removed(); ed.lock.lock(); } } @@ -1189,13 +1178,11 @@ template class event_loop public: using mutex_t = T_Mutex; - using FdWatcher = dprivate::FdWatcher>; - using BidiFdWatcher = dprivate::BidiFdWatcher>; - using SignalWatcher = dprivate::SignalWatcher>; - using ChildProcWatcher = dprivate::ChildProcWatcher>; - using Timer = dprivate::Timer>; - - // using LoopTraits = dasynq::LoopTraits; + using fd_watcher = dprivate::fd_watcher; + using bidi_fd_watcher = dprivate::bidi_fd_watcher; + using signal_watcher = dprivate::signal_watcher; + using child_proc_watcher = dprivate::child_proc_watcher; + using timer = dprivate::timer; void run() noexcept { @@ -1225,19 +1212,19 @@ namespace dprivate { // Posix signal event watcher template -class SignalWatcher : private dprivate::BaseSignalWatcher +class signal_watcher : private dprivate::BaseSignalWatcher { using BaseWatcher = dprivate::BaseWatcher; using T_Mutex = typename EventLoop::mutex_t; public: - using SigInfo_p = typename dprivate::BaseSignalWatcher::SigInfo_p; + using SigInfo_p = typename dprivate::BaseSignalWatcher::SigInfo_p; // Register this watcher to watch the specified signal. // If an attempt is made to register with more than one event loop at // a time, behaviour is undefined. The signal should be masked before // call. - inline void addWatch(EventLoop &eloop, int signo, int prio = DEFAULT_PRIORITY) + inline void add_watch(EventLoop &eloop, int signo, int prio = DEFAULT_PRIORITY) { BaseWatcher::init(); this->priority = prio; @@ -1250,12 +1237,42 @@ public: eloop.deregister(this, this->siginfo.get_signo()); } - // virtual rearm received(EventLoop &, int signo, SigInfo_p info) = 0; + template + static signal_watcher *add_watch(EventLoop &eloop, int signo, T watchHndlr) + { + class LambdaSigWatcher : public signal_watcher + { + private: + T watchHndlr; + + public: + LambdaSigWatcher(T watchHandlr_a) : watchHndlr(watchHandlr_a) + { + // + } + + rearm received(EventLoop &eloop, int signo, SigInfo_p siginfo) override + { + return watchHndlr(eloop, signo, siginfo); + } + + void watch_removed() noexcept override + { + delete this; + } + }; + + LambdaSigWatcher * lsw = new LambdaSigWatcher(watchHndlr); + lsw->add_watch(eloop, signo); + return lsw; + } + + virtual rearm received(EventLoop &eloop, int signo, SigInfo_p siginfo) = 0; }; // Posix file descriptor event watcher template -class FdWatcher : private dprivate::BaseFdWatcher +class fd_watcher : private dprivate::BaseFdWatcher { using BaseWatcher = dprivate::BaseWatcher; using T_Mutex = typename EventLoop::mutex_t; @@ -1266,7 +1283,7 @@ class FdWatcher : private dprivate::BaseFdWatcher // is true; otherwise has unspecified behavior. // Only safe to call from within the callback handler (fdEvent). Might not take // effect until the current callback handler returns with REARM. - void setWatchFlags(int newFlags) + void set_watch_flags(int newFlags) { this->watch_flags = newFlags; } @@ -1286,7 +1303,7 @@ class FdWatcher : private dprivate::BaseFdWatcher // causes undefined behavior. // // Can fail with std::bad_alloc or std::system_error. - void addWatch(EventLoop &eloop, int fd, int flags, bool enabled = true, int prio = DEFAULT_PRIORITY) + void add_watch(EventLoop &eloop, int fd, int flags, bool enabled = true, int prio = DEFAULT_PRIORITY) { BaseWatcher::init(); this->priority = prio; @@ -1295,7 +1312,7 @@ class FdWatcher : private dprivate::BaseFdWatcher eloop.registerFd(this, fd, flags, enabled); } - int getWatchedFd() + int get_watched_fd() { return this->watch_fd; } @@ -1303,7 +1320,7 @@ class FdWatcher : private dprivate::BaseFdWatcher // Deregister a file descriptor watcher. // // If other threads may be polling the event loop, it is not safe to assume - // the watcher is unregistered until the watchRemoved() callback is issued + // the watcher is unregistered until the watch_removed() callback is issued // (which will not occur until the event handler returns, if it is active). // In a single threaded environment, it is safe to delete the watcher after // calling this method as long as the handler (if it is active) accesses no @@ -1313,7 +1330,7 @@ class FdWatcher : private dprivate::BaseFdWatcher eloop.deregister(this, this->watch_fd); } - void setEnabled(EventLoop &eloop, bool enable) noexcept + void set_enabled(EventLoop &eloop, bool enable) noexcept { std::lock_guard guard(eloop.getBaseLock()); eloop.setFdEnabled_nolock(this, this->watch_fd, this->watch_flags, enable); @@ -1325,9 +1342,9 @@ class FdWatcher : private dprivate::BaseFdWatcher // Add an Fd watch via a lambda. The watch is allocated dynamically and destroys // itself when removed from the event loop. template - static FdWatcher *addWatch(EventLoop &eloop, int fd, int flags, T watchHndlr) + static fd_watcher *add_watch(EventLoop &eloop, int fd, int flags, T watchHndlr) { - class LambdaFdWatcher : public FdWatcher + class LambdaFdWatcher : public fd_watcher { private: T watchHndlr; @@ -1338,35 +1355,35 @@ class FdWatcher : private dprivate::BaseFdWatcher // } - rearm fdEvent(EventLoop &eloop, int fd, int flags) override + rearm fd_event(EventLoop &eloop, int fd, int flags) override { return watchHndlr(eloop, fd, flags); } - void watchRemoved() noexcept override + void watch_removed() noexcept override { delete this; } }; LambdaFdWatcher * lfd = new LambdaFdWatcher(watchHndlr); - lfd->addWatch(eloop, fd, flags); + lfd->add_watch(eloop, fd, flags); return lfd; } - // virtual rearm fdEvent(EventLoop &, int fd, int flags) = 0; + virtual rearm fd_event(EventLoop &eloop, int fd, int flags) = 0; }; // A Bi-directional file descriptor watcher with independent read- and write- channels. // This watcher type has two event notification methods which can both potentially be // active at the same time. template -class BidiFdWatcher : private dprivate::BaseBidiFdWatcher +class bidi_fd_watcher : private dprivate::BaseBidiFdWatcher { using BaseWatcher = dprivate::BaseWatcher; using T_Mutex = typename EventLoop::mutex_t; - void setWatchEnabled(EventLoop &eloop, bool in, bool b) + void set_watch_enabled(EventLoop &eloop, bool in, bool b) { int events = in ? IN_EVENTS : OUT_EVENTS; @@ -1376,7 +1393,7 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcherwatch_flags &= ~events; } - if (EventLoop::LoopTraits::has_separate_rw_fd_watches) { + if (EventLoop::loop_traits_t::has_separate_rw_fd_watches) { dprivate::BaseWatcher * watcher = in ? this : &this->outWatcher; eloop.setFdEnabled_nolock(watcher, this->watch_fd, events | ONE_SHOT, b); if (! b) { @@ -1394,19 +1411,27 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcher guard(eloop.getBaseLock()); - if (LoopTraits::has_separate_rw_fd_watches) { - setWatchEnabled(eloop, true, (newFlags & IN_EVENTS) != 0); - setWatchEnabled(eloop, false, (newFlags & OUT_EVENTS) != 0); + if (EventLoop::loop_traits_t::has_separate_rw_fd_watches) { + set_watch_enabled(eloop, true, (newFlags & IN_EVENTS) != 0); + set_watch_enabled(eloop, false, (newFlags & OUT_EVENTS) != 0); } else { this->watch_flags = (this->watch_flags & ~IO_EVENTS) | newFlags; @@ -1431,13 +1456,11 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcheroutWatcher.BaseWatcher::init(); @@ -1450,7 +1473,7 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcherwatch_fd; } @@ -1458,7 +1481,7 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcherwatch_fd); } - // rearm readReady(EventLoop * eloop, int fd) noexcept - // rearm writeReady(EventLoop * eloop, int fd) noexcept + virtual rearm read_ready(EventLoop &eloop, int fd) noexcept = 0; + virtual rearm write_ready(EventLoop &eloop, int fd) noexcept = 0; }; // Child process event watcher template -class ChildProcWatcher : private dprivate::BaseChildWatcher +class child_proc_watcher : private dprivate::BaseChildWatcher { using BaseWatcher = dprivate::BaseWatcher; using T_Mutex = typename EventLoop::mutex_t; @@ -1483,7 +1506,7 @@ class ChildProcWatcher : private dprivate::BaseChildWatcherwatch_pid = child; @@ -1511,7 +1534,7 @@ class ChildProcWatcher : private dprivate::BaseChildWatcherwatch_pid = child; @@ -1533,9 +1556,9 @@ class ChildProcWatcher : private dprivate::BaseChildWatcher -class Timer : private BaseTimerWatcher +class timer : private BaseTimerWatcher { + private: + clock_type clock; + public: - // Allocate a timer (using the MONOTONIC clock) - void addTimer(EventLoop &eloop, int prio = DEFAULT_PRIORITY) + void add_timer(EventLoop &eloop, clock_type clock = clock_type::MONOTONIC, int prio = DEFAULT_PRIORITY) { this->priority = prio; - eloop.registerTimer(this); + this->clock = clock; + eloop.registerTimer(this, clock); } - void armTimer(EventLoop &eloop, struct timespec &timeout) noexcept + void arm_timer(EventLoop &eloop, struct timespec &timeout) noexcept { - eloop.setTimer(this, timeout); + eloop.setTimer(this, timeout, clock); } - void armTimer(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept + void arm_timer(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept { - eloop.setTimer(this, timeout, interval); + eloop.setTimer(this, timeout, interval, clock); } // Arm timer, relative to now: - void armTimerRel(EventLoop &eloop, struct timespec &timeout) noexcept + void arm_timer_rel(EventLoop &eloop, struct timespec &timeout) noexcept { - eloop.setTimerRel(this, timeout); + eloop.setTimerRel(this, timeout, clock); } - void armTimerRel(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept + void arm_timer_rel(EventLoop &eloop, struct timespec &timeout, struct timespec &interval) noexcept { - eloop.setTimerRel(this, timeout, interval); + eloop.setTimerRel(this, timeout, interval, clock); } void deregister(EventLoop &eloop) noexcept { - eloop.deregister(this); + eloop.deregister(this, clock); } + + // Timer expired, and the given number of intervals have elapsed before + // expiry evenet was queued. Normally intervals == 1 to indicate no + // overrun. + virtual rearm timer_expiry(EventLoop &eloop, int intervals) = 0; }; } // namespace dasynq::dprivate diff --git a/src/dinit-log.cc b/src/dinit-log.cc index af46516..f96e3aa 100644 --- a/src/dinit-log.cc +++ b/src/dinit-log.cc @@ -20,7 +20,7 @@ LogLevel log_level[2] = { LogLevel::WARN, LogLevel::WARN }; static ServiceSet *service_set = nullptr; // Reference to service set namespace { -class BufferedLogStream : public EventLoop_t::FdWatcher +class BufferedLogStream : public EventLoop_t::fd_watcher { private: @@ -50,7 +50,7 @@ class BufferedLogStream : public EventLoop_t::FdWatcher release = false; } - rearm fdEvent(EventLoop_t &loop, int fd, int flags) noexcept override; + rearm fd_event(EventLoop_t &loop, int fd, int flags) noexcept override; // Check whether the console can be released. void flushForRelease(); @@ -63,7 +63,7 @@ class BufferedLogStream : public EventLoop_t::FdWatcher bool was_first = current_index == 0; current_index = log_buffer.get_length(); if (was_first && ! release) { - setEnabled(eventLoop, true); + set_enabled(eventLoop, true); } } @@ -119,15 +119,15 @@ void BufferedLogStream::flushForRelease() // Try to flush any messages that are currently buffered. (Console is non-blocking // so it will fail gracefully). - if (fdEvent(eventLoop, fd, OUT_EVENTS) == rearm::DISARM) { + if (fd_event(eventLoop, fd, OUT_EVENTS) == rearm::DISARM) { // Console has already been released at this point. - setEnabled(eventLoop, false); + set_enabled(eventLoop, false); } - // fdEvent didn't want to disarm, so must be partway through a message; will + // fd_event didn't want to disarm, so must be partway through a message; will // release when it's finished. } -rearm BufferedLogStream::fdEvent(EventLoop_t &loop, int fd, int flags) noexcept +rearm BufferedLogStream::fd_event(EventLoop_t &loop, int fd, int flags) noexcept { if ((! partway) && (! special) && discarded) { special_buf = "dinit: *** message discarded due to full buffer ****\n"; @@ -237,7 +237,7 @@ rearm BufferedLogStream::fdEvent(EventLoop_t &loop, int fd, int flags) noexcept void init_log(ServiceSet *sset) { service_set = sset; - log_stream[DLOG_CONS].addWatch(eventLoop, STDOUT_FILENO, OUT_EVENTS, false); + log_stream[DLOG_CONS].add_watch(eventLoop, STDOUT_FILENO, OUT_EVENTS, false); enable_console_log(true); } @@ -246,7 +246,7 @@ void init_log(ServiceSet *sset) void setup_main_log(int fd) { log_stream[DLOG_MAIN].init(fd); - log_stream[DLOG_MAIN].addWatch(eventLoop, fd, OUT_EVENTS); + log_stream[DLOG_MAIN].add_watch(eventLoop, fd, OUT_EVENTS); } bool is_log_flushed() noexcept @@ -267,7 +267,7 @@ void enable_console_log(bool enable) noexcept fcntl(1, F_SETFL, flags | O_NONBLOCK); // Activate watcher: log_stream[DLOG_CONS].init(STDOUT_FILENO); - log_stream[DLOG_CONS].setEnabled(eventLoop, true); + log_stream[DLOG_CONS].set_enabled(eventLoop, true); } else if (! enable && log_to_console) { log_stream[DLOG_CONS].flushForRelease(); diff --git a/src/dinit.cc b/src/dinit.cc index 447fff4..b7a19e3 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -52,9 +52,9 @@ void open_control_socket(bool report_ro_failure = true) noexcept; void setup_external_log() noexcept; -class ControlSocketWatcher : public EventLoop_t::FdWatcher +class ControlSocketWatcher : public EventLoop_t::fd_watcher { - rearm fdEvent(EventLoop_t &loop, int fd, int flags) override + rearm fd_event(EventLoop_t &loop, int fd, int flags) override { control_socket_cb(&loop, fd); return rearm::REARM; @@ -102,7 +102,7 @@ const char * get_user_home() namespace { - class CallbackSignalHandler : public EventLoop_t::SignalWatcher + class CallbackSignalHandler : public EventLoop_t::signal_watcher { public: typedef void (*cb_func_t)(EventLoop_t *); @@ -126,9 +126,9 @@ namespace { } }; - class ControlSocketWatcher : public EventLoop_t::FdWatcher + class ControlSocketWatcher : public EventLoop_t::fd_watcher { - rearm fdEvent(EventLoop_t &loop, int fd, int flags) + rearm fd_event(EventLoop_t &loop, int fd, int flags) override { control_socket_cb(&loop, fd); return rearm::REARM; @@ -290,9 +290,9 @@ int main(int argc, char **argv) auto sigterm_watcher = CallbackSignalHandler(sigterm_cb); - sigint_watcher.addWatch(eventLoop, SIGINT); - sigquit_watcher.addWatch(eventLoop, SIGQUIT); - sigterm_watcher.addWatch(eventLoop, SIGTERM); + sigint_watcher.add_watch(eventLoop, SIGINT); + sigquit_watcher.add_watch(eventLoop, SIGQUIT); + sigterm_watcher.add_watch(eventLoop, SIGTERM); // Try to open control socket (may fail due to readonly filesystem) open_control_socket(false); @@ -479,7 +479,7 @@ void open_control_socket(bool report_ro_failure) noexcept } try { - control_socket_io.addWatch(eventLoop, sockfd, IN_EVENTS); + control_socket_io.add_watch(eventLoop, sockfd, IN_EVENTS); control_socket_open = true; } catch (std::exception &e) @@ -493,7 +493,7 @@ void open_control_socket(bool report_ro_failure) noexcept static void close_control_socket() noexcept { if (control_socket_open) { - int fd = control_socket_io.getWatchedFd(); + int fd = control_socket_io.get_watched_fd(); control_socket_io.deregister(eventLoop); close(fd); diff --git a/src/service.cc b/src/service.cc index 258e0e8..6db03ef 100644 --- a/src/service.cc +++ b/src/service.cc @@ -120,7 +120,7 @@ void ServiceRecord::stopped() noexcept } } -dasynq::rearm ServiceChildWatcher::childStatus(EventLoop_t &loop, pid_t child, int status) noexcept +dasynq::rearm ServiceChildWatcher::child_status(EventLoop_t &loop, pid_t child, int status) noexcept { ServiceRecord *sr = service; @@ -261,15 +261,15 @@ void ServiceRecord::handle_exit_status() noexcept } } -rearm ServiceIoWatcher::fdEvent(EventLoop_t &loop, int fd, int flags) noexcept +rearm ServiceIoWatcher::fd_event(EventLoop_t &loop, int fd, int flags) noexcept { ServiceRecord *sr = service; sr->waiting_for_execstat = false; int exec_status; - int r = read(getWatchedFd(), &exec_status, sizeof(int)); + int r = read(get_watched_fd(), &exec_status, sizeof(int)); deregister(loop); - close(getWatchedFd()); + close(get_watched_fd()); if (r > 0) { // We read an errno code; exec() failed, and the service startup failed. @@ -623,7 +623,7 @@ bool ServiceRecord::read_pid_file() noexcept pidbuf[r] = 0; // store nul terminator pid = std::atoi(pidbuf); if (kill(pid, 0) == 0) { - child_listener.addWatch(eventLoop, pid); + child_listener.add_watch(eventLoop, pid); } else { log(LogLevel::ERROR, service_name, ": pid read from pidfile (", pid, ") is not valid"); @@ -766,7 +766,7 @@ bool ServiceRecord::start_ps_process(const std::vector &cmd, bool pid_t forkpid; try { - child_status_listener.addWatch(eventLoop, pipefd[0], IN_EVENTS); + child_status_listener.add_watch(eventLoop, pipefd[0], IN_EVENTS); child_status_registered = true; forkpid = child_listener.fork(eventLoop); diff --git a/src/service.h b/src/service.h index 3b58e90..24f1e36 100644 --- a/src/service.h +++ b/src/service.h @@ -184,20 +184,20 @@ static std::vector separate_args(std::string &s, std::list