tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

message_pump_libevent.h (9642B)


      1 // Copyright 2012 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
      6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
      7 
      8 #include <memory>
      9 #include <tuple>
     10 
     11 #include "base/base_export.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/memory/raw_ptr.h"
     14 #include "base/memory/raw_ptr_exclusion.h"
     15 #include "base/memory/weak_ptr.h"
     16 #include "base/message_loop/message_pump.h"
     17 #include "base/message_loop/message_pump_buildflags.h"
     18 #include "base/message_loop/watchable_io_message_pump_posix.h"
     19 #include "base/threading/thread_checker.h"
     20 #include "third_party/libevent/event.h"
     21 
     22 // Declare structs we need from libevent.h rather than including it
     23 struct event_base;
     24 struct event;
     25 namespace base {
     26 
     27 class MessagePumpEpoll;
     28 
     29 // Class to monitor sockets and issue callbacks when sockets are ready for I/O
     30 // TODO(dkegel): add support for background file IO somehow
     31 class BASE_EXPORT MessagePumpLibevent : public MessagePump,
     32                                        public WatchableIOMessagePumpPosix {
     33 public:
     34  class FdWatchController;
     35 
     36  // Parameters used to construct and describe an EpollInterest.
     37  struct EpollInterestParams {
     38    // The file descriptor of interest.
     39    int fd;
     40 
     41    // Indicates an interest in being able to read() from `fd`.
     42    bool read;
     43 
     44    // Indicates an interest in being able to write() to `fd`.
     45    bool write;
     46 
     47    // Indicates whether this interest is a one-shot interest, meaning that it
     48    // must be automatically deactivated every time it triggers an epoll event.
     49    bool one_shot;
     50 
     51    bool IsEqual(const EpollInterestParams& rhs) const {
     52      return std::tie(fd, read, write, one_shot) ==
     53             std::tie(rhs.fd, rhs.read, rhs.write, rhs.one_shot);
     54    }
     55  };
     56 
     57  // Represents a single controller's interest in a file descriptor via epoll,
     58  // and tracks whether that interest is currently active. Though an interest
     59  // persists as long as its controller is alive and hasn't changed interests,
     60  // it only participates in epoll waits while active. These objects are only
     61  // used when MessagePumpLibevent is configured to use the epoll API instead of
     62  // libevent.
     63  class EpollInterest : public RefCounted<EpollInterest> {
     64   public:
     65    EpollInterest(FdWatchController* controller,
     66                  const EpollInterestParams& params);
     67    EpollInterest(const EpollInterest&) = delete;
     68    EpollInterest& operator=(const EpollInterest&) = delete;
     69 
     70    FdWatchController* controller() { return controller_; }
     71    const EpollInterestParams& params() const { return params_; }
     72 
     73    bool active() const { return active_; }
     74    void set_active(bool active) { active_ = active; }
     75 
     76    // Only meaningful between WatchForControllerDestruction() and
     77    // StopWatchingForControllerDestruction().
     78    bool was_controller_destroyed() const { return was_controller_destroyed_; }
     79 
     80    void WatchForControllerDestruction() {
     81      DCHECK(!controller_->was_destroyed_);
     82      controller_->was_destroyed_ = &was_controller_destroyed_;
     83    }
     84 
     85    void StopWatchingForControllerDestruction() {
     86      if (!was_controller_destroyed_) {
     87        DCHECK_EQ(controller_->was_destroyed_, &was_controller_destroyed_);
     88        controller_->was_destroyed_ = nullptr;
     89      }
     90    }
     91 
     92   private:
     93    friend class RefCounted<EpollInterest>;
     94    ~EpollInterest();
     95 
     96    const raw_ptr<FdWatchController, AcrossTasksDanglingUntriaged> controller_;
     97    const EpollInterestParams params_;
     98    bool active_ = true;
     99    bool was_controller_destroyed_ = false;
    100  };
    101 
    102  // Note that this class is used as the FdWatchController for both
    103  // MessagePumpLibevent *and* MessagePumpEpoll in order to avoid unnecessary
    104  // code churn during experimentation and eventual transition. Consumers
    105  // construct their own FdWatchController instances, so switching this type
    106  // at runtime would require potentially complex logic changes to all
    107  // consumers.
    108  class FdWatchController : public FdWatchControllerInterface {
    109   public:
    110    explicit FdWatchController(const Location& from_here);
    111 
    112    FdWatchController(const FdWatchController&) = delete;
    113    FdWatchController& operator=(const FdWatchController&) = delete;
    114 
    115    // Implicitly calls StopWatchingFileDescriptor.
    116    ~FdWatchController() override;
    117 
    118    // FdWatchControllerInterface:
    119    bool StopWatchingFileDescriptor() override;
    120 
    121   private:
    122    friend class MessagePumpEpoll;
    123    friend class MessagePumpLibevent;
    124    friend class MessagePumpLibeventTest;
    125 
    126    // Common methods called by both pump implementations.
    127    void set_watcher(FdWatcher* watcher) { watcher_ = watcher; }
    128 
    129    // Methods called only by MessagePumpLibevent
    130    void set_libevent_pump(MessagePumpLibevent* pump) { libevent_pump_ = pump; }
    131    MessagePumpLibevent* libevent_pump() const { return libevent_pump_; }
    132 
    133    void Init(std::unique_ptr<event> e);
    134    std::unique_ptr<event> ReleaseEvent();
    135 
    136    void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
    137    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
    138 
    139    // Methods called only by MessagePumpEpoll
    140    void set_epoll_pump(WeakPtr<MessagePumpEpoll> pump) {
    141      epoll_pump_ = std::move(pump);
    142    }
    143    const scoped_refptr<EpollInterest>& epoll_interest() const {
    144      return epoll_interest_;
    145    }
    146 
    147    // Creates a new Interest described by `params` and adopts it as this
    148    // controller's exclusive interest. Any prior interest is dropped by the
    149    // controller and should be unregistered on the MessagePumpEpoll.
    150    const scoped_refptr<EpollInterest>& AssignEpollInterest(
    151        const EpollInterestParams& params);
    152 
    153    void OnFdReadable();
    154    void OnFdWritable();
    155 
    156    // Common state
    157    raw_ptr<FdWatcher> watcher_ = nullptr;
    158 
    159    // If this pointer is non-null when the FdWatchController is destroyed, the
    160    // pointee is set to true.
    161    raw_ptr<bool> was_destroyed_ = nullptr;
    162 
    163    // State used only with libevent
    164    std::unique_ptr<event> event_;
    165 
    166    // Tests (e.g. FdWatchControllerPosixTest) deliberately make this dangle.
    167    raw_ptr<MessagePumpLibevent, DisableDanglingPtrDetection> libevent_pump_ =
    168        nullptr;
    169 
    170    // State used only with epoll
    171    WeakPtr<MessagePumpEpoll> epoll_pump_;
    172    scoped_refptr<EpollInterest> epoll_interest_;
    173  };
    174 
    175  MessagePumpLibevent();
    176 
    177 #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
    178  // Constructs a MessagePumpLibevent which is forced to use epoll directly
    179  // instead of libevent.
    180  enum { kUseEpoll };
    181  explicit MessagePumpLibevent(decltype(kUseEpoll));
    182 #endif
    183 
    184  MessagePumpLibevent(const MessagePumpLibevent&) = delete;
    185  MessagePumpLibevent& operator=(const MessagePumpLibevent&) = delete;
    186 
    187  ~MessagePumpLibevent() override;
    188 
    189  // Must be called early in process startup, but after FeatureList
    190  // initialization. This allows MessagePumpLibevent to query and cache the
    191  // enabled state of any relevant features.
    192  static void InitializeFeatures();
    193 
    194  bool WatchFileDescriptor(int fd,
    195                           bool persistent,
    196                           int mode,
    197                           FdWatchController* controller,
    198                           FdWatcher* delegate);
    199 
    200  // MessagePump methods:
    201  void Run(Delegate* delegate) override;
    202  void Quit() override;
    203  void ScheduleWork() override;
    204  void ScheduleDelayedWork(
    205      const Delegate::NextWorkInfo& next_work_info) override;
    206 
    207 private:
    208  friend class MessagePumpLibeventTest;
    209 
    210  // Risky part of constructor.  Returns true on success.
    211  bool Init();
    212 
    213  // Called by libevent to tell us a registered FD can be read/written to.
    214  static void OnLibeventNotification(int fd, short flags, void* context);
    215 
    216  // Unix pipe used to implement ScheduleWork()
    217  // ... callback; called by libevent inside Run() when pipe is ready to read
    218  static void OnWakeup(int socket, short flags, void* context);
    219 
    220  struct RunState {
    221    explicit RunState(Delegate* delegate_in) : delegate(delegate_in) {}
    222 
    223    // `delegate` is not a raw_ptr<...> for performance reasons (based on
    224    // analysis of sampling profiler data and tab_search:top100:2020).
    225    RAW_PTR_EXCLUSION Delegate* const delegate;
    226 
    227    // Used to flag that the current Run() invocation should return ASAP.
    228    bool should_quit = false;
    229  };
    230 
    231 #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
    232  // If direct use of epoll is enabled, this is the MessagePumpEpoll instance
    233  // used. In that case, all libevent state below is ignored and unused.
    234  // Otherwise this is null.
    235  std::unique_ptr<MessagePumpEpoll> epoll_pump_;
    236 #endif
    237 
    238  // State for the current invocation of Run(). null if not running.
    239  // This field is not a raw_ptr<> because it was filtered by the rewriter for:
    240  // #addr-of
    241  RAW_PTR_EXCLUSION RunState* run_state_ = nullptr;
    242 
    243  // This flag is set if libevent has processed I/O events.
    244  bool processed_io_events_ = false;
    245 
    246  struct EventBaseFree {
    247    inline void operator()(event_base* e) const {
    248      if (e)
    249        event_base_free(e);
    250    }
    251  };
    252  // Libevent dispatcher.  Watches all sockets registered with it, and sends
    253  // readiness callbacks when a socket is ready for I/O.
    254  std::unique_ptr<event_base, EventBaseFree> event_base_{event_base_new()};
    255 
    256  // ... write end; ScheduleWork() writes a single byte to it
    257  int wakeup_pipe_in_ = -1;
    258  // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
    259  int wakeup_pipe_out_ = -1;
    260  // ... libevent wrapper for read end
    261  std::unique_ptr<event> wakeup_event_;
    262 
    263  ThreadChecker watch_file_descriptor_caller_checker_;
    264 };
    265 
    266 }  // namespace base
    267 
    268 #endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_