• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsEqualEpollInterestParams51     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 
controller()70     FdWatchController* controller() { return controller_; }
params()71     const EpollInterestParams& params() const { return params_; }
72 
active()73     bool active() const { return active_; }
set_active(bool active)74     void set_active(bool active) { active_ = active; }
75 
76     // Only meaningful between WatchForControllerDestruction() and
77     // StopWatchingForControllerDestruction().
was_controller_destroyed()78     bool was_controller_destroyed() const { return was_controller_destroyed_; }
79 
WatchForControllerDestruction()80     void WatchForControllerDestruction() {
81       DCHECK(!controller_->was_destroyed_);
82       controller_->was_destroyed_ = &was_controller_destroyed_;
83     }
84 
StopWatchingForControllerDestruction()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, DanglingUntriaged> 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.
set_watcher(FdWatcher * watcher)127     void set_watcher(FdWatcher* watcher) { watcher_ = watcher; }
128 
129     // Methods called only by MessagePumpLibevent
set_libevent_pump(MessagePumpLibevent * pump)130     void set_libevent_pump(MessagePumpLibevent* pump) { libevent_pump_ = pump; }
libevent_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
set_epoll_pump(WeakPtr<MessagePumpEpoll> pump)140     void set_epoll_pump(WeakPtr<MessagePumpEpoll> pump) {
141       epoll_pump_ = std::move(pump);
142     }
epoll_interest()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 {
RunStateRunState221     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 {
operatorEventBaseFree247     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_
269