Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/envoy/event/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ class Timer {
virtual void enableTimer(const std::chrono::milliseconds& ms,
const ScopeTrackedObject* object = nullptr) PURE;

/**
* Enable a pending high resolution timeout. If a timeout is already pending, it will be reset to
* the new timeout.
*
* @param us supplies the duration of the alarm in microseconds.
* @param object supplies an optional scope for the duration of the alarm.
*/
virtual void enableHRTimer(const std::chrono::microseconds& us,
const ScopeTrackedObject* object = nullptr) PURE;
/**
* Return whether the timer is currently armed.
*/
Expand Down
9 changes: 7 additions & 2 deletions source/common/event/timer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace Envoy {
namespace Event {

void TimerUtils::millisecondsToTimeval(const std::chrono::milliseconds& d, timeval& tv) {
void TimerUtils::microsecondsToTimeval(const std::chrono::microseconds& d, timeval& tv) {
std::chrono::seconds secs = std::chrono::duration_cast<std::chrono::seconds>(d);
std::chrono::microseconds usecs = std::chrono::duration_cast<std::chrono::microseconds>(d - secs);

Expand Down Expand Up @@ -38,12 +38,17 @@ TimerImpl::TimerImpl(Libevent::BasePtr& libevent, TimerCb cb, Dispatcher& dispat
void TimerImpl::disableTimer() { event_del(&raw_event_); }

void TimerImpl::enableTimer(const std::chrono::milliseconds& d, const ScopeTrackedObject* object) {
enableHRTimer(d, object);
}

void TimerImpl::enableHRTimer(const std::chrono::microseconds& d,
const ScopeTrackedObject* object = nullptr) {
object_ = object;
if (d.count() == 0) {
event_active(&raw_event_, EV_TIMEOUT, 0);
} else {
timeval tv;
TimerUtils::millisecondsToTimeval(d, tv);
TimerUtils::microsecondsToTimeval(d, tv);
event_add(&raw_event_, &tv);
}
}
Expand Down
5 changes: 4 additions & 1 deletion source/common/event/timer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Event {
*/
class TimerUtils {
public:
static void millisecondsToTimeval(const std::chrono::milliseconds& d, timeval& tv);
static void microsecondsToTimeval(const std::chrono::microseconds& d, timeval& tv);
};

/**
Expand All @@ -29,6 +29,9 @@ class TimerImpl : public Timer, ImplBase {
// Timer
void disableTimer() override;
void enableTimer(const std::chrono::milliseconds& d, const ScopeTrackedObject* scope) override;
void enableHRTimer(const std::chrono::microseconds& us,
const ScopeTrackedObject* object) override;

bool enabled() override;

private:
Expand Down
70 changes: 39 additions & 31 deletions test/common/event/dispatcher_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,33 @@ class DispatcherImplTest : public testing::Test {
dispatcher_thread_->join();
}

void timerTest(std::function<void(Timer&)> enable_timer_delegate) {
TimerPtr timer;
dispatcher_->post([this, &timer]() {
{
Thread::LockGuard lock(mu_);
timer = dispatcher_->createTimer([this]() {
{
Thread::LockGuard lock(mu_);
work_finished_ = true;
}
cv_.notifyOne();
});
EXPECT_FALSE(timer->enabled());
}
cv_.notifyOne();
});

Thread::LockGuard lock(mu_);
while (timer == nullptr) {
cv_.wait(mu_);
}
enable_timer_delegate(*timer);
while (!work_finished_) {
cv_.wait(mu_);
}
}

NiceMock<Stats::MockStore> scope_; // Used in InitializeStats, must outlive dispatcher_->exit().
Api::ApiPtr api_;
Thread::ThreadPtr dispatcher_thread_;
Expand Down Expand Up @@ -158,31 +185,8 @@ TEST_F(DispatcherImplTest, RunPostCallbacksLocking) {
}

TEST_F(DispatcherImplTest, Timer) {
TimerPtr timer;
dispatcher_->post([this, &timer]() {
{
Thread::LockGuard lock(mu_);
timer = dispatcher_->createTimer([this]() {
{
Thread::LockGuard lock(mu_);
work_finished_ = true;
}
cv_.notifyOne();
});
EXPECT_FALSE(timer->enabled());
}
cv_.notifyOne();
});

Thread::LockGuard lock(mu_);
while (timer == nullptr) {
cv_.wait(mu_);
}
timer->enableTimer(std::chrono::milliseconds(50));

while (!work_finished_) {
cv_.wait(mu_);
}
timerTest([](Timer& timer) { timer.enableTimer(std::chrono::milliseconds(50)); });
timerTest([](Timer& timer) { timer.enableHRTimer(std::chrono::microseconds(50)); });
}

TEST_F(DispatcherImplTest, TimerWithScope) {
Expand Down Expand Up @@ -305,6 +309,10 @@ TEST(TimerImplTest, TimerEnabledDisabled) {
EXPECT_TRUE(timer->enabled());
dispatcher->run(Dispatcher::RunType::NonBlock);
EXPECT_FALSE(timer->enabled());
timer->enableHRTimer(std::chrono::milliseconds(0));
EXPECT_TRUE(timer->enabled());
dispatcher->run(Dispatcher::RunType::NonBlock);
EXPECT_FALSE(timer->enabled());
}

TEST(TimerImplTest, TimerValueConversion) {
Expand All @@ -313,21 +321,21 @@ TEST(TimerImplTest, TimerValueConversion) {

// Basic test with zero milliseconds.
msecs = std::chrono::milliseconds(0);
TimerUtils::millisecondsToTimeval(msecs, tv);
TimerUtils::microsecondsToTimeval(msecs, tv);
EXPECT_EQ(tv.tv_sec, 0);
EXPECT_EQ(tv.tv_usec, 0);

// 2050 milliseconds is 2 seconds and 50000 microseconds.
msecs = std::chrono::milliseconds(2050);
TimerUtils::millisecondsToTimeval(msecs, tv);
TimerUtils::microsecondsToTimeval(msecs, tv);
EXPECT_EQ(tv.tv_sec, 2);
EXPECT_EQ(tv.tv_usec, 50000);

// Check maximum value conversion.
msecs = std::chrono::milliseconds::duration::max();
TimerUtils::millisecondsToTimeval(msecs, tv);
EXPECT_EQ(tv.tv_sec, msecs.count() / 1000);
EXPECT_EQ(tv.tv_usec, (msecs.count() % tv.tv_sec) * 1000);
const auto usecs = std::chrono::microseconds::duration::max();
TimerUtils::microsecondsToTimeval(usecs, tv);
EXPECT_EQ(tv.tv_sec, usecs.count() / 1000000);
EXPECT_EQ(tv.tv_usec, usecs.count() % tv.tv_sec);
}

} // namespace
Expand Down
2 changes: 2 additions & 0 deletions test/mocks/event/mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ class MockTimer : public Timer {
MOCK_METHOD0(disableTimer, void());
MOCK_METHOD2(enableTimer,
void(const std::chrono::milliseconds&, const ScopeTrackedObject* scope));
MOCK_METHOD2(enableHRTimer,
void(const std::chrono::microseconds&, const ScopeTrackedObject* scope));
MOCK_METHOD0(enabled, bool());

MockDispatcher* dispatcher_{};
Expand Down
12 changes: 8 additions & 4 deletions test/test_common/simulated_time_system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ class SimulatedTimeSystemHelper::Alarm : public Timer {
// Timer
void disableTimer() override;
void enableTimer(const std::chrono::milliseconds& duration,
const ScopeTrackedObject* scope) override;
const ScopeTrackedObject* scope) override {
enableHRTimer(duration, scope);
};
void enableHRTimer(const std::chrono::microseconds& duration,
const ScopeTrackedObject* scope) override;
bool enabled() override {
Thread::LockGuard lock(time_system_.mutex_);
return armed_ || base_timer_->enabled();
Expand Down Expand Up @@ -177,8 +181,8 @@ void SimulatedTimeSystemHelper::Alarm::Alarm::disableTimerLockHeld() {
}
}

void SimulatedTimeSystemHelper::Alarm::Alarm::enableTimer(const std::chrono::milliseconds& duration,
const ScopeTrackedObject* scope) {
void SimulatedTimeSystemHelper::Alarm::Alarm::enableHRTimer(
const std::chrono::microseconds& duration, const ScopeTrackedObject* scope) {
Thread::LockGuard lock(time_system_.mutex_);
disableTimerLockHeld();
armed_ = true;
Expand Down Expand Up @@ -287,7 +291,7 @@ int64_t SimulatedTimeSystemHelper::nextIndex() {
}

void SimulatedTimeSystemHelper::addAlarmLockHeld(
Alarm* alarm, const std::chrono::milliseconds& duration) NO_THREAD_SAFETY_ANALYSIS {
Alarm* alarm, const std::chrono::microseconds& duration) NO_THREAD_SAFETY_ANALYSIS {
ASSERT(&(alarm->timeSystem()) == this);
alarm->setTimeLockHeld(monotonic_time_ + duration);
alarms_.insert(alarm);
Expand Down
2 changes: 1 addition & 1 deletion test/test_common/simulated_time_system.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class SimulatedTimeSystemHelper : public TestTimeSystem {
int64_t nextIndex();

// Adds/removes an alarm.
void addAlarmLockHeld(Alarm*, const std::chrono::milliseconds& duration)
void addAlarmLockHeld(Alarm*, const std::chrono::microseconds& duration)
EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void removeAlarmLockHeld(Alarm*) EXCLUSIVE_LOCKS_REQUIRED(mutex_);

Expand Down