Skip to content

Commit

Permalink
Add fml::WeakPtr and update users in Shell. (flutter#4296)
Browse files Browse the repository at this point in the history
  • Loading branch information
chinmaygarde authored Oct 31, 2017
1 parent ac16530 commit 19e690e
Show file tree
Hide file tree
Showing 26 changed files with 532 additions and 52 deletions.
12 changes: 7 additions & 5 deletions fml/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ source_set("fml") {
"icu_util.h",
"mapping.cc",
"mapping.h",
"memory/weak_ptr.h",
"memory/weak_ptr_internal.cc",
"memory/weak_ptr_internal.h",
"message_loop.cc",
"message_loop.h",
"message_loop_impl.cc",
Expand All @@ -24,18 +27,16 @@ source_set("fml") {
]

deps = [
"//third_party/dart/runtime:dart_api",
"//garnet/public/lib/fxl",
"//third_party/dart/runtime:dart_api",

# These need to be in sync with the Fuchsia buildroot.
"//third_party/icu",
]

configs += [ "//third_party/icu:icu_config" ]

public_configs = [
"$flutter_root:config",
]
public_configs = [ "$flutter_root:config" ]

libs = []

Expand Down Expand Up @@ -108,15 +109,16 @@ executable("fml_unittests") {
testonly = true

sources = [
"memory/weak_ptr_unittest.cc",
"message_loop_unittests.cc",
"thread_local_unittests.cc",
"thread_unittests.cc",
]

deps = [
"//third_party/dart/runtime:libdart_jit",
"$flutter_root/fml",
"$flutter_root/testing",
"//garnet/public/lib/fxl",
"//third_party/dart/runtime:libdart_jit",
]
}
178 changes: 178 additions & 0 deletions fml/memory/weak_ptr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file provides weak pointers and weak pointer factories that work like
// Chromium's |base::WeakPtr<T>| and |base::WeakPtrFactory<T>|.

#ifndef FLUTTER_FML_MEMORY_WEAK_PTR_H_
#define FLUTTER_FML_MEMORY_WEAK_PTR_H_

#include <utility>

#include "flutter/fml/memory/weak_ptr_internal.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/memory/ref_counted.h"

namespace fml {

// Forward declaration, so |WeakPtr<T>| can friend it.
template <typename T>
class WeakPtrFactory;

// Class for "weak pointers" that can be invalidated. Valid weak pointers can
// only originate from a |WeakPtrFactory| (see below), though weak pointers are
// copyable and movable.
//
// Weak pointers are not in general thread-safe. They may only be *used* on a
// single thread, namely the same thread as the "originating" |WeakPtrFactory|
// (which can invalidate the weak pointers that it generates).
//
// However, weak pointers may be passed to other threads, reset on other
// threads, or destroyed on other threads. They may also be reassigned on other
// threads (in which case they should then only be used on the thread
// corresponding to the new "originating" |WeakPtrFactory|).
template <typename T>
class WeakPtr {
public:
WeakPtr() : ptr_(nullptr) {}

// Copy constructor.
WeakPtr(const WeakPtr<T>& r) = default;

template <typename U>
WeakPtr(const WeakPtr<U>& r) : ptr_(r.ptr_), flag_(r.flag_) {}

// Move constructor.
WeakPtr(WeakPtr<T>&& r) = default;

template <typename U>
WeakPtr(WeakPtr<U>&& r) : ptr_(r.ptr_), flag_(std::move(r.flag_)) {}

~WeakPtr() = default;

// The following methods are thread-friendly, in the sense that they may be
// called subject to additional synchronization.

// Copy assignment.
WeakPtr<T>& operator=(const WeakPtr<T>& r) = default;

// Move assignment.
WeakPtr<T>& operator=(WeakPtr<T>&& r) = default;

void reset() { flag_ = nullptr; }

// The following methods should only be called on the same thread as the
// "originating" |WeakPtrFactory|.

explicit operator bool() const { return flag_ && flag_->is_valid(); }

T* get() const { return *this ? ptr_ : nullptr; }

T& operator*() const {
FXL_DCHECK(*this);
return *get();
}

T* operator->() const {
FXL_DCHECK(*this);
return get();
}

private:
template <typename U>
friend class WeakPtr;

friend class WeakPtrFactory<T>;

explicit WeakPtr(T* ptr, fxl::RefPtr<fml::internal::WeakPtrFlag>&& flag)
: ptr_(ptr), flag_(std::move(flag)) {}

T* ptr_;
fxl::RefPtr<fml::internal::WeakPtrFlag> flag_;

// Copy/move construction/assignment supported.
};

// Class that produces (valid) |WeakPtr<T>|s. Typically, this is used as a
// member variable of |T| (preferably the last one -- see below), and |T|'s
// methods control how weak pointers to it are vended. This class is not
// thread-safe, and should only be created, destroyed and used on a single
// thread.
//
// Example:
//
// class Controller {
// public:
// Controller() : ..., weak_factory_(this) {}
// ...
//
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// void WorkComplete(const Result& result) { ... }
//
// private:
// ...
//
// // Member variables should appear before the |WeakPtrFactory|, to ensure
// // that any |WeakPtr|s to |Controller| are invalidated before its member
// // variables' destructors are executed.
// WeakPtrFactory<Controller> weak_factory_;
// };
//
// class Worker {
// public:
// static void StartNew(const WeakPtr<Controller>& controller) {
// Worker* worker = new Worker(controller);
// // Kick off asynchronous processing....
// }
//
// private:
// Worker(const WeakPtr<Controller>& controller) : controller_(controller) {}
//
// void DidCompleteAsynchronousProcessing(const Result& result) {
// if (controller_)
// controller_->WorkComplete(result);
// }
//
// WeakPtr<Controller> controller_;
// };
template <typename T>
class WeakPtrFactory {
public:
explicit WeakPtrFactory(T* ptr) : ptr_(ptr) { FXL_DCHECK(ptr_); }
~WeakPtrFactory() { InvalidateWeakPtrs(); }

// Gets a new weak pointer, which will be valid until either
// |InvalidateWeakPtrs()| is called or this object is destroyed.
WeakPtr<T> GetWeakPtr() {
if (!flag_)
flag_ = fxl::MakeRefCounted<fml::internal::WeakPtrFlag>();
return WeakPtr<T>(ptr_, flag_.Clone());
}

// Call this method to invalidate all existing weak pointers. (Note that
// additional weak pointers can be produced even after this is called.)
void InvalidateWeakPtrs() {
if (!flag_)
return;
flag_->Invalidate();
flag_ = nullptr;
}

// Call this method to determine if any weak pointers exist. (Note that a
// "false" result is definitive, but a "true" result may not be if weak
// pointers are held/reset/destroyed/reassigned on other threads.)
bool HasWeakPtrs() const { return flag_ && !flag_->HasOneRef(); }

private:
// Note: See weak_ptr_internal.h for an explanation of why we store the
// pointer here, instead of in the "flag".
T* const ptr_;
fxl::RefPtr<fml::internal::WeakPtrFlag> flag_;

FXL_DISALLOW_COPY_AND_ASSIGN(WeakPtrFactory);
};

} // namespace fml

#endif // FLUTTER_FML_MEMORY_WEAK_PTR_H_
26 changes: 26 additions & 0 deletions fml/memory/weak_ptr_internal.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/fml/memory/weak_ptr_internal.h"

#include "lib/fxl/logging.h"

namespace fml {
namespace internal {

WeakPtrFlag::WeakPtrFlag() : is_valid_(true) {}

WeakPtrFlag::~WeakPtrFlag() {
// Should be invalidated before destruction.
FXL_DCHECK(!is_valid_);
}

void WeakPtrFlag::Invalidate() {
// Invalidation should happen exactly once.
FXL_DCHECK(is_valid_);
is_valid_ = false;
}

} // namespace internal
} // namespace fml
41 changes: 41 additions & 0 deletions fml/memory/weak_ptr_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_MEMORY_WEAK_PTR_INTERNAL_H_
#define FLUTTER_FML_MEMORY_WEAK_PTR_INTERNAL_H_

#include "lib/fxl/macros.h"
#include "lib/fxl/memory/ref_counted.h"

namespace fml {
namespace internal {

// |WeakPtr<T>|s have a reference to a |WeakPtrFlag| to determine whether they
// are valid (non-null) or not. We do not store a |T*| in this object since
// there may also be |WeakPtr<U>|s to the same object, where |U| is a superclass
// of |T|.
//
// This class in not thread-safe, though references may be released on any
// thread (allowing weak pointers to be destroyed/reset/reassigned on any
// thread).
class FXL_EXPORT WeakPtrFlag : public fxl::RefCountedThreadSafe<WeakPtrFlag> {
public:
WeakPtrFlag();

~WeakPtrFlag();

bool is_valid() const { return is_valid_; }

void Invalidate();

private:
bool is_valid_;

FXL_DISALLOW_COPY_AND_ASSIGN(WeakPtrFlag);
};

} // namespace internal
} // namespace fml

#endif // FLUTTER_FML_MEMORY_WEAK_PTR_INTERNAL_H_
Loading

0 comments on commit 19e690e

Please sign in to comment.