#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 {
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;
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_;
};
class MachPortWatcher {
public:
virtual ~MachPortWatcher() = default;
virtual void OnMachMessageReceived(mach_port_t port) = 0;
};
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;
static void InitializeFeatures();
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;
bool WatchMachReceivePort(mach_port_t port,
MachPortWatchController* controller,
MachPortWatcher* delegate);
bool WatchFileDescriptor(int fd,
bool persistent,
int mode,
FdWatchController* controller,
FdWatcher* delegate);
private:
bool StopWatchingMachPort(MachPortWatchController* controller);
bool StopWatchingFileDescriptor(FdWatchController* controller);
bool DoInternalWork(Delegate* delegate,
Delegate::NextWorkInfo* next_work_info);
bool ProcessEvents(Delegate* delegate, size_t count);
void MaybeUpdateWakeupTimer(const base::TimeTicks& wakeup_time,
base::TimeDelta leeway);
void SetWakeupTimerEvent(const base::TimeTicks& wakeup_time,
base::TimeDelta leeway,
kevent64_s* timer_event);
apple::ScopedMachReceiveRight wakeup_;
mach_msg_empty_rcv_t wakeup_buffer_;
IDMap<FdWatchController*, uint64_t> fd_controllers_;
IDMap<MachPortWatchController*, mach_port_t> port_controllers_;
ScopedFD kqueue_;
bool keep_running_ = true;
base::TimeTicks scheduled_wakeup_time_{base::TimeTicks::Max()};
size_t event_count_ = 1;
std::vector<kevent64_s> events_{event_count_};
WeakPtrFactory<MessagePumpKqueue> weak_factory_;
};
}
#endif