blob: a5650561e62dbad075a3f8190765f21970216e16 [file] [log] [blame]
// Copyright 2012 The Chromium 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 COMPONENTS_SYNC_BASE_WEAK_HANDLE_H_
#define COMPONENTS_SYNC_BASE_WEAK_HANDLE_H_
#include <cstddef>
#include <utility>
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
// Weak handles provides a way to refer to weak pointers from another sequence.
// This is useful because it is not safe to reference a weak pointer from a
// sequence other than the sequence on which it was created.
//
// Weak handles can be passed across sequences, so for example, you can use them
// to do the "real" work on one thread and get notified on another thread:
//
// class FooIOWorker {
// public:
// FooIOWorker(const WeakHandle<Foo>& foo) : foo_(foo) {}
//
// void OnIOStart() {
// foo_.Call(FROM_HERE, &Foo::OnIOStart);
// }
//
// private:
// const WeakHandle<Foo> foo_;
// };
//
// class Foo : public SupportsWeakPtr<Foo> {
// public:
// Foo() {
// SpawnFooIOWorkerOnIOThread(base::MakeWeakHandle(AsWeakPtr()));
// }
//
// /* Will always be called on the correct sequence, and only if this
// object hasn't been destroyed. */
// void OnIOStart() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); .. }
//
// private:
// SEQUENCE_CHECKER(sequence_checker_);
// };
namespace base {
class Location;
} // namespace base
namespace syncer {
template <typename T>
class WeakHandle;
namespace internal {
// These classes are part of the WeakHandle implementation. DO NOT
// USE THESE CLASSES DIRECTLY YOURSELF.
// Base class for WeakHandleCore<T> to avoid template bloat. Handles
// the interaction with the owner thread and its message loop.
class WeakHandleCoreBase {
public:
// Assumes the current thread is the owner thread.
WeakHandleCoreBase();
// May be called on any thread.
bool IsOnOwnerThread() const;
protected:
// May be destroyed on any thread.
~WeakHandleCoreBase();
// May be called on any thread.
void PostToOwnerThread(const base::Location& from_here,
const base::Closure& fn) const;
private:
// May be used on any thread.
const scoped_refptr<base::SequencedTaskRunner> owner_loop_task_runner_;
DISALLOW_COPY_AND_ASSIGN(WeakHandleCoreBase);
};
// WeakHandleCore<T> contains all the logic for WeakHandle<T>.
template <typename T>
class WeakHandleCore : public WeakHandleCoreBase,
public base::RefCountedThreadSafe<WeakHandleCore<T>> {
public:
// Must be called on |ptr|'s owner thread, which is assumed to be
// the current thread.
explicit WeakHandleCore(const base::WeakPtr<T>& ptr) : ptr_(ptr) {}
// Must be called on |ptr_|'s owner thread.
base::WeakPtr<T> Get() const {
DCHECK(IsOnOwnerThread());
return ptr_;
}
// Call(...) may be called on any thread, but all its arguments
// should be safe to be bound and copied across threads.
template <typename Method, typename... Args>
void Call(const base::Location& from_here,
Method method,
Args&&... args) const {
PostToOwnerThread(from_here,
base::Bind(method, ptr_, std::forward<Args>(args)...));
}
private:
friend class base::RefCountedThreadSafe<WeakHandleCore<T>>;
// May be destroyed on any thread.
~WeakHandleCore() {}
// Must be dereferenced only on the owner thread. May be destroyed
// from any thread.
base::WeakPtr<T> ptr_;
DISALLOW_COPY_AND_ASSIGN(WeakHandleCore);
};
} // namespace internal
// May be destroyed on any thread.
// Copying and assignment are welcome.
template <typename T>
class WeakHandle {
public:
// Creates an uninitialized WeakHandle.
WeakHandle() {}
// Creates an initialized WeakHandle from |ptr|.
explicit WeakHandle(const base::WeakPtr<T>& ptr)
: core_(new internal::WeakHandleCore<T>(ptr)) {}
// Allow conversion from WeakHandle<U> to WeakHandle<T> if U is
// convertible to T, but we *must* be on |other|'s owner thread.
// Note that this doesn't override the regular copy constructor, so
// that one can be called on any thread.
template <typename U>
WeakHandle(const WeakHandle<U>& other) // NOLINT
: core_(other.IsInitialized()
? new internal::WeakHandleCore<T>(other.Get())
: nullptr) {}
// Returns true iff this WeakHandle is initialized. Note that being
// initialized isn't a guarantee that the underlying object is still
// alive.
bool IsInitialized() const { return core_.get() != nullptr; }
// Resets to an uninitialized WeakHandle.
void Reset() { core_ = nullptr; }
// Must be called only on the underlying object's owner thread.
base::WeakPtr<T> Get() const {
DCHECK(IsInitialized());
DCHECK(core_->IsOnOwnerThread());
return core_->Get();
}
// Call(...) may be called on any thread, but all its arguments
// should be safe to be bound and copied across threads.
template <typename Method, typename... Args>
void Call(const base::Location& from_here,
Method method,
Args&&... args) const {
DCHECK(IsInitialized());
core_->Call(from_here, method, std::forward<Args>(args)...);
}
private:
FRIEND_TEST_ALL_PREFIXES(WeakHandleTest, TypeConversionConstructor);
FRIEND_TEST_ALL_PREFIXES(WeakHandleTest, TypeConversionConstructorAssignment);
scoped_refptr<internal::WeakHandleCore<T>> core_;
};
// Makes a WeakHandle from a WeakPtr.
template <typename T>
WeakHandle<T> MakeWeakHandle(const base::WeakPtr<T>& ptr) {
return WeakHandle<T>(ptr);
}
} // namespace syncer
#endif // COMPONENTS_SYNC_BASE_WEAK_HANDLE_H_