// 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/functional/bind_internal.h" #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>> { … }; // 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 { … }; } // namespace blink namespace base { IsWeakReceiver<blink::Persistent<blink::WeakCell<T>>>; BindUnwrapTraits<blink::Persistent<blink::WeakCell<T>>>; MaybeValidTraits<blink::Persistent<blink::WeakCell<T>>>; IsWeakReceiver<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>; BindUnwrapTraits<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>; MaybeValidTraits<blink::UnwrappingCrossThreadHandle<blink::WeakCell<T>>>; } // namespace base #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_HEAP_WEAK_CELL_H_