Skip to content

Instantly share code, notes, and snippets.

@qookei
Created May 29, 2020 23:02
Show Gist options
  • Save qookei/197fb68f1d5398bf2af0a62f32cb1074 to your computer and use it in GitHub Desktop.
Save qookei/197fb68f1d5398bf2af0a62f32cb1074 to your computer and use it in GitHub Desktop.
struct timerfd final : file {
static auto create_timer(reactor *rtor_) {
return new timerfd{rtor_};
}
timerfd(reactor *rtor)
: file{rtor, timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)}, current_{} { }
// ----------------------------------------------------------------------------------
// Sleep boilerplate.
// ----------------------------------------------------------------------------------
private:
struct sleep_base {
friend struct timerfd;
sleep_base(timespec t)
: t_{t} { }
protected:
~sleep_base() = default;
virtual void complete() = 0;
private:
timespec t_;
};
public:
struct [[nodiscard]] sleep_sender {
timerfd *fd;
timespec t;
};
sleep_sender async_sleep(timespec t) {
assert(!current_ && "one timerfd can only be used for one sleep at a time");
return {this, t};
}
template<typename Receiver>
struct sleep_operation final : sleep_base {
friend struct timerfd;
sleep_operation(sleep_sender s, Receiver r)
: sleep_base{s.t}, fd_{s.fd}, r_{std::move(r)} { }
void start() {
itimerspec ts{.it_value = t_, .it_interval = {}};
timerfd_settime(fd_->get_fd(), 0, &ts, nullptr);
fd_->current_ = this;
}
protected:
void complete() override {
fd_->current_ = nullptr;
r_.set_value();
}
private:
timerfd *fd_;
Receiver r_;
};
template<typename Receiver>
friend sleep_operation<Receiver> connect(sleep_sender s, Receiver r) {
return {s, std::move(r)};
}
friend async::sender_awaiter<sleep_sender, void>
operator co_await(sleep_sender s) {
return {s};
};
protected:
void on_readable() override {
assert(current_);
current_->complete();
}
void on_writable() override { }
private:
sleep_base *current_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment