// Copyright (c) 2011 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. // Weak handles provides a way to refer to weak pointers from another // thread. This is useful because it is not safe to reference a weak // pointer from a thread other than the thread on which it was // created. // // Weak handles can be passed across threads, 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) {} // // void OnIOStart() { // foo_.Call(FROM_HERE, &Foo::OnIOStart); // } // // void OnIOEvent(IOEvent e) { // foo_.Call(FROM_HERE, &Foo::OnIOEvent, e); // } // // void OnIOError(IOError err) { // foo_.Call(FROM_HERE, &Foo::OnIOError, err); // } // // private: // const WeakHandle foo_; // }; // // class Foo : public SupportsWeakPtr, public NonThreadSafe { // public: // Foo() { // SpawnFooIOWorkerOnIOThread(base::MakeWeakHandle(AsWeakPtr())); // } // // /* Will always be called on the correct thread, and only if this // object hasn't been destroyed. */ // void OnIOStart() { DCHECK(CalledOnValidThread(); ... } // void OnIOEvent(IOEvent e) { DCHECK(CalledOnValidThread(); ... } // void OnIOError(IOError err) { DCHECK(CalledOnValidThread(); ... } // }; #ifndef CHROME_BROWSER_SYNC_WEAK_HANDLE_H_ #define CHROME_BROWSER_SYNC_WEAK_HANDLE_H_ #pragma once #include #include "base/basictypes.h" #include "base/bind.h" #include "base/callback.h" #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/tracked.h" namespace base { class MessageLoopProxy; } // namespace base namespace tracked_objects { class Location; } // namespace tracked_objects namespace browser_sync { template class WeakHandle; namespace internal { // These classes are part of the WeakHandle implementation. DO NOT // USE THESE CLASSES DIRECTLY YOURSELF. // Adapted from base/callback_internal.h. template struct ParamTraits { typedef const T& ForwardType; }; template struct ParamTraits { typedef T& ForwardType; }; template struct ParamTraits { typedef const T* ForwardType; }; template struct ParamTraits { typedef const T* ForwardType; }; class WeakHandleCoreBase; struct WeakHandleCoreBaseTraits { static void Destruct(const WeakHandleCoreBase* core_base); }; // Base class for WeakHandleCore to avoid template bloat. Handles // the interaction with the owner thread and its message loop. class WeakHandleCoreBase : public MessageLoop::DestructionObserver, public base::RefCountedThreadSafe { public: // Assumes the current thread is the owner thread. WeakHandleCoreBase(); // May be called on any thread. bool IsOnOwnerThread() const; // MessageLoop::DestructionObserver implementation. Must be called // on the owner thread. virtual void WillDestroyCurrentMessageLoop() OVERRIDE; protected: // May be deleted on any thread, but only via DestroyAndDelete() // which is called by our traits class. virtual ~WeakHandleCoreBase(); // This is called exactly once on the owner thread right before this // object is destroyed or when the owner thread is destroyed, // whichever comes first. Overridden by WeakHandle (which also // calls WeakHandleCoreBase::CleanupOnOwnerThread()). virtual void CleanupOnOwnerThread(); // May be called on any thread. void PostToOwnerThread(const tracked_objects::Location& from_here, const base::Closure& fn) const; private: friend struct WeakHandleCoreBaseTraits; // May be called on any thread, but only via // WeakHandleCoreBaseTraits::Destruct(). Destroys and deletes this // object. void Destroy(); // Calls CleanupOnOwnerThread() and deletes |this|. Must be called // on the owner thread via Destroy(). void CleanupAndDestroyOnOwnerThread(); // May be read on any thread, but should only be dereferenced on the // owner thread. MessageLoop* const owner_loop_; // May be used on any thread. const scoped_refptr owner_loop_proxy_; // Should only be read on the owner thread or in the destructor. // Used only for CHECKs. bool destroyed_on_owner_thread_; DISALLOW_COPY_AND_ASSIGN(WeakHandleCoreBase); }; // WeakHandleCore contains all the logic for WeakHandle. template class WeakHandleCore : public WeakHandleCoreBase { public: // Must be called on |ptr|'s owner thread, which is assumed to be // the current thread. explicit WeakHandleCore(const base::WeakPtr& ptr) : ptr_(new base::WeakPtr(ptr)) {} // Must be called on |ptr_|'s owner thread. base::WeakPtr Get() const { CHECK(IsOnOwnerThread()); return ptr_ ? *ptr_ : base::WeakPtr(); } // Call(...) may be called on any thread, but all its arguments // should be safe to be bound and copied across threads. template void Call(const tracked_objects::Location& from_here, void (U::*fn)(void)) const { PostToOwnerThread( from_here, Bind(&WeakHandleCore::template DoCall0, this, fn)); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1), typename ParamTraits::ForwardType a1) const { PostToOwnerThread( from_here, Bind(&WeakHandleCore::template DoCall1, this, fn, a1)); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2) const { PostToOwnerThread( from_here, Bind(&WeakHandleCore::template DoCall2, this, fn, a1, a2)); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2, A3), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2, typename ParamTraits::ForwardType a3) const { PostToOwnerThread( from_here, Bind(&WeakHandleCore::template DoCall3, this, fn, a1, a2, a3)); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2, A3, A4), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2, typename ParamTraits::ForwardType a3, typename ParamTraits::ForwardType a4) const { PostToOwnerThread( from_here, Bind(&WeakHandleCore::template DoCall4, this, fn, a1, a2, a3, a4)); } protected: // Must be called on |ptr_|'s owner thread exactly once. virtual void CleanupOnOwnerThread() OVERRIDE { CHECK(IsOnOwnerThread()); CHECK(ptr_); delete ptr_; ptr_ = NULL; WeakHandleCoreBase::CleanupOnOwnerThread(); } private: // May be called on any thread. ~WeakHandleCore() { // It is safe to read |ptr_| here even if we're not on the owner // thread (see comments on base::AtomicRefCountDecN()). CHECK(!ptr_); } // GCC 4.2.1 on OS X gets confused if all the DoCall functions are // named the same, so we distinguish them. template void DoCall0(void (U::*fn)(void)) const { CHECK(IsOnOwnerThread()); if (!Get()) { return; } (Get()->*fn)(); } template void DoCall1(void (U::*fn)(A1), typename ParamTraits::ForwardType a1) const { CHECK(IsOnOwnerThread()); if (!Get()) { return; } (Get()->*fn)(a1); } template void DoCall2(void (U::*fn)(A1, A2), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2) const { CHECK(IsOnOwnerThread()); if (!Get()) { return; } (Get()->*fn)(a1, a2); } template void DoCall3(void (U::*fn)(A1, A2, A3), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2, typename ParamTraits::ForwardType a3) const { CHECK(IsOnOwnerThread()); if (!Get()) { return; } (Get()->*fn)(a1, a2, a3); } template void DoCall4(void (U::*fn)(A1, A2, A3, A4), typename ParamTraits::ForwardType a1, typename ParamTraits::ForwardType a2, typename ParamTraits::ForwardType a3, typename ParamTraits::ForwardType a4) const { CHECK(IsOnOwnerThread()); if (!Get()) { return; } (Get()->*fn)(a1, a2, a3, a4); } // Must be dereferenced and destroyed only on the owner thread. // Must be read only on the owner thread or the destructor. base::WeakPtr* ptr_; DISALLOW_COPY_AND_ASSIGN(WeakHandleCore); }; } // namespace internal // May be destroyed on any thread. // Copying and assignment are welcome. template class WeakHandle { public: // Creates an uninitialized WeakHandle. WeakHandle() {} // Creates an initialized WeakHandle from |ptr|. explicit WeakHandle(const base::WeakPtr& ptr) : core_(new internal::WeakHandleCore(ptr)) {} // 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() != NULL; } // Resets to an uninitialized WeakHandle. void Reset() { core_ = NULL; } // Must be called only on the underlying object's owner thread. base::WeakPtr Get() const { CHECK(IsInitialized()); CHECK(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 void Call(const tracked_objects::Location& from_here, void (U::*fn)(void)) const { CHECK(IsInitialized()); core_->Call(from_here, fn); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1), typename internal::ParamTraits::ForwardType a1) const { CHECK(IsInitialized()); core_->Call(from_here, fn, a1); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2), typename internal::ParamTraits::ForwardType a1, typename internal::ParamTraits::ForwardType a2) const { CHECK(IsInitialized()); core_->Call(from_here, fn, a1, a2); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2, A3), typename internal::ParamTraits::ForwardType a1, typename internal::ParamTraits::ForwardType a2, typename internal::ParamTraits::ForwardType a3) const { CHECK(IsInitialized()); core_->Call(from_here, fn, a1, a2, a3); } template void Call(const tracked_objects::Location& from_here, void (U::*fn)(A1, A2, A3, A4), typename internal::ParamTraits::ForwardType a1, typename internal::ParamTraits::ForwardType a2, typename internal::ParamTraits::ForwardType a3, typename internal::ParamTraits::ForwardType a4) const { CHECK(IsInitialized()); core_->Call(from_here, fn, a1, a2, a3, a4); } private: scoped_refptr > core_; }; // Makes a WeakHandle from a WeakPtr. template WeakHandle MakeWeakHandle(const base::WeakPtr& ptr) { return WeakHandle(ptr); } } // namespace browser_sync #endif // CHROME_BROWSER_SYNC_WEAK_HANDLE_H_