-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix interrupt transaction race condition #1107
base: main
Are you sure you want to change the base?
Changes from 6 commits
c9d4276
1a2a0c9
11f1e9a
8ad83f2
1a50b7b
0f4fbb4
d072fcd
848f90e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,9 +39,10 @@ void compute_and_print_timer_accuracy(platform_timer& timer) { | |
for(unsigned int i = 0; i < loops; ++i) { | ||
auto start = std::chrono::high_resolution_clock::now(); | ||
timer.start(fc::time_point(fc::time_point::now().time_since_epoch() + fc::microseconds(interval))); | ||
while(!timer.expired) {} | ||
while(timer.timer_state() == platform_timer::state_t::running) {} | ||
auto end = std::chrono::high_resolution_clock::now(); | ||
int timer_slop = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() - interval; | ||
timer.stop(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not seeing why this added line is necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added it because I originally added an assert that start() only called when timer is stopped. However, we don't actually honor that constraint currently elsewhere. Seems like it is better to honor that constraint normally. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decided it best to fix the invariant that |
||
|
||
//since more samples are run for the shorter expirations, weigh the longer expirations accordingly. This | ||
//helps to make a few results more fair. Two such examples: AWS c4&i5 xen instances being rather stable | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,36 +57,43 @@ platform_timer::~platform_timer() { | |
|
||
void platform_timer::start(fc::time_point tp) { | ||
if(tp == fc::time_point::maximum()) { | ||
expired = false; | ||
_state = state_t::running; | ||
return; | ||
} | ||
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch(); | ||
if(x.count() <= 0) | ||
expired = true; | ||
_state = state_t::timed_out; | ||
else { | ||
expired = false; | ||
_state = state_t::running; | ||
my->timer->expires_after(std::chrono::microseconds(x.count())); | ||
my->timer->async_wait([this](const boost::system::error_code& ec) { | ||
if(ec) | ||
return; | ||
expire_now(); | ||
_expire_now(); | ||
}); | ||
} | ||
} | ||
|
||
void platform_timer::expire_now() { | ||
bool expected = false; | ||
if (expired.compare_exchange_strong(expected, true)) { | ||
void platform_timer::_expire_now() { | ||
state_t expected = state_t::running; | ||
if (_state.compare_exchange_strong(expected, state_t::timed_out)) { | ||
call_expiration_callback(); | ||
} | ||
} | ||
|
||
void platform_timer::interrupt_timer() { | ||
state_t expected = state_t::running; | ||
if (_state.compare_exchange_strong(expected, state_t::interrupted)) { | ||
Comment on lines
+78
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't these call Isn't it possible that someone calls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We would need to add a mutex around the timer to do that. I think the intention is that stop() should be called before calling start() again. |
||
call_expiration_callback(); | ||
} | ||
} | ||
|
||
void platform_timer::stop() { | ||
if(expired) | ||
if(_state == state_t::stopped) | ||
return; | ||
|
||
my->timer->cancel(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't it make sense to call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This now needs to set to stopped, so the assert on start() is not triggered. |
||
expired = true; | ||
_state = state_t::stopped; | ||
} | ||
|
||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be made private then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not without some friends and with the multiple impls that becomes rather a pain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of the impls are the same
platform_timer
struct though, not separate classes. And even_state
is already private.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm a bit surprised that worked.