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

base / message_loop / message_pump_fuchsia.h [blame]

// Copyright 2017 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_FUCHSIA_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_FUCHSIA_H_

#include <lib/async/wait.h>
#include <memory>

#include "base/base_export.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"

typedef struct fdio fdio_t;

namespace async {
class Loop;
}  // namespace async

namespace base {

class BASE_EXPORT MessagePumpFuchsia : public MessagePump,
                                       public WatchableIOMessagePumpPosix {
 public:
  // Implemented by callers to receive notifications of handle & fd events.
  class ZxHandleWatcher {
   public:
    virtual void OnZxHandleSignalled(zx_handle_t handle,
                                     zx_signals_t signals) = 0;

   protected:
    virtual ~ZxHandleWatcher() = default;
  };

  // Manages an active watch on an zx_handle_t.
  class ZxHandleWatchController : public async_wait_t {
   public:
    explicit ZxHandleWatchController(const Location& from_here);

    ZxHandleWatchController(const ZxHandleWatchController&) = delete;
    ZxHandleWatchController& operator=(const ZxHandleWatchController&) = delete;

    // Deleting the Controller implicitly calls StopWatchingZxHandle.
    virtual ~ZxHandleWatchController();

    // Stop watching the handle, always safe to call.  No-op if there's nothing
    // to do.
    bool StopWatchingZxHandle();

    const Location& created_from_location() { return created_from_location_; }

   protected:
    friend class MessagePumpFuchsia;

    virtual bool WaitBegin();

    bool is_active() const { return async_wait_t::handler != nullptr; }

    static void HandleSignal(async_dispatcher_t* async,
                             async_wait_t* wait,
                             zx_status_t status,
                             const zx_packet_signal_t* signal);

    const Location created_from_location_;

    // This bool is used by the pump when invoking the ZxHandleWatcher callback,
    // and by the FdHandleWatchController when invoking read & write callbacks,
    // to cope with the possibility of the caller deleting the *Watcher within
    // the callback. The pump sets |was_stopped_| to a location on the stack,
    // and the Watcher writes to it, if set, when deleted, allowing the pump
    // to check the value on the stack to short-cut any post-callback work.
    raw_ptr<bool> was_stopped_ = nullptr;

    // Set directly from the inputs to WatchFileDescriptor.
    raw_ptr<ZxHandleWatcher> watcher_ = nullptr;

    // Used to safely access resources owned by the associated message pump.
    WeakPtr<MessagePumpFuchsia> weak_pump_;

    // A watch may be marked as persistent, which means it remains active even
    // after triggering.
    bool persistent_ = false;
  };

  class FdWatchController : public FdWatchControllerInterface,
                            public ZxHandleWatchController,
                            public ZxHandleWatcher {
   public:
    explicit FdWatchController(const Location& from_here);

    FdWatchController(const FdWatchController&) = delete;
    FdWatchController& operator=(const FdWatchController&) = delete;

    ~FdWatchController() override;

    // FdWatchControllerInterface:
    bool StopWatchingFileDescriptor() override;

   private:
    friend class MessagePumpFuchsia;

    // Determines the desires signals, and begins waiting on the handle.
    bool WaitBegin() override;

    // ZxHandleWatcher interface.
    void OnZxHandleSignalled(zx_handle_t handle, zx_signals_t signals) override;

    // Set directly from the inputs to WatchFileDescriptor.
    raw_ptr<FdWatcher> watcher_ = nullptr;
    int fd_ = -1;
    uint32_t desired_events_ = 0;

    // Set by WatchFileDescriptor() to hold a reference to the descriptor's
    // fdio.
    // TODO(366045345) This is actually an owning reference, so we should
    // probably turn it into a ScopedGeneric<> that calls fdio_unsafe_release()
    // on destruction.
    raw_ptr<fdio_t> io_ = nullptr;
  };

  enum Mode {
    WATCH_READ = 1 << 0,
    WATCH_WRITE = 1 << 1,
    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
  };

  MessagePumpFuchsia();

  MessagePumpFuchsia(const MessagePumpFuchsia&) = delete;
  MessagePumpFuchsia& operator=(const MessagePumpFuchsia&) = delete;

  ~MessagePumpFuchsia() override;

  bool WatchZxHandle(zx_handle_t handle,
                     bool persistent,
                     zx_signals_t signals,
                     ZxHandleWatchController* controller,
                     ZxHandleWatcher* delegate);
  bool WatchFileDescriptor(int fd,
                           bool persistent,
                           int mode,
                           FdWatchController* controller,
                           FdWatcher* delegate);

  // MessagePump implementation:
  void Run(Delegate* delegate) override;
  void Quit() override;
  void ScheduleWork() override;
  void ScheduleDelayedWork(
      const Delegate::NextWorkInfo& next_work_info) override;

 private:
  // Handles IO events by running |async_dispatcher_| until |deadline|. Returns
  // true if any events were received or if ScheduleWork() was called.
  bool HandleIoEventsUntil(zx_time_t deadline);

  struct RunState {
    explicit RunState(Delegate* delegate_in) : delegate(delegate_in) {}

    // `delegate` is not a raw_ptr<...> for performance reasons (based on
    // analysis of sampling profiler data and tab_search:top100:2020).
    RAW_PTR_EXCLUSION Delegate* const delegate;

    // Used to flag that the current Run() invocation should return ASAP.
    bool should_quit = false;
  };

  // State for the current invocation of Run(). null if not running.
  RAW_PTR_EXCLUSION RunState* run_state_ = nullptr;

  std::unique_ptr<async::Loop> async_loop_;

  base::WeakPtrFactory<MessagePumpFuchsia> weak_factory_;
};

}  // namespace base

#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_FUCHSIA_H_