tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_