1
#include "source/common/event/libevent_scheduler.h"
2

            
3
#include "source/common/common/assert.h"
4
#include "source/common/event/schedulable_cb_impl.h"
5
#include "source/common/event/timer_impl.h"
6

            
7
#include "event2/util.h"
8

            
9
namespace Envoy {
10
namespace Event {
11

            
12
namespace {
13
7453634
void recordTimeval(Stats::Histogram& histogram, const timeval& tv) {
14
7453634
  histogram.recordValue(tv.tv_sec * 1000000 + tv.tv_usec);
15
7453634
}
16
} // namespace
17

            
18
77715
LibeventScheduler::LibeventScheduler() {
19
#ifdef WIN32
20
  event_config* event_config = event_config_new();
21
  RELEASE_ASSERT(event_config != nullptr,
22
                 "Failed to initialize libevent event_base: event_config_new");
23
  // Request wepoll backend by avoiding win32 backend.
24
  int error = event_config_avoid_method(event_config, "win32");
25
  RELEASE_ASSERT(error == 0, "Failed to initialize libevent event_base: event_config_avoid_method");
26
  event_base* event_base = event_base_new_with_config(event_config);
27
  event_config_free(event_config);
28
#else
29
77715
  event_base* event_base = event_base_new();
30
77715
#endif
31
77715
  RELEASE_ASSERT(event_base != nullptr, "Failed to initialize libevent event_base");
32
77715
  libevent_ = Libevent::BasePtr(event_base);
33

            
34
  // The dispatcher won't work as expected if libevent hasn't been configured to use threads.
35
77715
  RELEASE_ASSERT(Libevent::Global::initialized(), "");
36
77715
}
37

            
38
386585
TimerPtr LibeventScheduler::createTimer(const TimerCb& cb, Dispatcher& dispatcher) {
39
386585
  return std::make_unique<TimerImpl>(libevent_, cb, dispatcher);
40
386585
};
41

            
42
SchedulableCallbackPtr
43
427221
LibeventScheduler::createSchedulableCallback(const std::function<void()>& cb) {
44
427221
  return std::make_unique<SchedulableCallbackImpl>(libevent_, cb);
45
427221
};
46

            
47
239044481
void LibeventScheduler::run(Dispatcher::RunType mode) {
48
239044481
  int flag = 0;
49
239044481
  switch (mode) {
50
238947995
  case Dispatcher::RunType::NonBlock:
51
238947995
    flag = LibeventScheduler::flagsBasedOnEventType();
52
238947995
    break;
53
74866
  case Dispatcher::RunType::Block:
54
    // The default flags have 'block' behavior. See
55
    // http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html
56
74866
    break;
57
21619
  case Dispatcher::RunType::RunUntilExit:
58
21619
    flag = EVLOOP_NO_EXIT_ON_EMPTY;
59
21619
    break;
60
239044481
  }
61
239044480
  event_base_loop(libevent_.get(), flag);
62
239044480
}
63

            
64
123309
void LibeventScheduler::loopExit() { event_base_loopexit(libevent_.get(), nullptr); }
65

            
66
6
void LibeventScheduler::registerOnPrepareCallback(OnPrepareCallback&& callback) {
67
6
  ASSERT(callback);
68
6
  ASSERT(!prepare_callback_);
69

            
70
6
  prepare_callback_ = std::move(callback);
71
6
  evwatch_prepare_new(libevent_.get(), &onPrepareForCallback, this);
72
6
}
73

            
74
77693
void LibeventScheduler::registerOnCheckCallback(OnCheckCallback&& callback) {
75
77693
  ASSERT(callback);
76
77693
  ASSERT(!check_callback_);
77

            
78
77693
  check_callback_ = std::move(callback);
79
77693
  evwatch_check_new(libevent_.get(), &onCheckForCallback, this);
80
77693
}
81

            
82
15
void LibeventScheduler::initializeStats(DispatcherStats* stats) {
83
15
  stats_ = stats;
84
  // These are thread safe.
85
15
  evwatch_prepare_new(libevent_.get(), &onPrepareForStats, this);
86
15
  evwatch_check_new(libevent_.get(), &onCheckForStats, this);
87
15
}
88

            
89
308
void LibeventScheduler::onPrepareForCallback(evwatch*, const evwatch_prepare_cb_info*, void* arg) {
90
  // `self` is `this`, passed in from evwatch_prepare_new.
91
308
  auto self = static_cast<LibeventScheduler*>(arg);
92
308
  self->prepare_callback_();
93
308
}
94

            
95
245892933
void LibeventScheduler::onCheckForCallback(evwatch*, const evwatch_check_cb_info*, void* arg) {
96
  // `self` is `this`, passed in from evwatch_prepare_new.
97
245892933
  auto self = static_cast<LibeventScheduler*>(arg);
98
245892933
  self->check_callback_();
99
245892933
}
100

            
101
void LibeventScheduler::onPrepareForStats(evwatch*, const evwatch_prepare_cb_info* info,
102
3727298
                                          void* arg) {
103
  // `self` is `this`, passed in from evwatch_prepare_new.
104
3727298
  auto self = static_cast<LibeventScheduler*>(arg);
105

            
106
  // Record poll timeout and prepare time for this iteration of the event loop. The timeout is the
107
  // expected polling duration, whereas the actual polling duration will be the difference measured
108
  // between the prepare time and the check time immediately after polling. These are compared in
109
  // onCheckForStats to compute the poll_delay stat.
110
3727298
  self->timeout_set_ = evwatch_prepare_get_timeout(info, &self->timeout_);
111
3727298
  evutil_gettimeofday(&self->prepare_time_, nullptr);
112

            
113
  // If we have a check time available from a previous iteration of the event loop (that is, all but
114
  // the first), compute the loop_duration stat.
115
3727298
  if (self->check_time_.tv_sec != 0) {
116
3727283
    timeval delta;
117
3727283
    evutil_timersub(&self->prepare_time_, &self->check_time_, &delta);
118
3727283
    recordTimeval(self->stats_->loop_duration_us_, delta);
119
3727283
  }
120
3727298
}
121

            
122
3727298
void LibeventScheduler::onCheckForStats(evwatch*, const evwatch_check_cb_info*, void* arg) {
123
  // `self` is `this`, passed in from evwatch_check_new.
124
3727298
  auto self = static_cast<LibeventScheduler*>(arg);
125

            
126
  // Record check time for this iteration of the event loop. Use this together with prepare time
127
  // from above to compute the actual polling duration, and store it for the next iteration of the
128
  // event loop to compute the loop duration.
129
3727298
  evutil_gettimeofday(&self->check_time_, nullptr);
130
3727298
  if (self->timeout_set_) {
131
3727298
    timeval delta, delay;
132
3727298
    evutil_timersub(&self->check_time_, &self->prepare_time_, &delta);
133
3727298
    evutil_timersub(&delta, &self->timeout_, &delay);
134

            
135
    // Delay can be negative, meaning polling completed early. This happens in normal operation,
136
    // either because I/O was ready before we hit the timeout, or just because the kernel was
137
    // feeling saucy. Disregard negative delays in stats, since they don't indicate anything
138
    // particularly useful.
139
3727298
    if (delay.tv_sec >= 0) {
140
3726351
      recordTimeval(self->stats_->poll_delay_us_, delay);
141
3726351
    }
142
3727298
  }
143
3727298
}
144

            
145
} // namespace Event
146
} // namespace Envoy