From 807ce78fa5ffc73447defd4a96b287c2fc2485be Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Wed, 9 Nov 2016 20:19:36 +0000 Subject: [PATCH] Incorporate Dasynq changes (v0.02) --- src/dasynq/dasynq-epoll.h | 2 ++ src/dasynq/dasynq-kqueue.h | 2 ++ src/dasynq/dasynq.h | 47 +++++++++++++++++++++++--------------- 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/dasynq/dasynq-epoll.h b/src/dasynq/dasynq-epoll.h index dd1f404..763c40a 100644 --- a/src/dasynq/dasynq-epoll.h +++ b/src/dasynq/dasynq-epoll.h @@ -174,6 +174,8 @@ template class EpollLoop : public Base throw std::system_error(std::make_error_code(std::errc::not_supported)); } + // flags specifies which watch to remove; ignored if the loop doesn't support + // separate read/write watches. void removeFdWatch(int fd, int flags) noexcept { epoll_ctl(epfd, EPOLL_CTL_DEL, fd, nullptr); diff --git a/src/dasynq/dasynq-kqueue.h b/src/dasynq/dasynq-kqueue.h index 784068c..ad44708 100644 --- a/src/dasynq/dasynq-kqueue.h +++ b/src/dasynq/dasynq-kqueue.h @@ -225,6 +225,8 @@ template class KqueueLoop : public Base } } + // flags specifies which watch to remove; ignored if the loop doesn't support + // separate read/write watches. void removeFdWatch(int fd, int flags) { removeFilter((flags & IN_EVENTS) ? EVFILT_READ : EVFILT_WRITE, fd); diff --git a/src/dasynq/dasynq.h b/src/dasynq/dasynq.h index c457a40..6dc785a 100644 --- a/src/dasynq/dasynq.h +++ b/src/dasynq/dasynq.h @@ -104,7 +104,7 @@ namespace dprivate { // that is, watcher should not be disabled until all watched event types are queued. constexpr static int multi_watch = 4; - // Represents a queued event notification + // Represents a queued event notification. Various event watchers derive from this type. class BaseWatcher { template friend class EventDispatch; @@ -169,8 +169,10 @@ namespace dprivate { protected: int watch_fd; - int watch_flags; - int event_flags; + + // These flags are protected by the loop's internal lock: + int watch_flags; // events being watched + int event_flags; // events pending (queued) BaseFdWatcher() noexcept : BaseWatcher(WatchType::FD) { } @@ -303,9 +305,6 @@ namespace dprivate { }; // This class serves as the base class (mixin) for the AEN mechanism class. - // Note that EventDispatch, here, and EventLoop (below) are really two sides of one coin; - // they do not work independently. The mixin pattern that we use to avoid dynamic dispatch - // forces them to be two seperate classes, however. // // The EventDispatch class maintains the queued event data structures. It inserts watchers // into the queue when eventes are received (receiveXXX methods). @@ -314,7 +313,7 @@ namespace dprivate { friend class EventLoop; // queue data structure/pointer - BaseWatcher * first; + BaseWatcher * first = nullptr; using BaseSignalWatcher = dasynq::dprivate::BaseSignalWatcher; using BaseFdWatcher = dasynq::dprivate::BaseFdWatcher; @@ -753,7 +752,9 @@ template class EventLoop Rearm processFdRearm(BaseFdWatcher * bfw, Rearm rearmType, bool is_multi_watch) { - // Called with lock held + // Called with lock held; + // bdfw->event_flags contains only with pending (queued) events + if (is_multi_watch) { BaseBidiFdWatcher * bdfw = static_cast(bfw); @@ -772,9 +773,7 @@ template class EventLoop } } else { - // TODO this will need flags for such a loop, since it can't - // otherwise distinguish which channel watch to remove - loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags); + loop_mech.removeFdWatch_nolock(bdfw->watch_fd, IN_EVENTS); } } else if (rearmType == Rearm::DISARM) { @@ -782,10 +781,15 @@ template class EventLoop } else if (rearmType == Rearm::REARM) { bdfw->watch_flags |= IN_EVENTS; + 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), - (bdfw->watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); + (watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); } else { loop_mech.enableFdWatch_nolock(bdfw->watch_fd, @@ -807,6 +811,7 @@ template class EventLoop } } + // Process re-arm for the secondary (output) watcher in a Bi-direction Fd watcher. Rearm processSecondaryRearm(BaseBidiFdWatcher * bdfw, Rearm rearmType) { // Called with lock held @@ -815,9 +820,7 @@ template class EventLoop bdfw->watch_flags &= ~OUT_EVENTS; if (LoopTraits::has_separate_rw_fd_watches) { - // TODO this will need flags for such a loop, since it can't - // otherwise distinguish which channel watch to remove - loop_mech.removeFdWatch_nolock(bdfw->watch_fd, bdfw->watch_flags); + loop_mech.removeFdWatch_nolock(bdfw->watch_fd, OUT_EVENTS); return bdfw->read_removed ? Rearm::REMOVE : Rearm::NOOP; } else { @@ -836,10 +839,15 @@ template class EventLoop } else if (rearmType == Rearm::REARM) { bdfw->watch_flags |= OUT_EVENTS; + 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), - (bdfw->watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); + (watch_flags & (IN_EVENTS | OUT_EVENTS)) | ONE_SHOT); } else { loop_mech.enableFdWatch_nolock(bdfw->watch_fd, @@ -913,9 +921,11 @@ template class EventLoop // The primary watcher for a multi-watch watcher is queued for // read events. rearmType = bbfw->readReady(*this, bfw->watch_fd); + bbfw->event_flags &= ~IN_EVENTS; } else { rearmType = bfw->fdEvent(*this, bfw->watch_fd, bfw->event_flags); + bfw->event_flags = 0; } break; } @@ -926,6 +936,7 @@ template class EventLoop } case WatchType::SECONDARYFD: { rearmType = bbfw->writeReady(*this, bbfw->watch_fd); + bbfw->event_flags &= ~OUT_EVENTS; break; } default: ; @@ -1088,7 +1099,6 @@ class FdWatcher : private dprivate::BaseFdWatcher // 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 // internal state and returns Rearm::REMOVED. - // TODO: implement REMOVED, or correct above statement. void deregister(EventLoop &eloop) noexcept { eloop.deregister(this, this->watch_fd); @@ -1192,6 +1202,8 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcheroutWatcher.BaseWatcher::init(); this->watch_fd = fd; this->watch_flags = flags | dprivate::multi_watch; + this->read_removed = false; + this->write_removed = false; eloop.registerFd(this, fd, flags); } @@ -1208,7 +1220,6 @@ class BidiFdWatcher : private dprivate::BaseBidiFdWatcherwatch_fd); -- 2.25.1