Line data Source code
1 : #pragma once 2 : 3 : #include <chrono> 4 : 5 : #include "envoy/event/timer.h" 6 : 7 : #include "source/common/common/scope_tracker.h" 8 : #include "source/common/common/utility.h" 9 : #include "source/common/event/event_impl_base.h" 10 : #include "source/common/event/libevent.h" 11 : 12 : namespace Envoy { 13 : namespace Event { 14 : 15 : /** 16 : * Utility helper functions for Timer implementation. 17 : */ 18 : class TimerUtils { 19 : public: 20 : /** 21 : * Intended for consumption by enable(HR)Timer, this method is templated method to avoid implicit 22 : * duration conversions for its input arguments. This lets us have an opportunity to check bounds 23 : * before doing any conversions. When the passed in duration exceeds INT32_MAX max seconds, the 24 : * output will be clipped to yield INT32_MAX seconds and 0 microseconds for the 25 : * output argument. We clip to INT32_MAX to guard against overflowing the timeval structure. 26 : * Throws an EnvoyException on negative duration input. 27 : * @tparam Duration std::chrono duration type, e.g. seconds, milliseconds, ... 28 : * @param d duration value 29 : * @param tv output parameter that will be updated 30 : */ 31 9270 : template <typename Duration> static void durationToTimeval(const Duration& d, timeval& tv) { 32 9270 : if (d.count() < 0) { 33 0 : ExceptionUtil::throwEnvoyException( 34 0 : fmt::format("Negative duration passed to durationToTimeval(): {}", d.count())); 35 0 : }; 36 9270 : constexpr int64_t clip_to = INT32_MAX; // 136.102208 years 37 9270 : auto secs = std::chrono::duration_cast<std::chrono::seconds>(d); 38 9270 : if (secs.count() > clip_to) { 39 0 : tv.tv_sec = clip_to; 40 0 : tv.tv_usec = 0; 41 0 : return; 42 0 : } 43 : 44 9270 : auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(d - secs); 45 9270 : tv.tv_sec = secs.count(); 46 9270 : tv.tv_usec = usecs.count(); 47 9270 : } 48 : }; 49 : 50 : /** 51 : * libevent implementation of Timer. 52 : */ 53 : class TimerImpl : public Timer, ImplBase { 54 : public: 55 : TimerImpl(Libevent::BasePtr& libevent, TimerCb cb, Event::Dispatcher& dispatcher); 56 : 57 : // Timer 58 : void disableTimer() override; 59 : 60 : void enableTimer(std::chrono::milliseconds d, const ScopeTrackedObject* scope) override; 61 : void enableHRTimer(std::chrono::microseconds us, const ScopeTrackedObject* object) override; 62 : 63 : bool enabled() override; 64 : 65 : private: 66 : void internalEnableTimer(const timeval& tv, const ScopeTrackedObject* scope); 67 : TimerCb cb_; 68 : Dispatcher& dispatcher_; 69 : // This has to be atomic for alarms which are handled out of thread, for 70 : // example if the DispatcherImpl::post is called by two threads, they race to 71 : // both set this to null. 72 : std::atomic<const ScopeTrackedObject*> object_{}; 73 : }; 74 : 75 : } // namespace Event 76 : } // namespace Envoy