summaryrefslogtreecommitdiff
path: root/src/looper_poll.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/looper_poll.cc')
-rw-r--r--src/looper_poll.cc176
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