Skip to content

Commit

Permalink
GH-985 Avoid multiple expiration callback calls.
Browse files Browse the repository at this point in the history
  • Loading branch information
heifner committed Oct 31, 2024
1 parent ecf2d0a commit d0ea755
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 31 deletions.
22 changes: 13 additions & 9 deletions libraries/chain/platform_timer_asio_fallback.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,44 +57,48 @@ platform_timer::~platform_timer() {

void platform_timer::start(fc::time_point tp) {
if(tp == fc::time_point::maximum()) {
expired = 0;
expired = false;
return;
}
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
if(x.count() <= 0)
expired = 1;
expired = true;
else {
#if 0
std::promise<void> p;
auto f = p.get_future();
checktime_ios->post([&p,this]() {
expired = 0;
expired = false;
p.set_value();
});
f.get();
#endif
expired = 0;
expired = false;
my->timer->expires_after(std::chrono::microseconds(x.count()));
my->timer->async_wait([this](const boost::system::error_code& ec) {
if(ec)
return;
expired = 1;
call_expiration_callback();
bool expected = false;
if (expired.compare_exchange_strong(expected, true)) {
call_expiration_callback();
}
});
}
}

void platform_timer::expire_now() {
expired = 1;
call_expiration_callback();
bool expected = false;
if (expired.compare_exchange_strong(expected, true)) {
call_expiration_callback();
}
}

void platform_timer::stop() {
if(expired)
return;

my->timer->cancel();
expired = 1;
expired = true;
}

}}
22 changes: 13 additions & 9 deletions libraries/chain/platform_timer_kqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ platform_timer::platform_timer() {

if(c == 1 && anEvent.filter == EVFILT_TIMER) {
platform_timer* self = (platform_timer*)anEvent.udata;
self->expired = 1;
self->call_expiration_callback();
bool expected = false;
if (self->expired.compare_exchange_strong(expected, true)) {
self->call_expiration_callback();
}
}
else if(c == 1 && anEvent.filter == EVFILT_USER)
return;
Expand Down Expand Up @@ -90,25 +92,27 @@ platform_timer::~platform_timer() {

void platform_timer::start(fc::time_point tp) {
if(tp == fc::time_point::maximum()) {
expired = 0;
expired = false;
return;
}
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
if(x.count() <= 0)
expired = 1;
expired = true;
else {
struct kevent64_s aTimerEvent;
EV_SET64(&aTimerEvent, my->timerid, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, NOTE_USECONDS|NOTE_CRITICAL, x.count(), (uint64_t)this, 0, 0);

expired = 0;
expired = false;
if(kevent64(kqueue_fd, &aTimerEvent, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL) != 0)
expired = 1;
expired = true;
}
}

void platform_timer::expire_now() {
expired = 1;
call_expiration_callback();
bool expected = false;
if (expired.compare_exchange_strong(expected, true)) {
call_expiration_callback();
}
}

void platform_timer::stop() {
Expand All @@ -118,7 +122,7 @@ void platform_timer::stop() {
struct kevent64_s stop_timer_event;
EV_SET64(&stop_timer_event, my->timerid, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0);
kevent64(kqueue_fd, &stop_timer_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL);
expired = 1;
expired = true;
}

}}
32 changes: 19 additions & 13 deletions libraries/chain/platform_timer_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
#include <fc/fwd_impl.hpp>
#include <fc/exception/exception.hpp>

#include <atomic>
#include <mutex>

#include <signal.h>
#include <time.h>
#include <sys/types.h>

namespace eosio { namespace chain {
namespace eosio::chain {

static_assert(std::atomic_bool::is_always_lock_free, "Only lock-free atomics AS-safe.");

Expand All @@ -19,18 +21,20 @@ struct platform_timer::impl {

static void sig_handler(int, siginfo_t* si, void*) {
platform_timer* self = (platform_timer*)si->si_value.sival_ptr;
self->expired = 1;
self->call_expiration_callback();
bool expected = false;
if (self->expired.compare_exchange_strong(expected, true)) {
self->call_expiration_callback();
}
}
};

platform_timer::platform_timer() {
static_assert(sizeof(impl) <= fwd_size);

static bool initialized;
static std::mutex initalized_mutex;
static std::mutex initialized_mutex;

if(std::lock_guard guard(initalized_mutex); !initialized) {
if(std::lock_guard guard(initialized_mutex); !initialized) {
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = impl::sig_handler;
Expand All @@ -55,33 +59,35 @@ platform_timer::~platform_timer() {

void platform_timer::start(fc::time_point tp) {
if(tp == fc::time_point::maximum()) {
expired = 0;
expired = false;
return;
}
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
if(x.count() <= 0)
expired = 1;
expired = true;
else {
time_t secs = x.count() / 1000000;
long nsec = (x.count() - (secs*1000000)) * 1000;
struct itimerspec enable = {{0, 0}, {secs, nsec}};
expired = 0;
expired = false;
if(timer_settime(my->timerid, 0, &enable, NULL) != 0)
expired = 1;
expired = true;
}
}

void platform_timer::expire_now() {
expired = 1;
call_expiration_callback();
bool expected = false;
if (expired.compare_exchange_strong(expected, true)) {
call_expiration_callback();
}
}

void platform_timer::stop() {
if(expired)
return;
struct itimerspec disable = {{0, 0}, {0, 0}};
timer_settime(my->timerid, 0, &disable, NULL);
expired = 1;
expired = true;
}

}}
}

0 comments on commit d0ea755

Please sign in to comment.