message_pump_kqueue.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. #ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_KQUEUE_H_
  5. #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_KQUEUE_H_
  6. #include <mach/mach.h>
  7. #include <stdint.h>
  8. #include <sys/event.h>
  9. #include <vector>
  10. #include "base/containers/id_map.h"
  11. #include "base/files/scoped_file.h"
  12. #include "base/location.h"
  13. #include "base/mac/scoped_mach_port.h"
  14. #include "base/macros.h"
  15. #include "base/memory/weak_ptr.h"
  16. #include "base/message_loop/message_pump.h"
  17. #include "base/message_loop/watchable_io_message_pump_posix.h"
  18. namespace base {
  19. // MessagePumpKqueue is used on macOS to drive an IO MessageLoop that is
  20. // capable of watching both POSIX file descriptors and Mach ports.
  21. class BASE_EXPORT MessagePumpKqueue : public MessagePump,
  22. public WatchableIOMessagePumpPosix {
  23. public:
  24. class FdWatchController : public FdWatchControllerInterface {
  25. public:
  26. explicit FdWatchController(const Location& from_here);
  27. ~FdWatchController() override;
  28. // FdWatchControllerInterface:
  29. bool StopWatchingFileDescriptor() override;
  30. protected:
  31. friend class MessagePumpKqueue;
  32. void Init(WeakPtr<MessagePumpKqueue> pump,
  33. int fd,
  34. int mode,
  35. FdWatcher* watcher);
  36. void Reset();
  37. int fd() { return fd_; }
  38. int mode() { return mode_; }
  39. FdWatcher* watcher() { return watcher_; }
  40. private:
  41. int fd_ = -1;
  42. int mode_ = 0;
  43. FdWatcher* watcher_ = nullptr;
  44. WeakPtr<MessagePumpKqueue> pump_;
  45. DISALLOW_COPY_AND_ASSIGN(FdWatchController);
  46. };
  47. // Delegate interface that provides notifications of Mach message receive
  48. // events.
  49. class MachPortWatcher {
  50. public:
  51. virtual ~MachPortWatcher() {}
  52. virtual void OnMachMessageReceived(mach_port_t port) = 0;
  53. };
  54. // Controller interface that is used to stop receiving events for an
  55. // installed MachPortWatcher.
  56. class MachPortWatchController {
  57. public:
  58. explicit MachPortWatchController(const Location& from_here);
  59. ~MachPortWatchController();
  60. bool StopWatchingMachPort();
  61. protected:
  62. friend class MessagePumpKqueue;
  63. void Init(WeakPtr<MessagePumpKqueue> pump,
  64. mach_port_t port,
  65. MachPortWatcher* watcher);
  66. void Reset();
  67. mach_port_t port() { return port_; }
  68. MachPortWatcher* watcher() { return watcher_; }
  69. private:
  70. mach_port_t port_ = MACH_PORT_NULL;
  71. MachPortWatcher* watcher_ = nullptr;
  72. WeakPtr<MessagePumpKqueue> pump_;
  73. const Location from_here_;
  74. DISALLOW_COPY_AND_ASSIGN(MachPortWatchController);
  75. };
  76. MessagePumpKqueue();
  77. ~MessagePumpKqueue() override;
  78. // MessagePump:
  79. void Run(Delegate* delegate) override;
  80. void Quit() override;
  81. void ScheduleWork() override;
  82. void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
  83. // Begins watching the Mach receive right named by |port|. The |controller|
  84. // can be used to stop watching for incoming messages, and new message
  85. // notifications are delivered to the |delegate|. Returns true if the watch
  86. // was successfully set-up and false on error.
  87. bool WatchMachReceivePort(mach_port_t port,
  88. MachPortWatchController* controller,
  89. MachPortWatcher* delegate);
  90. // WatchableIOMessagePumpPosix:
  91. bool WatchFileDescriptor(int fd,
  92. bool persistent,
  93. int mode,
  94. FdWatchController* controller,
  95. FdWatcher* delegate);
  96. private:
  97. // Called by the watch controller implementations to stop watching the
  98. // respective types of handles.
  99. bool StopWatchingMachPort(MachPortWatchController* controller);
  100. bool StopWatchingFileDescriptor(FdWatchController* controller);
  101. // Checks the |kqueue_| for events. If |next_work_info| is null, then the
  102. // kqueue will be polled for events. If it is non-null, it will wait for the
  103. // amount of time specified by the NextWorkInfo or until an event is
  104. // triggered. Returns whether any events were dispatched, with the events
  105. // stored in |events_|.
  106. bool DoInternalWork(Delegate::NextWorkInfo* next_work_info);
  107. // Called by DoInternalWork() to dispatch the user events stored in |events_|
  108. // that were triggered. |count| is the number of events to process. Returns
  109. // true if work was done, or false if no work was done.
  110. bool ProcessEvents(int count);
  111. // Receive right to which an empty Mach message is sent to wake up the pump
  112. // in response to ScheduleWork().
  113. mac::ScopedMachReceiveRight wakeup_;
  114. // Scratch buffer that is used to receive the message sent to |wakeup_|.
  115. mach_msg_empty_rcv_t wakeup_buffer_;
  116. // A Mach port set used to watch ports from WatchMachReceivePort(). This is
  117. // only used on macOS <10.12, where kqueues cannot watch ports directly.
  118. mac::ScopedMachPortSet port_set_;
  119. // Watch controllers for FDs. IDs are generated by the map and are stored in
  120. // the kevent64_s::udata field.
  121. IDMap<FdWatchController*> fd_controllers_;
  122. // Watch controllers for Mach ports. IDs are the port being watched.
  123. IDMap<MachPortWatchController*> port_controllers_;
  124. // The kqueue that drives the pump.
  125. ScopedFD kqueue_;
  126. // Whether the pump has been Quit() or not.
  127. bool keep_running_ = true;
  128. // The number of events scheduled on the |kqueue_|. There is always at least
  129. // 1, for the |wakeup_| port (or |port_set_|).
  130. size_t event_count_ = 1;
  131. // Buffer used by DoInternalWork() to be notified of triggered events. This
  132. // is always at least |event_count_|-sized.
  133. std::vector<kevent64_s> events_{event_count_};
  134. WeakPtrFactory<MessagePumpKqueue> weak_factory_;
  135. DISALLOW_COPY_AND_ASSIGN(MessagePumpKqueue);
  136. };
  137. } // namespace base
  138. #endif // BASE_MESSAGE_LOOP_MESSAGE_PUMP_KQUEUE_H_