123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
- #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
- #include <memory>
- #include <tuple>
- #include "base/base_export.h"
- #include "base/compiler_specific.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/message_loop/message_pump.h"
- #include "base/message_loop/message_pump_buildflags.h"
- #include "base/message_loop/watchable_io_message_pump_posix.h"
- #include "base/threading/thread_checker.h"
- #include "third_party/libevent/event.h"
- // Declare structs we need from libevent.h rather than including it
- struct event_base;
- struct event;
- namespace base {
- class MessagePumpEpoll;
- // Class to monitor sockets and issue callbacks when sockets are ready for I/O
- // TODO(dkegel): add support for background file IO somehow
- class BASE_EXPORT MessagePumpLibevent : public MessagePump,
- public WatchableIOMessagePumpPosix {
- public:
- class FdWatchController;
- // Parameters used to construct and describe an EpollInterest.
- struct EpollInterestParams {
- // The file descriptor of interest.
- int fd;
- // Indicates an interest in being able to read() from `fd`.
- bool read;
- // Indicates an interest in being able to write() to `fd`.
- bool write;
- // Indicates whether this interest is a one-shot interest, meaning that it
- // must be automatically deactivated every time it triggers an epoll event.
- bool one_shot;
- bool IsEqual(const EpollInterestParams& rhs) const {
- return std::tie(fd, read, write, one_shot) ==
- std::tie(rhs.fd, rhs.read, rhs.write, rhs.one_shot);
- }
- };
- // Represents a single controller's interest in a file descriptor via epoll,
- // and tracks whether that interest is currently active. Though an interest
- // persists as long as its controller is alive and hasn't changed interests,
- // it only participates in epoll waits while active. These objects are only
- // used when MessagePumpLibevent is configured to use the epoll API instead of
- // libevent.
- class EpollInterest : public RefCounted<EpollInterest> {
- public:
- EpollInterest(FdWatchController* controller,
- const EpollInterestParams& params);
- EpollInterest(const EpollInterest&) = delete;
- EpollInterest& operator=(const EpollInterest&) = delete;
- FdWatchController* controller() { return controller_; }
- const EpollInterestParams& params() const { return params_; }
- bool active() const { return active_; }
- void set_active(bool active) { active_ = active; }
- private:
- friend class RefCounted<EpollInterest>;
- ~EpollInterest();
- FdWatchController* const controller_;
- const EpollInterestParams params_;
- bool active_ = true;
- };
- // Note that this class is used as the FdWatchController for both
- // MessagePumpLibevent *and* MessagePumpEpoll in order to avoid unnecessary
- // code churn during experimentation and eventual transition. Consumers
- // construct their own FdWatchController instances, so switching this type
- // at runtime would require potentially complex logic changes to all
- // consumers.
- class FdWatchController : public FdWatchControllerInterface {
- public:
- explicit FdWatchController(const Location& from_here);
- FdWatchController(const FdWatchController&) = delete;
- FdWatchController& operator=(const FdWatchController&) = delete;
- // Implicitly calls StopWatchingFileDescriptor.
- ~FdWatchController() override;
- // FdWatchControllerInterface:
- bool StopWatchingFileDescriptor() override;
- private:
- friend class MessagePumpEpoll;
- friend class MessagePumpLibevent;
- friend class MessagePumpLibeventTest;
- // Common methods called by both pump implementations.
- void set_watcher(FdWatcher* watcher) { watcher_ = watcher; }
- // Methods called only by MessagePumpLibevent
- void set_libevent_pump(MessagePumpLibevent* pump) { libevent_pump_ = pump; }
- MessagePumpLibevent* libevent_pump() const { return libevent_pump_; }
- void Init(std::unique_ptr<event> e);
- std::unique_ptr<event> ReleaseEvent();
- void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
- void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
- // Methods called only by MessagePumpEpoll
- void set_epoll_pump(WeakPtr<MessagePumpEpoll> pump) {
- epoll_pump_ = std::move(pump);
- }
- const scoped_refptr<EpollInterest>& epoll_interest() const {
- return epoll_interest_;
- }
- // Creates a new Interest described by `params` and adopts it as this
- // controller's exclusive interest. Any prior interest is dropped by the
- // controller and should be unregistered on the MessagePumpEpoll.
- const scoped_refptr<EpollInterest>& AssignEpollInterest(
- const EpollInterestParams& params);
- void OnFdReadable();
- void OnFdWritable();
- // Common state
- raw_ptr<FdWatcher> watcher_ = nullptr;
- // If this pointer is non-null when the FdWatchController is destroyed, the
- // pointee is set to true.
- raw_ptr<bool> was_destroyed_ = nullptr;
- // State used only with libevent
- std::unique_ptr<event> event_;
- raw_ptr<MessagePumpLibevent> libevent_pump_ = nullptr;
- // State used only with epoll
- WeakPtr<MessagePumpEpoll> epoll_pump_;
- scoped_refptr<EpollInterest> epoll_interest_;
- };
- MessagePumpLibevent();
- #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
- // Constructs a MessagePumpLibevent which is forced to use epoll directly
- // instead of libevent.
- enum { kUseEpoll };
- explicit MessagePumpLibevent(decltype(kUseEpoll));
- #endif
- MessagePumpLibevent(const MessagePumpLibevent&) = delete;
- MessagePumpLibevent& operator=(const MessagePumpLibevent&) = delete;
- ~MessagePumpLibevent() override;
- // Must be called early in process startup, but after FeatureList
- // initialization. This allows MessagePumpLibevent to query and cache the
- // enabled state of any relevant features.
- static void InitializeFeatures();
- bool WatchFileDescriptor(int fd,
- bool persistent,
- int mode,
- FdWatchController* controller,
- FdWatcher* delegate);
- // MessagePump methods:
- void Run(Delegate* delegate) override;
- void Quit() override;
- void ScheduleWork() override;
- void ScheduleDelayedWork(
- const Delegate::NextWorkInfo& next_work_info) override;
- private:
- friend class MessagePumpLibeventTest;
- // Risky part of constructor. Returns true on success.
- bool Init();
- // Called by libevent to tell us a registered FD can be read/written to.
- static void OnLibeventNotification(int fd, short flags, void* context);
- // Unix pipe used to implement ScheduleWork()
- // ... callback; called by libevent inside Run() when pipe is ready to read
- static void OnWakeup(int socket, short flags, void* context);
- struct RunState {
- explicit RunState(Delegate* delegate_in) : delegate(delegate_in) {}
- // `delegate` is not a raw_ptr<...> for performance reasons (based on
- // analysis of sampling profiler data and tab_search:top100:2020).
- RAW_PTR_EXCLUSION Delegate* const delegate;
- // Used to flag that the current Run() invocation should return ASAP.
- bool should_quit = false;
- };
- #if BUILDFLAG(ENABLE_MESSAGE_PUMP_EPOLL)
- // If direct use of epoll is enabled, this is the MessagePumpEpoll instance
- // used. In that case, all libevent state below is ignored and unused.
- // Otherwise this is null.
- std::unique_ptr<MessagePumpEpoll> epoll_pump_;
- #endif
- // State for the current invocation of Run(). null if not running.
- RunState* run_state_ = nullptr;
- // This flag is set if libevent has processed I/O events.
- bool processed_io_events_ = false;
- struct EventBaseFree {
- inline void operator()(event_base* e) const {
- if (e)
- event_base_free(e);
- }
- };
- // Libevent dispatcher. Watches all sockets registered with it, and sends
- // readiness callbacks when a socket is ready for I/O.
- std::unique_ptr<event_base, EventBaseFree> event_base_{event_base_new()};
- // ... write end; ScheduleWork() writes a single byte to it
- int wakeup_pipe_in_ = -1;
- // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
- int wakeup_pipe_out_ = -1;
- // ... libevent wrapper for read end
- std::unique_ptr<event> wakeup_event_;
- ThreadChecker watch_file_descriptor_caller_checker_;
- };
- } // namespace base
- #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
|