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