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

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include <functional>
       4             : 
       5             : #include "envoy/event/dispatcher.h"
       6             : #include "envoy/event/schedulable_cb.h"
       7             : #include "envoy/event/timer.h"
       8             : 
       9             : #include "source/common/event/libevent.h"
      10             : 
      11             : #include "event2/event.h"
      12             : #include "event2/watch.h"
      13             : 
      14             : namespace Envoy {
      15             : namespace Event {
      16             : 
      17             : // Implements Scheduler based on libevent.
      18             : //
      19             : // Here is a rough summary of operations that libevent performs in each event loop iteration, in
      20             : // order. Note that the invocation order for "same-iteration" operations that execute as a group
      21             : // can be surprising and invocation order of expired timers is non-deterministic.
      22             : // Whenever possible, it is preferable to avoid making event invocation ordering assumptions.
      23             : //
      24             : // 1. Calculate the poll timeout by comparing the current time to the deadline of the closest
      25             : // timer (the one at head of the priority queue).
      26             : // 2. Run registered "prepare" callbacks.
      27             : // 3. Poll for fd events using the closest timer as timeout, add active fds to the work list.
      28             : // 4. Run registered "check" callbacks.
      29             : // 5. Check timer deadlines against current time and move expired timers from the timer priority
      30             : // queue to the work list. Expired timers are moved to the work list is a non-deterministic order.
      31             : // 6. Execute items in the work list until the list is empty. Note that additional work
      32             : // items could be added to the work list during execution of this step, more details below.
      33             : // 7. Goto 1 if the loop termination condition has not been reached
      34             : //
      35             : // The following "same-iteration" work items are added directly to the work list when they are
      36             : // scheduled so they execute in the current iteration of the event loop. Note that there are no
      37             : // ordering guarantees when mixing the mechanisms below. Specifically, it is unsafe to assume that
      38             : // calling post followed by deferredDelete will result in the post callback being invoked before the
      39             : // deferredDelete; deferredDelete will run first if there is a pending deferredDeletion at the time
      40             : // the post callback is scheduled because deferredDelete invocation is grouped.
      41             : // - Event::Dispatcher::post(cb). Post callbacks are invoked as a group.
      42             : // - Event::Dispatcher::deferredDelete(object) and Event::DeferredTaskUtil::deferredRun(...).
      43             : // The same mechanism implements both of these operations, so they are invoked as a group.
      44             : // - Event::SchedulableCallback::scheduleCallbackCurrentIteration(). Each of these callbacks is
      45             : // scheduled and invoked independently.
      46             : //
      47             : // Event::FileEvent::activate and Event::SchedulableCallback::scheduleCallbackNextIteration are
      48             : // implemented as libevent timers with a deadline of 0. Both of these actions are moved to the work
      49             : // list while checking for expired timers during step 5.
      50             : //
      51             : // Events execute in the following order, derived from the order in which items were added to the
      52             : // work list:
      53             : // 0. Events added via event_active prior to the start of the event loop (in tests)
      54             : // 1. Fd events
      55             : // 2. Timers, FileEvent::activate and SchedulableCallback::scheduleCallbackNextIteration
      56             : // 3. "Same-iteration" work items described above, including Event::Dispatcher::post callbacks
      57             : class LibeventScheduler : public Scheduler, public CallbackScheduler {
      58             : public:
      59             :   using OnPrepareCallback = std::function<void()>;
      60             :   LibeventScheduler();
      61             : 
      62             :   // Scheduler
      63             :   TimerPtr createTimer(const TimerCb& cb, Dispatcher& dispatcher) override;
      64             :   SchedulableCallbackPtr createSchedulableCallback(const std::function<void()>& cb) override;
      65             : 
      66             :   /**
      67             :    * Runs the event loop.
      68             :    *
      69             :    * @param mode The mode in which to run the event loop.
      70             :    */
      71             :   void run(Dispatcher::RunType mode);
      72             : 
      73             :   /**
      74             :    * Exits the libevent loop.
      75             :    */
      76             :   void loopExit();
      77             : 
      78             :   /**
      79             :    * TODO(jmarantz): consider strengthening this abstraction and instead of
      80             :    * exposing the libevent base pointer, provide API abstractions for the calls
      81             :    * into it. Among other benefits this might make it more tractable to someday
      82             :    * consider an alternative to libevent if the need arises.
      83             :    *
      84             :    * @return the underlying libevent structure.
      85             :    */
      86        3803 :   event_base& base() { return *libevent_; }
      87             : 
      88             :   /**
      89             :    * Register callback to be called in the event loop prior to polling for
      90             :    * events. Must not be called more than once. |callback| must not be null.
      91             :    * |callback| cannot be unregistered, therefore it has to be valid throughout
      92             :    * the lifetime of |this|.
      93             :    */
      94             :   void registerOnPrepareCallback(OnPrepareCallback&& callback);
      95             : 
      96             :   /**
      97             :    * Start writing stats once thread-local storage is ready to receive them (see
      98             :    * ThreadLocalStoreImpl::initializeThreading).
      99             :    */
     100             :   void initializeStats(DispatcherStats* stats);
     101             : 
     102             : private:
     103             :   static void onPrepareForCallback(evwatch*, const evwatch_prepare_cb_info* info, void* arg);
     104             :   static void onPrepareForStats(evwatch*, const evwatch_prepare_cb_info* info, void* arg);
     105             :   static void onCheckForStats(evwatch*, const evwatch_check_cb_info*, void* arg);
     106             : 
     107       17249 :   static constexpr int flagsBasedOnEventType() {
     108       17249 :     if constexpr (Event::PlatformDefaultTriggerType == FileTriggerType::Level) {
     109             :       // With level events, EVLOOP_NONBLOCK will cause the libevent event_base_loop to run
     110             :       // forever. This is because the write event callbacks will trigger every time through the
     111             :       // loop. Adding EVLOOP_ONCE ensures the loop will run at most once
     112           0 :       return EVLOOP_NONBLOCK | EVLOOP_ONCE;
     113           0 :     }
     114       17249 :     return EVLOOP_NONBLOCK;
     115       17249 :   }
     116             : 
     117             :   Libevent::BasePtr libevent_;
     118             :   DispatcherStats* stats_{}; // stats owned by the containing DispatcherImpl
     119             :   bool timeout_set_{};       // whether there is a poll timeout in the current event loop iteration
     120             :   timeval timeout_{};        // the poll timeout for the current event loop iteration, if available
     121             :   timeval prepare_time_{};   // timestamp immediately before polling
     122             :   timeval check_time_{};     // timestamp immediately after polling
     123             :   OnPrepareCallback callback_; // callback to be called from onPrepareForCallback()
     124             : };
     125             : 
     126             : } // namespace Event
     127             : } // namespace Envoy

Generated by: LCOV version 1.15