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
   * ENVOY_BUGs if the duration is negative.
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
8137081
  template <typename Duration> static void durationToTimeval(const Duration& d, timeval& tv) {
32
8137081
    if (d.count() < 0) {
33
1
      IS_ENVOY_BUG(fmt::format("Negative duration passed to durationToTimeval(): {}", d.count()));
34
1
      tv.tv_sec = 0;
35
1
      tv.tv_usec = 500000;
36
1
      return;
37
8137080
    };
38
8137080
    constexpr int64_t clip_to = INT32_MAX; // 136.102208 years
39
8137080
    auto secs = std::chrono::duration_cast<std::chrono::seconds>(d);
40
8137080
    if (secs.count() > clip_to) {
41
4
      tv.tv_sec = clip_to;
42
4
      tv.tv_usec = 0;
43
4
      return;
44
4
    }
45

            
46
8137076
    auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(d - secs);
47
8137076
    tv.tv_sec = secs.count();
48
8137076
    tv.tv_usec = usecs.count();
49
8137076
  }
50
};
51

            
52
/**
53
 * libevent implementation of Timer.
54
 */
55
class TimerImpl : public Timer, ImplBase {
56
public:
57
  TimerImpl(Libevent::BasePtr& libevent, TimerCb cb, Event::Dispatcher& dispatcher);
58

            
59
  // Timer
60
  void disableTimer() override;
61

            
62
  void enableTimer(std::chrono::milliseconds d, const ScopeTrackedObject* scope) override;
63
  void enableHRTimer(std::chrono::microseconds us, const ScopeTrackedObject* object) override;
64

            
65
  bool enabled() override;
66

            
67
private:
68
  void internalEnableTimer(const timeval& tv, const ScopeTrackedObject* scope);
69
  TimerCb cb_;
70
  Dispatcher& dispatcher_;
71
  // This has to be atomic for alarms which are handled out of thread, for
72
  // example if the DispatcherImpl::post is called by two threads, they race to
73
  // both set this to null.
74
  std::atomic<const ScopeTrackedObject*> object_{};
75
};
76

            
77
} // namespace Event
78
} // namespace Envoy