Home | History | Annotate | Download | only in util
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Weak handles provides a way to refer to weak pointers from another
      6 // thread.  This is useful because it is not safe to reference a weak
      7 // pointer from a thread other than the thread on which it was
      8 // created.
      9 //
     10 // Weak handles can be passed across threads, so for example, you can
     11 // use them to do the "real" work on one thread and get notified on
     12 // another thread:
     13 //
     14 // class FooIOWorker {
     15 //  public:
     16 //   FooIOWorker(const WeakHandle<Foo>& foo) : foo_(foo) {}
     17 //
     18 //   void OnIOStart() {
     19 //     foo_.Call(FROM_HERE, &Foo::OnIOStart);
     20 //   }
     21 //
     22 //   void OnIOEvent(IOEvent e) {
     23 //     foo_.Call(FROM_HERE, &Foo::OnIOEvent, e);
     24 //   }
     25 //
     26 //   void OnIOError(IOError err) {
     27 //     foo_.Call(FROM_HERE, &Foo::OnIOError, err);
     28 //   }
     29 //
     30 //  private:
     31 //   const WeakHandle<Foo> foo_;
     32 // };
     33 //
     34 // class Foo : public SupportsWeakPtr<Foo>, public NonThreadSafe {
     35 //  public:
     36 //   Foo() {
     37 //     SpawnFooIOWorkerOnIOThread(base::MakeWeakHandle(AsWeakPtr()));
     38 //   }
     39 //
     40 //   /* Will always be called on the correct thread, and only if this
     41 //      object hasn't been destroyed. */
     42 //   void OnIOStart() { DCHECK(CalledOnValidThread(); ... }
     43 //   void OnIOEvent(IOEvent e) { DCHECK(CalledOnValidThread(); ... }
     44 //   void OnIOError(IOError err) { DCHECK(CalledOnValidThread(); ... }
     45 // };
     46 
     47 #ifndef SYNC_UTIL_WEAK_HANDLE_H_
     48 #define SYNC_UTIL_WEAK_HANDLE_H_
     49 
     50 #include <cstddef>
     51 
     52 #include "base/basictypes.h"
     53 #include "base/bind.h"
     54 #include "base/callback_forward.h"
     55 #include "base/compiler_specific.h"
     56 #include "base/gtest_prod_util.h"
     57 #include "base/location.h"
     58 #include "base/logging.h"
     59 #include "base/memory/ref_counted.h"
     60 #include "base/memory/weak_ptr.h"
     61 #include "sync/base/sync_export.h"
     62 
     63 namespace base {
     64 class MessageLoopProxy;
     65 }  // namespace base
     66 
     67 namespace tracked_objects {
     68 class Location;
     69 }  // namespace tracked_objects
     70 
     71 namespace syncer {
     72 
     73 template <typename T> class WeakHandle;
     74 
     75 namespace internal {
     76 // These classes are part of the WeakHandle implementation.  DO NOT
     77 // USE THESE CLASSES DIRECTLY YOURSELF.
     78 
     79 // Adapted from base/callback_internal.h.
     80 
     81 template <typename T>
     82 struct ParamTraits {
     83   typedef const T& ForwardType;
     84 };
     85 
     86 template <typename T>
     87 struct ParamTraits<T&> {
     88   typedef T& ForwardType;
     89 };
     90 
     91 template <typename T, size_t n>
     92 struct ParamTraits<T[n]> {
     93   typedef const T* ForwardType;
     94 };
     95 
     96 template <typename T>
     97 struct ParamTraits<T[]> {
     98   typedef const T* ForwardType;
     99 };
    100 
    101 // Base class for WeakHandleCore<T> to avoid template bloat.  Handles
    102 // the interaction with the owner thread and its message loop.
    103 class SYNC_EXPORT WeakHandleCoreBase {
    104  public:
    105   // Assumes the current thread is the owner thread.
    106   WeakHandleCoreBase();
    107 
    108   // May be called on any thread.
    109   bool IsOnOwnerThread() const;
    110 
    111  protected:
    112   // May be destroyed on any thread.
    113   ~WeakHandleCoreBase();
    114 
    115   // May be called on any thread.
    116   void PostToOwnerThread(const tracked_objects::Location& from_here,
    117                          const base::Closure& fn) const;
    118 
    119  private:
    120   // May be used on any thread.
    121   const scoped_refptr<base::MessageLoopProxy> owner_loop_proxy_;
    122 
    123   DISALLOW_COPY_AND_ASSIGN(WeakHandleCoreBase);
    124 };
    125 
    126 // WeakHandleCore<T> contains all the logic for WeakHandle<T>.
    127 template <typename T>
    128 class WeakHandleCore
    129     : public WeakHandleCoreBase,
    130       public base::RefCountedThreadSafe<WeakHandleCore<T> > {
    131  public:
    132   // Must be called on |ptr|'s owner thread, which is assumed to be
    133   // the current thread.
    134   explicit WeakHandleCore(const base::WeakPtr<T>& ptr) : ptr_(ptr) {}
    135 
    136   // Must be called on |ptr_|'s owner thread.
    137   base::WeakPtr<T> Get() const {
    138     CHECK(IsOnOwnerThread());
    139     return ptr_;
    140   }
    141 
    142   // Call(...) may be called on any thread, but all its arguments
    143   // should be safe to be bound and copied across threads.
    144 
    145   template <typename U>
    146   void Call(const tracked_objects::Location& from_here,
    147             void (U::*fn)(void)) const {
    148     PostToOwnerThread(
    149         from_here,
    150         Bind(&WeakHandleCore::template DoCall0<U>, this, fn));
    151   }
    152 
    153   template <typename U, typename A1>
    154   void Call(const tracked_objects::Location& from_here,
    155             void (U::*fn)(A1),
    156             typename ParamTraits<A1>::ForwardType a1) const {
    157     PostToOwnerThread(
    158         from_here,
    159         Bind(&WeakHandleCore::template DoCall1<U, A1>,
    160              this, fn, a1));
    161   }
    162 
    163   template <typename U, typename A1, typename A2>
    164   void Call(const tracked_objects::Location& from_here,
    165             void (U::*fn)(A1, A2),
    166             typename ParamTraits<A1>::ForwardType a1,
    167             typename ParamTraits<A2>::ForwardType a2) const {
    168     PostToOwnerThread(
    169         from_here,
    170         Bind(&WeakHandleCore::template DoCall2<U, A1, A2>,
    171              this, fn, a1, a2));
    172   }
    173 
    174   template <typename U, typename A1, typename A2, typename A3>
    175   void Call(const tracked_objects::Location& from_here,
    176             void (U::*fn)(A1, A2, A3),
    177             typename ParamTraits<A1>::ForwardType a1,
    178             typename ParamTraits<A2>::ForwardType a2,
    179             typename ParamTraits<A3>::ForwardType a3) const {
    180     PostToOwnerThread(
    181         from_here,
    182         Bind(&WeakHandleCore::template DoCall3<U, A1, A2, A3>,
    183              this, fn, a1, a2, a3));
    184   }
    185 
    186   template <typename U, typename A1, typename A2, typename A3, typename A4>
    187   void Call(const tracked_objects::Location& from_here,
    188             void (U::*fn)(A1, A2, A3, A4),
    189             typename ParamTraits<A1>::ForwardType a1,
    190             typename ParamTraits<A2>::ForwardType a2,
    191             typename ParamTraits<A3>::ForwardType a3,
    192             typename ParamTraits<A4>::ForwardType a4) const {
    193     PostToOwnerThread(
    194         from_here,
    195         Bind(&WeakHandleCore::template DoCall4<U, A1, A2, A3, A4>,
    196              this, fn, a1, a2, a3, a4));
    197   }
    198 
    199  private:
    200   friend class base::RefCountedThreadSafe<WeakHandleCore<T> >;
    201 
    202   // May be destroyed on any thread.
    203   ~WeakHandleCore() {}
    204 
    205   // GCC 4.2.1 on OS X gets confused if all the DoCall functions are
    206   // named the same, so we distinguish them.
    207 
    208   template <typename U>
    209   void DoCall0(void (U::*fn)(void)) const {
    210     CHECK(IsOnOwnerThread());
    211     if (!Get()) {
    212       return;
    213     }
    214     (Get().get()->*fn)();
    215   }
    216 
    217   template <typename U, typename A1>
    218   void DoCall1(void (U::*fn)(A1),
    219                typename ParamTraits<A1>::ForwardType a1) const {
    220     CHECK(IsOnOwnerThread());
    221     if (!Get()) {
    222       return;
    223     }
    224     (Get().get()->*fn)(a1);
    225   }
    226 
    227   template <typename U, typename A1, typename A2>
    228   void DoCall2(void (U::*fn)(A1, A2),
    229                typename ParamTraits<A1>::ForwardType a1,
    230                typename ParamTraits<A2>::ForwardType a2) const {
    231     CHECK(IsOnOwnerThread());
    232     if (!Get()) {
    233       return;
    234     }
    235     (Get().get()->*fn)(a1, a2);
    236   }
    237 
    238   template <typename U, typename A1, typename A2, typename A3>
    239   void DoCall3(void (U::*fn)(A1, A2, A3),
    240                typename ParamTraits<A1>::ForwardType a1,
    241                typename ParamTraits<A2>::ForwardType a2,
    242                typename ParamTraits<A3>::ForwardType a3) const {
    243     CHECK(IsOnOwnerThread());
    244     if (!Get()) {
    245       return;
    246     }
    247     (Get().get()->*fn)(a1, a2, a3);
    248   }
    249 
    250   template <typename U, typename A1, typename A2, typename A3, typename A4>
    251   void DoCall4(void (U::*fn)(A1, A2, A3, A4),
    252                typename ParamTraits<A1>::ForwardType a1,
    253                typename ParamTraits<A2>::ForwardType a2,
    254                typename ParamTraits<A3>::ForwardType a3,
    255                typename ParamTraits<A4>::ForwardType a4) const {
    256     CHECK(IsOnOwnerThread());
    257     if (!Get()) {
    258       return;
    259     }
    260     (Get().get()->*fn)(a1, a2, a3, a4);
    261   }
    262 
    263   // Must be dereferenced only on the owner thread.  May be destroyed
    264   // from any thread.
    265   base::WeakPtr<T> ptr_;
    266 
    267   DISALLOW_COPY_AND_ASSIGN(WeakHandleCore);
    268 };
    269 
    270 }  // namespace internal
    271 
    272 // May be destroyed on any thread.
    273 // Copying and assignment are welcome.
    274 template <typename T>
    275 class WeakHandle {
    276  public:
    277   // Creates an uninitialized WeakHandle.
    278   WeakHandle() {}
    279 
    280   // Creates an initialized WeakHandle from |ptr|.
    281   explicit WeakHandle(const base::WeakPtr<T>& ptr)
    282       : core_(new internal::WeakHandleCore<T>(ptr)) {}
    283 
    284   // Allow conversion from WeakHandle<U> to WeakHandle<T> if U is
    285   // convertible to T, but we *must* be on |other|'s owner thread.
    286   // Note that this doesn't override the regular copy constructor, so
    287   // that one can be called on any thread.
    288   template <typename U>
    289   WeakHandle(const WeakHandle<U>& other)  // NOLINT
    290       : core_(
    291           other.IsInitialized() ?
    292           new internal::WeakHandleCore<T>(other.Get()) :
    293           NULL) {}
    294 
    295   // Returns true iff this WeakHandle is initialized.  Note that being
    296   // initialized isn't a guarantee that the underlying object is still
    297   // alive.
    298   bool IsInitialized() const {
    299     return core_.get() != NULL;
    300   }
    301 
    302   // Resets to an uninitialized WeakHandle.
    303   void Reset() {
    304     core_ = NULL;
    305   }
    306 
    307   // Must be called only on the underlying object's owner thread.
    308   base::WeakPtr<T> Get() const {
    309     CHECK(IsInitialized());
    310     CHECK(core_->IsOnOwnerThread());
    311     return core_->Get();
    312   }
    313 
    314   // Call(...) may be called on any thread, but all its arguments
    315   // should be safe to be bound and copied across threads.
    316 
    317   template <typename U>
    318   void Call(const tracked_objects::Location& from_here,
    319             void (U::*fn)(void)) const {
    320     CHECK(IsInitialized());
    321     core_->Call(from_here, fn);
    322   }
    323 
    324   template <typename U, typename A1>
    325   void Call(const tracked_objects::Location& from_here,
    326             void (U::*fn)(A1),
    327             typename internal::ParamTraits<A1>::ForwardType a1) const {
    328     CHECK(IsInitialized());
    329     core_->Call(from_here, fn, a1);
    330   }
    331 
    332   template <typename U, typename A1, typename A2>
    333   void Call(const tracked_objects::Location& from_here,
    334             void (U::*fn)(A1, A2),
    335             typename internal::ParamTraits<A1>::ForwardType a1,
    336             typename internal::ParamTraits<A2>::ForwardType a2) const {
    337     CHECK(IsInitialized());
    338     core_->Call(from_here, fn, a1, a2);
    339   }
    340 
    341   template <typename U, typename A1, typename A2, typename A3>
    342   void Call(const tracked_objects::Location& from_here,
    343             void (U::*fn)(A1, A2, A3),
    344             typename internal::ParamTraits<A1>::ForwardType a1,
    345             typename internal::ParamTraits<A2>::ForwardType a2,
    346             typename internal::ParamTraits<A3>::ForwardType a3) const {
    347     CHECK(IsInitialized());
    348     core_->Call(from_here, fn, a1, a2, a3);
    349   }
    350 
    351   template <typename U, typename A1, typename A2, typename A3, typename A4>
    352   void Call(const tracked_objects::Location& from_here,
    353             void (U::*fn)(A1, A2, A3, A4),
    354             typename internal::ParamTraits<A1>::ForwardType a1,
    355             typename internal::ParamTraits<A2>::ForwardType a2,
    356             typename internal::ParamTraits<A3>::ForwardType a3,
    357             typename internal::ParamTraits<A4>::ForwardType a4) const {
    358     CHECK(IsInitialized());
    359     core_->Call(from_here, fn, a1, a2, a3, a4);
    360   }
    361 
    362  private:
    363   FRIEND_TEST_ALL_PREFIXES(WeakHandleTest,
    364                            TypeConversionConstructor);
    365   FRIEND_TEST_ALL_PREFIXES(WeakHandleTest,
    366                            TypeConversionConstructorAssignment);
    367 
    368   scoped_refptr<internal::WeakHandleCore<T> > core_;
    369 };
    370 
    371 // Makes a WeakHandle from a WeakPtr.
    372 template <typename T>
    373 WeakHandle<T> MakeWeakHandle(const base::WeakPtr<T>& ptr) {
    374   return WeakHandle<T>(ptr);
    375 }
    376 
    377 }  // namespace syncer
    378 
    379 #endif  // SYNC_UTIL_WEAK_HANDLE_H_
    380