1 // Copyright 2019 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_KQUEUE_H_ 6 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_KQUEUE_H_ 7 8 #include <mach/mach.h> 9 #include <stdint.h> 10 #include <sys/event.h> 11 12 #include <vector> 13 14 #include "base/apple/scoped_mach_port.h" 15 #include "base/containers/id_map.h" 16 #include "base/files/scoped_file.h" 17 #include "base/location.h" 18 #include "base/memory/raw_ptr.h" 19 #include "base/memory/weak_ptr.h" 20 #include "base/message_loop/message_pump.h" 21 #include "base/message_loop/watchable_io_message_pump_posix.h" 22 23 namespace base { 24 25 // MessagePumpKqueue is used on macOS to drive an IO MessageLoop that is 26 // capable of watching both POSIX file descriptors and Mach ports. 27 class BASE_EXPORT MessagePumpKqueue : public MessagePump, 28 public WatchableIOMessagePumpPosix { 29 public: 30 class FdWatchController : public FdWatchControllerInterface { 31 public: 32 explicit FdWatchController(const Location& from_here); 33 34 FdWatchController(const FdWatchController&) = delete; 35 FdWatchController& operator=(const FdWatchController&) = delete; 36 37 ~FdWatchController() override; 38 39 // FdWatchControllerInterface: 40 bool StopWatchingFileDescriptor() override; 41 42 protected: 43 friend class MessagePumpKqueue; 44 45 void Init(WeakPtr<MessagePumpKqueue> pump, 46 int fd, 47 int mode, 48 FdWatcher* watcher); 49 void Reset(); 50 fd()51 int fd() { return fd_; } mode()52 int mode() { return mode_; } watcher()53 FdWatcher* watcher() { return watcher_; } 54 55 private: 56 int fd_ = -1; 57 int mode_ = 0; 58 raw_ptr<FdWatcher> watcher_ = nullptr; 59 WeakPtr<MessagePumpKqueue> pump_; 60 }; 61 62 // Delegate interface that provides notifications of Mach message receive 63 // events. 64 class MachPortWatcher { 65 public: ~MachPortWatcher()66 virtual ~MachPortWatcher() {} 67 virtual void OnMachMessageReceived(mach_port_t port) = 0; 68 }; 69 70 // Controller interface that is used to stop receiving events for an 71 // installed MachPortWatcher. 72 class MachPortWatchController { 73 public: 74 explicit MachPortWatchController(const Location& from_here); 75 76 MachPortWatchController(const MachPortWatchController&) = delete; 77 MachPortWatchController& operator=(const MachPortWatchController&) = delete; 78 79 ~MachPortWatchController(); 80 81 bool StopWatchingMachPort(); 82 83 protected: 84 friend class MessagePumpKqueue; 85 86 void Init(WeakPtr<MessagePumpKqueue> pump, 87 mach_port_t port, 88 MachPortWatcher* watcher); 89 void Reset(); 90 port()91 mach_port_t port() { return port_; } watcher()92 MachPortWatcher* watcher() { return watcher_; } 93 94 private: 95 mach_port_t port_ = MACH_PORT_NULL; 96 raw_ptr<MachPortWatcher> watcher_ = nullptr; 97 WeakPtr<MessagePumpKqueue> pump_; 98 const Location from_here_; 99 }; 100 101 MessagePumpKqueue(); 102 103 MessagePumpKqueue(const MessagePumpKqueue&) = delete; 104 MessagePumpKqueue& operator=(const MessagePumpKqueue&) = delete; 105 106 ~MessagePumpKqueue() override; 107 108 // Initializes features for this class. See `base::features::Init()`. 109 static void InitializeFeatures(); 110 111 // MessagePump: 112 void Run(Delegate* delegate) override; 113 // Simplified version of the loop used under experiment (crbug.com/1200141) 114 void RunSimplified(Delegate* delegate); 115 void Quit() override; 116 void ScheduleWork() override; 117 void ScheduleDelayedWork( 118 const Delegate::NextWorkInfo& next_work_info) override; 119 TimeTicks AdjustDelayedRunTime(TimeTicks earliest_time, 120 TimeTicks run_time, 121 TimeTicks latest_time) override; 122 123 // Begins watching the Mach receive right named by |port|. The |controller| 124 // can be used to stop watching for incoming messages, and new message 125 // notifications are delivered to the |delegate|. Returns true if the watch 126 // was successfully set-up and false on error. 127 bool WatchMachReceivePort(mach_port_t port, 128 MachPortWatchController* controller, 129 MachPortWatcher* delegate); 130 131 // WatchableIOMessagePumpPosix: 132 bool WatchFileDescriptor(int fd, 133 bool persistent, 134 int mode, 135 FdWatchController* controller, 136 FdWatcher* delegate); 137 138 private: 139 // Called by the watch controller implementations to stop watching the 140 // respective types of handles. 141 bool StopWatchingMachPort(MachPortWatchController* controller); 142 bool StopWatchingFileDescriptor(FdWatchController* controller); 143 144 // Checks the |kqueue_| for events. If |next_work_info| is null, then the 145 // kqueue will be polled for events. If it is non-null, it will wait for the 146 // amount of time specified by the NextWorkInfo or until an event is 147 // triggered. Returns whether any events were dispatched, with the events 148 // stored in |events_|. 149 bool DoInternalWork(Delegate* delegate, 150 Delegate::NextWorkInfo* next_work_info); 151 152 // Called by DoInternalWork() to dispatch the user events stored in |events_| 153 // that were triggered. |count| is the number of events to process. Returns 154 // true if work was done, or false if no work was done. 155 bool ProcessEvents(Delegate* delegate, size_t count); 156 157 // Updates the wakeup timer to |wakeup_time| if it differs from the currently 158 // scheduled wakeup. Clears the wakeup timer if |wakeup_time| is 159 // base::TimeTicks::Max(). 160 // Updates |scheduled_wakeup_time_| to follow. 161 void MaybeUpdateWakeupTimer(const base::TimeTicks& wakeup_time, 162 base::TimeDelta leeway); 163 164 void SetWakeupTimerEvent(const base::TimeTicks& wakeup_time, 165 base::TimeDelta leeway, 166 kevent64_s* timer_event); 167 168 // Receive right to which an empty Mach message is sent to wake up the pump 169 // in response to ScheduleWork(). 170 apple::ScopedMachReceiveRight wakeup_; 171 // Scratch buffer that is used to receive the message sent to |wakeup_|. 172 mach_msg_empty_rcv_t wakeup_buffer_; 173 174 // Watch controllers for FDs. IDs are generated by the map and are stored in 175 // the kevent64_s::udata field. 176 IDMap<FdWatchController*, uint64_t> fd_controllers_; 177 178 // Watch controllers for Mach ports. IDs are the port being watched. 179 IDMap<MachPortWatchController*, mach_port_t> port_controllers_; 180 181 // The kqueue that drives the pump. 182 ScopedFD kqueue_; 183 184 // Whether the pump has been Quit() or not. 185 bool keep_running_ = true; 186 187 // The currently scheduled wakeup, if any. If no wakeup is scheduled, 188 // contains base::TimeTicks::Max(). 189 base::TimeTicks scheduled_wakeup_time_{base::TimeTicks::Max()}; 190 191 // The number of events scheduled on the |kqueue_|. There is always at least 192 // 1, for the |wakeup_| port. 193 size_t event_count_ = 1; 194 // Buffer used by DoInternalWork() to be notified of triggered events. This 195 // is always at least |event_count_|-sized. 196 std::vector<kevent64_s> events_{event_count_}; 197 198 WeakPtrFactory<MessagePumpKqueue> weak_factory_; 199 }; 200 201 } // namespace base 202 203 #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_KQUEUE_H_ 204