OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 CHROME_BROWSER_SYNC_UTIL_WEAK_HANDLE_H_ | |
48 #define CHROME_BROWSER_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 // CHROME_BROWSER_SYNC_UTIL_WEAK_HANDLE_H_ | |
OLD | NEW |