File: mojo_trap.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (126 lines) | stat: -rw-r--r-- 4,899 bytes parent folder | download | duplicates (9)
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
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MOJO_CORE_IPCZ_DRIVER_MOJO_TRAP_H_
#define MOJO_CORE_IPCZ_DRIVER_MOJO_TRAP_H_

#include <cstdint>
#include <optional>

#include "base/containers/flat_map.h"
#include "base/containers/span.h"
#include "base/memory/scoped_refptr.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread_ref.h"
#include "mojo/core/ipcz_driver/object.h"
#include "mojo/public/c/system/trap.h"
#include "mojo/public/c/system/types.h"
#include "third_party/abseil-cpp/absl/container/inlined_vector.h"
#include "third_party/ipcz/include/ipcz/ipcz.h"

namespace mojo::core::ipcz_driver {

// Mojo traps are more complex than ipcz traps. A Mojo trap is approximately
// equivalent to a *collection* of ipcz traps (which Mojo would call "triggers"
// within a trap) sharing a common event handler.
//
// A Mojo trap can only be armed while all of its triggers' conditions are
// simultaneously unsatisfied. This object emulates that behavior well enough to
// suit Chromium's needs.
class MojoTrap : public Object<MojoTrap> {
 public:
  explicit MojoTrap(MojoTrapEventHandler handler);

  static Type object_type() { return kMojoTrap; }

  // Registers a new trigger on this trap. Each trigger corresponds to an active
  // ipcz trap when this Mojo trap is armed.
  MojoResult AddTrigger(MojoHandle handle,
                        MojoHandleSignals signals,
                        MojoTriggerCondition condition,
                        uintptr_t trigger_context);

  // Unregisters a trigger from the trap. If the trigger still has an ipcz trap
  // installed on `handle`, any event it may eventually fire will be ignored.
  MojoResult RemoveTrigger(uintptr_t trigger_context);

  // Attempts to arm this Mojo trap. Successful arming means that for every
  // trigger added, we can install a corresponding ipcz trap.
  MojoResult Arm(MojoTrapEvent* blocking_events, uint32_t* num_blocking_events);

  // ObjectBase:
  void Close() override;

 private:
  struct Trigger;

  ~MojoTrap() override;

  static void TrapEventHandler(const IpczTrapEvent* event);
  static void TrapRemovalEventHandler(const IpczTrapEvent* event);

  void HandleEvent(const IpczTrapEvent& event);
  void HandleTrapRemoved(const IpczTrapEvent& event);

  // Attempts to arm a single trigger by creating an ipcz trap for it. If this
  // fails because trapped conditions are already met, a corresponding event
  // is stored in `event`.
  IpczResult ArmTrigger(Trigger& trigger, MojoTrapEvent& event);

  void DispatchOrQueueTriggerRemoval(Trigger& trigger)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void DispatchOrQueueEvent(Trigger& trigger, const MojoTrapEvent& event)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void DispatchEvent(const MojoTrapEvent& event)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);

  const MojoTrapEventHandler handler_;

  base::Lock lock_;

  // Condition variable used to wait for any other thread to finish dispatching
  // events so that another thread may dipatch its own.
  base::ConditionVariable dispatching_condition_ GUARDED_BY(lock_){&lock_};

  // The current number of waiters on |dispatching_condition_|.
  uint32_t waiters_ GUARDED_BY(lock_) = 0;

  // A ref identifying the thread which is currently dispatching an event for
  // this trap, if any.
  std::optional<base::PlatformThreadRef> dispatching_thread_ GUARDED_BY(lock_);

  using TriggerMap = base::flat_map<uintptr_t, scoped_refptr<Trigger>>;
  TriggerMap triggers_ GUARDED_BY(lock_);

  // Trigger prioritization proceeds in a round-robin fashion across consecutive
  // Arm() invocations. This iterator caches the most recently prioritized
  // entry.
  //
  // SUBTLE: Because it is invalidated by mutations to `triggers_`, this MUST
  // be reset any time a trigger is inserted or removed.
  TriggerMap::iterator next_trigger_ GUARDED_BY(lock_) = triggers_.end();

  // A Mojo trap must ensure that all its event dispatches are mutually
  // exclusive. While one thread is dispatching an event, other threads must
  // wait to acquire `dispatching_condition_` before dispatching anything; but
  // if the in-progress dispatch itself elicits new events on the trap, those
  // events are accumulated here and flushed (FIFO) after the in-progress
  // dispatch is done.
  struct PendingEvent {
    PendingEvent();
    PendingEvent(scoped_refptr<Trigger> trigger, const MojoTrapEvent& event);
    PendingEvent(PendingEvent&&);
    ~PendingEvent();
    scoped_refptr<Trigger> trigger;
    MojoTrapEvent event;
  };
  absl::InlinedVector<PendingEvent, 4> pending_mojo_events_ GUARDED_BY(lock_);

  bool armed_ GUARDED_BY(lock_) = false;
};

}  // namespace mojo::core::ipcz_driver

#endif  // MOJO_CORE_IPCZ_DRIVER_MOJO_TRAP_H_