LCOV - code coverage report
Current view: top level - source/common/event - libevent_scheduler.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 67 67 100.0 %
Date: 2024-01-05 06:35:25 Functions: 11 11 100.0 %

          Line data    Source code
       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           4 : void recordTimeval(Stats::Histogram& histogram, const timeval& tv) {
      14           4 :   histogram.recordValue(tv.tv_sec * 1000000 + tv.tv_usec);
      15           4 : }
      16             : } // namespace
      17             : 
      18        1498 : 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        1498 :   event_base* event_base = event_base_new();
      30        1498 : #endif
      31        1498 :   RELEASE_ASSERT(event_base != nullptr, "Failed to initialize libevent event_base");
      32        1498 :   libevent_ = Libevent::BasePtr(event_base);
      33             : 
      34             :   // The dispatcher won't work as expected if libevent hasn't been configured to use threads.
      35        1498 :   RELEASE_ASSERT(Libevent::Global::initialized(), "");
      36        1498 : }
      37             : 
      38       11384 : TimerPtr LibeventScheduler::createTimer(const TimerCb& cb, Dispatcher& dispatcher) {
      39       11384 :   return std::make_unique<TimerImpl>(libevent_, cb, dispatcher);
      40       11384 : };
      41             : 
      42             : SchedulableCallbackPtr
      43        8329 : LibeventScheduler::createSchedulableCallback(const std::function<void()>& cb) {
      44        8329 :   return std::make_unique<SchedulableCallbackImpl>(libevent_, cb);
      45        8329 : };
      46             : 
      47       18604 : void LibeventScheduler::run(Dispatcher::RunType mode) {
      48       18604 :   int flag = 0;
      49       18604 :   switch (mode) {
      50       17249 :   case Dispatcher::RunType::NonBlock:
      51       17249 :     flag = LibeventScheduler::flagsBasedOnEventType();
      52       18382 :   case Dispatcher::RunType::Block:
      53             :     // The default flags have 'block' behavior. See
      54             :     // http://www.wangafu.net/~nickm/libevent-book/Ref3_eventloop.html
      55       18382 :     break;
      56         222 :   case Dispatcher::RunType::RunUntilExit:
      57         222 :     flag = EVLOOP_NO_EXIT_ON_EMPTY;
      58         222 :     break;
      59       18604 :   }
      60       18604 :   event_base_loop(libevent_.get(), flag);
      61       18604 : }
      62             : 
      63        1633 : void LibeventScheduler::loopExit() { event_base_loopexit(libevent_.get(), nullptr); }
      64             : 
      65        1498 : void LibeventScheduler::registerOnPrepareCallback(OnPrepareCallback&& callback) {
      66        1498 :   ASSERT(callback);
      67        1498 :   ASSERT(!callback_);
      68             : 
      69        1498 :   callback_ = std::move(callback);
      70        1498 :   evwatch_prepare_new(libevent_.get(), &onPrepareForCallback, this);
      71        1498 : }
      72             : 
      73           2 : void LibeventScheduler::initializeStats(DispatcherStats* stats) {
      74           2 :   stats_ = stats;
      75             :   // These are thread safe.
      76           2 :   evwatch_prepare_new(libevent_.get(), &onPrepareForStats, this);
      77           2 :   evwatch_check_new(libevent_.get(), &onCheckForStats, this);
      78           2 : }
      79             : 
      80       28616 : void LibeventScheduler::onPrepareForCallback(evwatch*, const evwatch_prepare_cb_info*, void* arg) {
      81             :   // `self` is `this`, passed in from evwatch_prepare_new.
      82       28616 :   auto self = static_cast<LibeventScheduler*>(arg);
      83       28616 :   self->callback_();
      84       28616 : }
      85             : 
      86             : void LibeventScheduler::onPrepareForStats(evwatch*, const evwatch_prepare_cb_info* info,
      87           3 :                                           void* arg) {
      88             :   // `self` is `this`, passed in from evwatch_prepare_new.
      89           3 :   auto self = static_cast<LibeventScheduler*>(arg);
      90             : 
      91             :   // Record poll timeout and prepare time for this iteration of the event loop. The timeout is the
      92             :   // expected polling duration, whereas the actual polling duration will be the difference measured
      93             :   // between the prepare time and the check time immediately after polling. These are compared in
      94             :   // onCheckForStats to compute the poll_delay stat.
      95           3 :   self->timeout_set_ = evwatch_prepare_get_timeout(info, &self->timeout_);
      96           3 :   evutil_gettimeofday(&self->prepare_time_, nullptr);
      97             : 
      98             :   // If we have a check time available from a previous iteration of the event loop (that is, all but
      99             :   // the first), compute the loop_duration stat.
     100           3 :   if (self->check_time_.tv_sec != 0) {
     101           1 :     timeval delta;
     102           1 :     evutil_timersub(&self->prepare_time_, &self->check_time_, &delta);
     103           1 :     recordTimeval(self->stats_->loop_duration_us_, delta);
     104           1 :   }
     105           3 : }
     106             : 
     107           3 : void LibeventScheduler::onCheckForStats(evwatch*, const evwatch_check_cb_info*, void* arg) {
     108             :   // `self` is `this`, passed in from evwatch_check_new.
     109           3 :   auto self = static_cast<LibeventScheduler*>(arg);
     110             : 
     111             :   // Record check time for this iteration of the event loop. Use this together with prepare time
     112             :   // from above to compute the actual polling duration, and store it for the next iteration of the
     113             :   // event loop to compute the loop duration.
     114           3 :   evutil_gettimeofday(&self->check_time_, nullptr);
     115           3 :   if (self->timeout_set_) {
     116           3 :     timeval delta, delay;
     117           3 :     evutil_timersub(&self->check_time_, &self->prepare_time_, &delta);
     118           3 :     evutil_timersub(&delta, &self->timeout_, &delay);
     119             : 
     120             :     // Delay can be negative, meaning polling completed early. This happens in normal operation,
     121             :     // either because I/O was ready before we hit the timeout, or just because the kernel was
     122             :     // feeling saucy. Disregard negative delays in stats, since they don't indicate anything
     123             :     // particularly useful.
     124           3 :     if (delay.tv_sec >= 0) {
     125           3 :       recordTimeval(self->stats_->poll_delay_us_, delay);
     126           3 :     }
     127           3 :   }
     128           3 : }
     129             : 
     130             : } // namespace Event
     131             : } // namespace Envoy

Generated by: LCOV version 1.15