File: weak_cell.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (184 lines) | stat: -rw-r--r-- 6,145 bytes parent folder | download | duplicates (3)
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
183
184
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_

#include <type_traits>

#include "base/types/pass_key.h"
#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/member.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"

namespace blink {

template <typename T>
class WeakCellFactory;

// A `WeakCell<T>` provides a GC-safe pattern for classes that want to:
// - expose weak references to themselves
// - invalidate the weak references *before* the object becomes unreachable.
//
// This differs from `WeakMember<T>` in the last point, as `WeakMember<T>` only
// becomes implicitly null after the referenced `T` is no longer reachable. In
// Chrome, a common use of early invalidation is to cancel callbacks that have
// not yet run.
//
// If early invalidation is not needed, please use `WeakMember<T>`!
//
// Like many Oilpan types, this class is thread-unsafe.
//
// Note: This is the GC-safe version of `WeakPtrFactory<T>` + `WeakPtr<T>`.
// `WeakPtrFactory<T>` + `WeakPtr<T>` are GC-unsafe and should not be embedded
// in objects that live on the Oilpan heap.
template <typename T>
class WeakCell : public GarbageCollected<WeakCell<T>> {
 public:
  // Returns a pointer to the referenced object, or null if:
  // - the cell has been invalidated by its factory
  // - or the referenced object is no longer reachable.
  T* Get() const { return ptr_; }

  void Trace(Visitor* v) const { v->Trace(ptr_); }

  // Internal helpers for `WeakCellFactory` implementation.
  explicit WeakCell(base::PassKey<WeakCellFactory<T>>, T* ptr) : ptr_(ptr) {}
  void Invalidate(base::PassKey<WeakCellFactory<T>>) { ptr_ = nullptr; }

 private:
  WeakMember<T> ptr_;
};

// A `WeakCellFactory<T>` vends out a pointer to a `WeakCell<T>`, and allows the
// owning class to invalidate `WeakCell<T>`s that have already been handed out.
//
// Usage overview:
//
// class DatabaseScheduler : public GarbageCollected<DatabaseScheduler> {
//  public:
//   ...
//
//   void DoWork();
//   void CancelWork();
//
//  private:
//   // Note: field ordering for `WeakCellFactory` does not matter, and it does
//   // *not* have to be the last field in a class.
//   WeakCellFactory<DatabaseScheduler> weak_factory_{this};
//   // Note: this is *not* a cross-thread task runner. In Blink, many task
//   // queues are multiplexed onto one thread.
//   scoped_refptr<base::TaskRunner> db_task_queue;
// };
//
// void DatabaseScheduler::DoWork() {
//   // IMPORTANT: the `WrapPersistent()` around the `WeakCell<T>` argument is
//   // mandatory, as `WeakCell<T>` itself is allocated on the Oilpan heap.
//   db_task_queue_->PostTask(
//       FROM_HERE,
//       base::BindOnce(&DatabaseScheduler::DoRealWork,
//                      WrapPersistent(weak_factory_.GetWeakCell())));
// }
//
// void DatabaseScheduler::CancelWork() {
//   // Any already-posted but not-yet-run tasks using a `WeakCell<T>` as the
//   // receiver will not run.
//   // However, any subsequent calls to `DoWork()` above *will* schedule new
//   // callbacks that will run unless `CancelWork()` is called again.
//   weak_factory_.Invalidate();
// }
template <typename T>
class WeakCellFactory {
  DISALLOW_NEW();

 public:
  explicit WeakCellFactory(T* ptr) : ptr_(ptr) {}

  WeakCell<T>* GetWeakCell() {
    if (!weak_cell_) {
      weak_cell_ = MakeGarbageCollected<WeakCell<T>>(
          base::PassKey<WeakCellFactory>(), ptr_);
    }
    DCHECK(weak_cell_);
    return weak_cell_.Get();
  }

  bool HasWeakCells() const { return weak_cell_; }

  // Invalidates the previous `WeakCell<T>` so that `previous_cell->Get()`
  // returns null. Future calls to `GetWeakCell()` will return a *new* and
  // *non-null* cell.
  void Invalidate() {
    if (!weak_cell_) return;
    weak_cell_->Invalidate(base::PassKey<WeakCellFactory>());
    weak_cell_ = nullptr;
  }

  void Trace(Visitor* v) const {
    v->Trace(ptr_);
    v->Trace(weak_cell_);
  }

 private:
  const WeakMember<T> ptr_;
  Member<WeakCell<T>> weak_cell_;
};

}  // namespace blink

namespace base {

template <typename T>
struct IsWeakReceiver<blink::Persistent<blink::WeakCell<T>>> : std::true_type {
};

template <typename T>
struct BindUnwrapTraits<blink::Persistent<blink::WeakCell<T>>> {
  static T* Unwrap(const blink::Persistent<blink::WeakCell<T>>& wrapped) {
    return wrapped->Get();
  }
};

template <typename T>
struct MaybeValidTraits<blink::Persistent<blink::WeakCell<T>>> {
  static constexpr bool MaybeValid(
      const blink::Persistent<blink::WeakCell<T>>& p) {
    // Not necessarily called on `Persistent<T>` and `WeakCell<T>`'s owning
    // thread, so the only possible implementation is to assume the weak cell
    // has not been invalidated.
    return true;
  }
};

template <typename T>
struct IsWeakReceiver<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>
    : std::true_type {};

template <typename T>
struct BindUnwrapTraits<
    blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>> {
  static T* Unwrap(
      const blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>& wrapped) {
    return wrapped.GetOnCreationThread()->Get();
  }
};

template <typename T>
struct MaybeValidTraits<
    blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>> {
  static constexpr bool MaybeValid(
      const blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>& p) {
    // Not necessarily called on `UnwrappingCrossThreadHandle<T>` and
    // `WeakCell<T>`'s owning thread, so the only possible implementation is to
    // assume the weak cell has not been invalidated.
    return true;
  }
};

}  // namespace base

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_