// Copyright (c) Vitaliy Filippov, 2019+ // License: VNPL-1.0 or GNU GPL-2.0+ (see README.md for details) #include #include #include #include "timerfd_interval.h" timerfd_interval::timerfd_interval(ring_loop_t *ringloop, int seconds, std::function cb) { wait_state = 0; timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); if (timerfd < 0) { throw std::runtime_error(std::string("timerfd_create: ") + strerror(errno)); } struct itimerspec exp = { .it_interval = { seconds, 0 }, .it_value = { seconds, 0 }, }; if (timerfd_settime(timerfd, 0, &exp, NULL)) { throw std::runtime_error(std::string("timerfd_settime: ") + strerror(errno)); } consumer.loop = [this]() { loop(); }; ringloop->register_consumer(&consumer); this->ringloop = ringloop; this->callback = cb; } timerfd_interval::~timerfd_interval() { ringloop->unregister_consumer(&consumer); close(timerfd); } void timerfd_interval::loop() { if (wait_state == 1) { return; } struct io_uring_sqe *sqe = ringloop->get_sqe(); if (!sqe) { wait_state = 0; return; } struct ring_data_t *data = ((ring_data_t*)sqe->user_data); my_uring_prep_poll_add(sqe, timerfd, POLLIN); data->callback = [&](ring_data_t *data) { if (data->res < 0) { throw std::runtime_error(std::string("waiting for timer failed: ") + strerror(-data->res)); } uint64_t n; read(timerfd, &n, 8); wait_state = 0; callback(); }; wait_state = 1; ringloop->submit(); }