diff options
Diffstat (limited to 'src/looper_poll.cc')
| -rw-r--r-- | src/looper_poll.cc | 176 |
1 files changed, 129 insertions, 47 deletions
diff --git a/src/looper_poll.cc b/src/looper_poll.cc index 2fed7d2..e6bf2cd 100644 --- a/src/looper_poll.cc +++ b/src/looper_poll.cc @@ -21,6 +21,64 @@ namespace looper { namespace { +inline short events_looper2poll(uint8_t events) { + short ret = 0; + if (events & EVENT_READ) + // NOLINTNEXTLINE(misc-include-cleaner) + ret |= POLLIN | POLLPRI; + if (events & EVENT_WRITE) + // NOLINTNEXTLINE(misc-include-cleaner) + ret |= POLLOUT; + return ret; +} + +inline uint8_t events_poll2looper(short events) { + uint8_t ret = 0; + // NOLINTNEXTLINE(misc-include-cleaner) + if (events & (POLLIN | POLLPRI | POLLHUP)) + ret |= EVENT_READ; + // NOLINTNEXTLINE(misc-include-cleaner) + if (events & POLLOUT) + ret |= EVENT_WRITE; + // NOLINTNEXTLINE(misc-include-cleaner) + if (events & (POLLERR | POLLNVAL)) + ret |= EVENT_ERROR; + return ret; +} + +class HookHelperImpl : public HookHelper { + public: + // NOLINTNEXTLINE(misc-include-cleaner) + HookHelperImpl(std::vector<struct pollfd>& pollfd, int& timeout) + : pollfd_(pollfd), timeout_(timeout) {} + + void monitor(int fd, uint8_t events) override { + // NOLINTNEXTLINE(misc-include-cleaner) + struct pollfd tmp; + tmp.fd = fd; + tmp.events = events_looper2poll(events); + pollfd_.push_back(tmp); + } + + void timeout(std::chrono::milliseconds timeout) override { + int new_timeout; + if (timeout.count() <= std::numeric_limits<int>::max()) { + new_timeout = static_cast<int>(timeout.count()); + } else { + new_timeout = std::numeric_limits<int>::max(); + } + if (timeout_ == -1) { + timeout_ = new_timeout; + } else { + timeout_ = std::min(timeout_, new_timeout); + } + } + + private: + std::vector<struct pollfd>& pollfd_; + int& timeout_; +}; + class LooperPoll : public Looper { public: LooperPoll() = default; @@ -91,17 +149,31 @@ class LooperPoll : public Looper { // NOLINTNEXTLINE(misc-include-cleaner) std::vector<struct pollfd> pollfd; pollfd.reserve(entry_.size()); - auto it = entry_.begin(); - while (it != entry_.end()) { - if (it->second.delete_) { - it = entry_.erase(it); - } else { - // NOLINTNEXTLINE(misc-include-cleaner) - struct pollfd tmp; - tmp.fd = it->first; - tmp.events = events_looper2poll(it->second.events_); - pollfd.push_back(tmp); - ++it; + { + auto it = entry_.begin(); + while (it != entry_.end()) { + if (it->second.delete_) { + it = entry_.erase(it); + } else { + // NOLINTNEXTLINE(misc-include-cleaner) + struct pollfd tmp; + tmp.fd = it->first; + tmp.events = events_looper2poll(it->second.events_); + pollfd.push_back(tmp); + ++it; + } + } + } + if (!hooks_.empty()) { + HookHelperImpl helper(pollfd, timeout); + auto it = hooks_.begin(); + while (it != hooks_.end()) { + if (it->delete_) { + it = hooks_.erase(it); + } else { + it->hook_->before(helper); + ++it; + } } } // NOLINTNEXTLINE(misc-include-cleaner) @@ -112,21 +184,36 @@ class LooperPoll : public Looper { logger.err(std::format("Poll failed: {}", strerror(errno))); return false; } - for (auto it2 = pollfd.begin(); active; ++it2) { - if (it2->revents == 0) - continue; - --active; - auto events = events_poll2looper(it2->revents); - if (events) { - it = entry_.find(it2->fd); - if (!it->second.delete_) { - events &= (it->second.events_ | EVENT_ERROR); - if (events) { - it->second.callback_(events); + { + for (auto it = pollfd.begin(); active; ++it) { + if (it->revents == 0) + continue; + --active; + auto events = events_poll2looper(it->revents); + if (events) { + auto it2 = entry_.find(it->fd); + if (it2 == entry_.end()) + break; + if (!it2->second.delete_) { + events &= (it2->second.events_ | EVENT_ERROR); + if (events) { + it2->second.callback_(events); + } } } } } + { + auto it = hooks_.begin(); + while (it != hooks_.end()) { + if (it->delete_) { + it = hooks_.erase(it); + } else { + it->hook_->after(); + ++it; + } + } + } } // Reset quit_ so run() can be called again quit_ = false; @@ -165,6 +252,18 @@ class LooperPoll : public Looper { } } + void add_hook(Hook* hook) override { + assert(hook); + hooks_.emplace_back(hook); + } + + void remove_hook(Hook* hook) override { + auto it = std::ranges::find_if( + hooks_, [hook](auto const& entry) { return entry.hook_ == hook; }); + if (it != hooks_.end()) + it->delete_ = true; + } + private: struct Entry { uint8_t events_; @@ -174,6 +273,13 @@ class LooperPoll : public Looper { explicit Entry(uint8_t events) : events_(events) {} }; + struct HookEntry { + Hook* hook_; + bool delete_{false}; + + explicit HookEntry(Hook* hook) : hook_(hook) {} + }; + struct Scheduled { std::function<void(uint32_t)> callback_; uint32_t id_; @@ -184,31 +290,6 @@ class LooperPoll : public Looper { : callback_(std::move(callback)), id_(id), target_(target) {} }; - static short events_looper2poll(uint8_t events) { - short ret = 0; - if (events & EVENT_READ) - // NOLINTNEXTLINE(misc-include-cleaner) - ret |= POLLIN | POLLPRI; - if (events & EVENT_WRITE) - // NOLINTNEXTLINE(misc-include-cleaner) - ret |= POLLOUT; - return ret; - } - - static uint8_t events_poll2looper(short events) { - uint8_t ret = 0; - // NOLINTNEXTLINE(misc-include-cleaner) - if (events & (POLLIN | POLLPRI | POLLHUP)) - ret |= EVENT_READ; - // NOLINTNEXTLINE(misc-include-cleaner) - if (events & POLLOUT) - ret |= EVENT_WRITE; - // NOLINTNEXTLINE(misc-include-cleaner) - if (events & (POLLERR | POLLNVAL)) - ret |= EVENT_ERROR; - return ret; - } - uint32_t next_schedule_id() { while (true) { uint32_t ret = next_schedule_id_++; @@ -226,6 +307,7 @@ class LooperPoll : public Looper { std::unordered_map<int, Entry> entry_; uint32_t next_schedule_id_{1}; std::deque<Scheduled> scheduled_; + std::vector<HookEntry> hooks_; }; } // namespace |
