message_pump_kqueue.h (6088B)
1 // Copyright 2019 The Chromium Authors. All rights reserved. 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_PUMP_KQUEUE_H_ 6 #define BASE_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 "mozilla/RefPtr.h" 15 #include "mozilla/UniquePtrExtensions.h" 16 #include "nsTHashMap.h" 17 18 #include "base/basictypes.h" 19 #include "base/time.h" 20 #include "base/message_pump.h" 21 22 namespace base { 23 24 // MessagePumpKqueue is used on macOS to drive an IO MessageLoop that is 25 // capable of watching both POSIX file descriptors and Mach ports. 26 class MessagePumpKqueue : public MessagePump { 27 public: 28 // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness 29 // of a File Descriptor. 30 class Watcher { 31 public: 32 virtual ~Watcher() {} 33 // Called from MessageLoop::Run when an FD can be read from/written to 34 // without blocking 35 virtual void OnFileCanReadWithoutBlocking(int fd) = 0; 36 virtual void OnFileCanWriteWithoutBlocking(int fd) = 0; 37 }; 38 39 class FileDescriptorWatcher { 40 public: 41 explicit FileDescriptorWatcher(); 42 ~FileDescriptorWatcher(); 43 44 bool StopWatchingFileDescriptor(); 45 46 protected: 47 friend class MessagePumpKqueue; 48 49 void Init(MessagePumpKqueue* pump, int fd, int mode, Watcher* watcher); 50 void Reset(); 51 52 int fd() { return fd_; } 53 int mode() { return mode_; } 54 Watcher* watcher() { return watcher_; } 55 56 private: 57 int fd_ = -1; 58 int mode_ = 0; 59 Watcher* watcher_ = nullptr; 60 RefPtr<MessagePumpKqueue> pump_; 61 62 DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher); 63 }; 64 65 enum Mode { 66 WATCH_READ = 1 << 0, 67 WATCH_WRITE = 1 << 1, 68 WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE 69 }; 70 71 // Delegate interface that provides notifications of Mach message receive 72 // events. 73 class MachPortWatcher { 74 public: 75 virtual ~MachPortWatcher() {} 76 virtual void OnMachMessageReceived(mach_port_t port) = 0; 77 }; 78 79 // Controller interface that is used to stop receiving events for an 80 // installed MachPortWatcher. 81 class MachPortWatchController { 82 public: 83 explicit MachPortWatchController(); 84 ~MachPortWatchController(); 85 86 bool StopWatchingMachPort(); 87 88 protected: 89 friend class MessagePumpKqueue; 90 91 void Init(MessagePumpKqueue* pump, mach_port_t port, 92 MachPortWatcher* watcher); 93 void Reset(); 94 95 mach_port_t port() { return port_; } 96 MachPortWatcher* watcher() { return watcher_; } 97 98 private: 99 mach_port_t port_ = MACH_PORT_NULL; 100 MachPortWatcher* watcher_ = nullptr; 101 RefPtr<MessagePumpKqueue> pump_; 102 103 DISALLOW_COPY_AND_ASSIGN(MachPortWatchController); 104 }; 105 106 MessagePumpKqueue(); 107 ~MessagePumpKqueue() override; 108 109 // MessagePump: 110 void Run(Delegate* delegate) override; 111 void Quit() override; 112 void ScheduleWork() override; 113 void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override; 114 115 // Begins watching the Mach receive right named by |port|. The |controller| 116 // can be used to stop watching for incoming messages, and new message 117 // notifications are delivered to the |delegate|. Returns true if the watch 118 // was successfully set-up and false on error. 119 bool WatchMachReceivePort(mach_port_t port, 120 MachPortWatchController* controller, 121 MachPortWatcher* delegate); 122 123 bool WatchFileDescriptor(int fd, bool persistent, int mode, 124 FileDescriptorWatcher* controller, 125 Watcher* delegate); 126 127 private: 128 // Called by the watch controller implementations to stop watching the 129 // respective types of handles. 130 bool StopWatchingMachPort(MachPortWatchController* controller); 131 bool StopWatchingFileDescriptor(FileDescriptorWatcher* controller); 132 133 // Checks the |kqueue_| for events. If |next_work_info| is null, then the 134 // kqueue will be polled for events. If it is non-null, it will wait for the 135 // amount of time specified by the NextWorkInfo or until an event is 136 // triggered. Returns whether any events were dispatched, with the events 137 // stored in |events_|. 138 bool DoInternalWork(Delegate* delegate, TimeTicks* delayed_work_time); 139 140 // Called by DoInternalWork() to dispatch the user events stored in |events_| 141 // that were triggered. |count| is the number of events to process. Returns 142 // true if work was done, or false if no work was done. 143 bool ProcessEvents(Delegate* delegate, int count); 144 145 // Sets the wakeup timer to |wakeup_time|, or clears it if |wakeup_time| is 146 // base::TimeTicks::Max(). Updates |scheduled_wakeup_time_| to follow. 147 void UpdateWakeupTimer(const base::TimeTicks& wakeup_time); 148 149 // Receive right to which an empty Mach message is sent to wake up the pump 150 // in response to ScheduleWork(). 151 mozilla::UniqueMachReceiveRight wakeup_; 152 // Scratch buffer that is used to receive the message sent to |wakeup_|. 153 mach_msg_empty_rcv_t wakeup_buffer_{}; 154 155 // Watch controllers for FDs. IDs are generated from next_fd_controller_id_ 156 // and are stored in the kevent64_s::udata field. 157 nsTHashMap<uint64_t, FileDescriptorWatcher*> fd_controllers_; 158 uint64_t next_fd_controller_id_ = 0; 159 160 // Watch controllers for Mach ports. IDs are the port being watched. 161 nsTHashMap<mach_port_name_t, MachPortWatchController*> port_controllers_; 162 163 // The kqueue that drives the pump. 164 mozilla::UniqueFileHandle kqueue_; 165 166 // Whether the pump has been Quit() or not. 167 bool keep_running_ = true; 168 169 // The time at which we cshould call DoDelayedWork. 170 base::TimeTicks delayed_work_time_; 171 172 // The number of events scheduled on the |kqueue_|. There is always at least 173 // 1, for the |wakeup_| port (or |port_set_|). 174 size_t event_count_ = 1; 175 // Buffer used by DoInternalWork() to be notified of triggered events. This 176 // is always at least |event_count_|-sized. 177 std::vector<kevent64_s> events_{event_count_}; 178 179 DISALLOW_COPY_AND_ASSIGN(MessagePumpKqueue); 180 }; 181 182 } // namespace base 183 184 #endif // BASE_MESSAGE_PUMP_KQUEUE_H_