| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 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 #pragma once | |
| 50 | |
| 51 #include <cstddef> | |
| 52 | |
| 53 #include "base/basictypes.h" | |
| 54 #include "base/bind.h" | |
| 55 #include "base/callback_forward.h" | |
| 56 #include "base/compiler_specific.h" | |
| 57 #include "base/gtest_prod_util.h" | |
| 58 #include "base/location.h" | |
| 59 #include "base/logging.h" | |
| 60 #include "base/memory/ref_counted.h" | |
| 61 #include "base/memory/weak_ptr.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 browser_sync { | |
| 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 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()->*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()->*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()->*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()->*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()->*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 browser_sync::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 browser_sync | |
| 378 | |
| 379 #endif // SYNC_UTIL_WEAK_HANDLE_H_ | |
| OLD | NEW |