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