OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/weak_ptr.h" | 5 #include "base/memory/weak_ptr.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 } | 30 } |
31 DCHECK(result); // We synchronized on thread destruction above. | 31 DCHECK(result); // We synchronized on thread destruction above. |
32 return result; | 32 return result; |
33 } | 33 } |
34 private: | 34 private: |
35 static void CreateObject(T** result) { | 35 static void CreateObject(T** result) { |
36 *result = new T; | 36 *result = new T; |
37 } | 37 } |
38 }; | 38 }; |
39 | 39 |
40 struct Base { std::string member; }; | 40 struct Base { |
| 41 std::string member; |
| 42 }; |
41 struct Derived : Base {}; | 43 struct Derived : Base {}; |
42 | 44 |
43 struct Producer : SupportsWeakPtr<Producer> {}; | 45 struct Target : SupportsWeakPtr<Target> {}; |
44 struct DerivedProducer : Producer {}; | 46 struct DerivedTarget : Target {}; |
45 struct Consumer { WeakPtr<Producer> producer; }; | 47 struct Arrow { |
| 48 WeakPtr<Target> target; |
| 49 }; |
46 | 50 |
47 // Helper class to create and destroy weak pointer copies | 51 // Helper class to create and destroy weak pointer copies |
48 // and delete objects on a background thread. | 52 // and delete objects on a background thread. |
49 class BackgroundThread : public Thread { | 53 class BackgroundThread : public Thread { |
50 public: | 54 public: |
51 BackgroundThread() : Thread("owner_thread") {} | 55 BackgroundThread() : Thread("owner_thread") {} |
52 | 56 |
53 virtual ~BackgroundThread() { | 57 virtual ~BackgroundThread() { |
54 Stop(); | 58 Stop(); |
55 } | 59 } |
56 | 60 |
57 void CreateConsumerFromProducer(Consumer** consumer, Producer* producer) { | 61 void CreateArrowFromTarget(Arrow** arrow, Target* target) { |
58 WaitableEvent completion(true, false); | 62 WaitableEvent completion(true, false); |
59 message_loop()->PostTask( | 63 message_loop()->PostTask( |
60 FROM_HERE, | 64 FROM_HERE, |
61 base::Bind(&BackgroundThread::DoCreateFromProducer, consumer, producer, | 65 base::Bind(&BackgroundThread::DoCreateArrowFromTarget, |
62 &completion)); | 66 arrow, target, &completion)); |
63 completion.Wait(); | 67 completion.Wait(); |
64 } | 68 } |
65 | 69 |
66 void CreateConsumerFromConsumer(Consumer** consumer, const Consumer* other) { | 70 void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) { |
67 WaitableEvent completion(true, false); | 71 WaitableEvent completion(true, false); |
68 message_loop()->PostTask( | 72 message_loop()->PostTask( |
69 FROM_HERE, | 73 FROM_HERE, |
70 base::Bind(&BackgroundThread::DoCreateFromConsumer, consumer, other, | 74 base::Bind(&BackgroundThread::DoCreateArrowFromArrow, |
71 &completion)); | 75 arrow, other, &completion)); |
72 completion.Wait(); | 76 completion.Wait(); |
73 } | 77 } |
74 | 78 |
75 void DeleteProducer(Producer* object) { | 79 void DeleteTarget(Target* object) { |
76 WaitableEvent completion(true, false); | 80 WaitableEvent completion(true, false); |
77 message_loop()->PostTask( | 81 message_loop()->PostTask( |
78 FROM_HERE, | 82 FROM_HERE, |
79 base::Bind(&BackgroundThread::DoDeleteProducer, object, &completion)); | 83 base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion)); |
80 completion.Wait(); | 84 completion.Wait(); |
81 } | 85 } |
82 | 86 |
83 void DeleteConsumer(Consumer* object) { | 87 void DeleteArrow(Arrow* object) { |
84 WaitableEvent completion(true, false); | 88 WaitableEvent completion(true, false); |
85 message_loop()->PostTask( | 89 message_loop()->PostTask( |
86 FROM_HERE, | 90 FROM_HERE, |
87 base::Bind(&BackgroundThread::DoDeleteConsumer, object, &completion)); | 91 base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion)); |
88 completion.Wait(); | 92 completion.Wait(); |
89 } | 93 } |
90 | 94 |
91 Producer* DeRef(const Consumer* consumer) { | 95 Target* DeRef(const Arrow* arrow) { |
92 WaitableEvent completion(true, false); | 96 WaitableEvent completion(true, false); |
93 Producer* result = NULL; | 97 Target* result = NULL; |
94 message_loop()->PostTask( | 98 message_loop()->PostTask( |
95 FROM_HERE, | 99 FROM_HERE, |
96 base::Bind(&BackgroundThread::DoDeRef, consumer, &result, &completion)); | 100 base::Bind(&BackgroundThread::DoDeRef, arrow, &result, &completion)); |
97 completion.Wait(); | 101 completion.Wait(); |
98 return result; | 102 return result; |
99 } | 103 } |
100 | 104 |
101 protected: | 105 protected: |
102 static void DoCreateFromConsumer(Consumer** consumer, | 106 static void DoCreateArrowFromArrow(Arrow** arrow, |
103 const Consumer* other, | 107 const Arrow* other, |
104 WaitableEvent* completion) { | 108 WaitableEvent* completion) { |
105 *consumer = new Consumer; | 109 *arrow = new Arrow; |
106 **consumer = *other; | 110 **arrow = *other; |
107 completion->Signal(); | 111 completion->Signal(); |
108 } | 112 } |
109 | 113 |
110 static void DoCreateFromProducer(Consumer** consumer, | 114 static void DoCreateArrowFromTarget(Arrow** arrow, |
111 Producer* producer, | 115 Target* target, |
112 WaitableEvent* completion) { | 116 WaitableEvent* completion) { |
113 *consumer = new Consumer; | 117 *arrow = new Arrow; |
114 (*consumer)->producer = producer->AsWeakPtr(); | 118 (*arrow)->target = target->AsWeakPtr(); |
115 completion->Signal(); | 119 completion->Signal(); |
116 } | 120 } |
117 | 121 |
118 static void DoDeRef(const Consumer* consumer, | 122 static void DoDeRef(const Arrow* arrow, |
119 Producer** result, | 123 Target** result, |
120 WaitableEvent* completion) { | 124 WaitableEvent* completion) { |
121 *result = consumer->producer.get(); | 125 *result = arrow->target.get(); |
122 completion->Signal(); | 126 completion->Signal(); |
123 } | 127 } |
124 | 128 |
125 static void DoDeleteProducer(Producer* object, WaitableEvent* completion) { | 129 static void DoDeleteTarget(Target* object, WaitableEvent* completion) { |
126 delete object; | 130 delete object; |
127 completion->Signal(); | 131 completion->Signal(); |
128 } | 132 } |
129 | 133 |
130 static void DoDeleteConsumer(Consumer* object, WaitableEvent* completion) { | 134 static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) { |
131 delete object; | 135 delete object; |
132 completion->Signal(); | 136 completion->Signal(); |
133 } | 137 } |
134 }; | 138 }; |
135 | 139 |
136 } // namespace | 140 } // namespace |
137 | 141 |
138 TEST(WeakPtrTest, Basic) { | 142 TEST(WeakPtrFactoryTest, Basic) { |
139 int data; | 143 int data; |
140 WeakPtrFactory<int> factory(&data); | 144 WeakPtrFactory<int> factory(&data); |
141 WeakPtr<int> ptr = factory.GetWeakPtr(); | 145 WeakPtr<int> ptr = factory.GetWeakPtr(); |
142 EXPECT_EQ(&data, ptr.get()); | 146 EXPECT_EQ(&data, ptr.get()); |
143 } | 147 } |
144 | 148 |
145 TEST(WeakPtrTest, Comparison) { | 149 TEST(WeakPtrFactoryTest, Comparison) { |
146 int data; | 150 int data; |
147 WeakPtrFactory<int> factory(&data); | 151 WeakPtrFactory<int> factory(&data); |
148 WeakPtr<int> ptr = factory.GetWeakPtr(); | 152 WeakPtr<int> ptr = factory.GetWeakPtr(); |
149 WeakPtr<int> ptr2 = ptr; | 153 WeakPtr<int> ptr2 = ptr; |
150 EXPECT_TRUE(ptr == ptr2); | 154 EXPECT_EQ(ptr, ptr2); |
151 } | 155 } |
152 | 156 |
153 TEST(WeakPtrTest, OutOfScope) { | 157 TEST(WeakPtrFactoryTest, OutOfScope) { |
154 WeakPtr<int> ptr; | 158 WeakPtr<int> ptr; |
155 EXPECT_TRUE(ptr.get() == NULL); | 159 EXPECT_EQ(NULL, ptr.get()); |
156 { | 160 { |
157 int data; | 161 int data; |
158 WeakPtrFactory<int> factory(&data); | 162 WeakPtrFactory<int> factory(&data); |
159 ptr = factory.GetWeakPtr(); | 163 ptr = factory.GetWeakPtr(); |
160 } | 164 } |
161 EXPECT_TRUE(ptr.get() == NULL); | 165 EXPECT_EQ(NULL, ptr.get()); |
162 } | 166 } |
163 | 167 |
164 TEST(WeakPtrTest, Multiple) { | 168 TEST(WeakPtrFactoryTest, Multiple) { |
165 WeakPtr<int> a, b; | 169 WeakPtr<int> a, b; |
166 { | 170 { |
167 int data; | 171 int data; |
168 WeakPtrFactory<int> factory(&data); | 172 WeakPtrFactory<int> factory(&data); |
169 a = factory.GetWeakPtr(); | 173 a = factory.GetWeakPtr(); |
170 b = factory.GetWeakPtr(); | 174 b = factory.GetWeakPtr(); |
171 EXPECT_EQ(&data, a.get()); | 175 EXPECT_EQ(&data, a.get()); |
172 EXPECT_EQ(&data, b.get()); | 176 EXPECT_EQ(&data, b.get()); |
173 } | 177 } |
174 EXPECT_TRUE(a.get() == NULL); | 178 EXPECT_EQ(NULL, a.get()); |
175 EXPECT_TRUE(b.get() == NULL); | 179 EXPECT_EQ(NULL, b.get()); |
176 } | 180 } |
177 | 181 |
178 TEST(WeakPtrTest, MultipleStaged) { | 182 TEST(WeakPtrFactoryTest, MultipleStaged) { |
179 WeakPtr<int> a; | 183 WeakPtr<int> a; |
180 { | 184 { |
181 int data; | 185 int data; |
182 WeakPtrFactory<int> factory(&data); | 186 WeakPtrFactory<int> factory(&data); |
183 a = factory.GetWeakPtr(); | 187 a = factory.GetWeakPtr(); |
184 { | 188 { |
185 WeakPtr<int> b = factory.GetWeakPtr(); | 189 WeakPtr<int> b = factory.GetWeakPtr(); |
186 } | 190 } |
187 EXPECT_TRUE(a.get() != NULL); | 191 EXPECT_TRUE(NULL != a.get()); |
188 } | 192 } |
189 EXPECT_TRUE(a.get() == NULL); | 193 EXPECT_EQ(NULL, a.get()); |
190 } | 194 } |
191 | 195 |
192 TEST(WeakPtrTest, UpCast) { | 196 TEST(WeakPtrFactoryTest, Dereference) { |
| 197 Base data; |
| 198 data.member = "123456"; |
| 199 WeakPtrFactory<Base> factory(&data); |
| 200 WeakPtr<Base> ptr = factory.GetWeakPtr(); |
| 201 EXPECT_EQ(&data, ptr.get()); |
| 202 EXPECT_EQ(data.member, (*ptr).member); |
| 203 EXPECT_EQ(data.member, ptr->member); |
| 204 } |
| 205 |
| 206 TEST(WeakPtrFactoryTest, UpCast) { |
193 Derived data; | 207 Derived data; |
194 WeakPtrFactory<Derived> factory(&data); | 208 WeakPtrFactory<Derived> factory(&data); |
195 WeakPtr<Base> ptr = factory.GetWeakPtr(); | 209 WeakPtr<Base> ptr = factory.GetWeakPtr(); |
196 ptr = factory.GetWeakPtr(); | 210 ptr = factory.GetWeakPtr(); |
197 EXPECT_EQ(ptr.get(), &data); | 211 EXPECT_EQ(ptr.get(), &data); |
198 } | 212 } |
199 | 213 |
200 TEST(WeakPtrTest, SupportsWeakPtr) { | 214 TEST(WeakPtrTest, SupportsWeakPtr) { |
201 Producer f; | 215 Target target; |
202 WeakPtr<Producer> ptr = f.AsWeakPtr(); | 216 WeakPtr<Target> ptr = target.AsWeakPtr(); |
203 EXPECT_EQ(&f, ptr.get()); | 217 EXPECT_EQ(&target, ptr.get()); |
204 } | 218 } |
205 | 219 |
206 TEST(WeakPtrTest, DerivedProducer) { | 220 TEST(WeakPtrTest, DerivedTarget) { |
207 DerivedProducer f; | 221 DerivedTarget target; |
208 WeakPtr<DerivedProducer> ptr = AsWeakPtr(&f); | 222 WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target); |
209 EXPECT_EQ(&f, ptr.get()); | 223 EXPECT_EQ(&target, ptr.get()); |
210 } | 224 } |
211 | 225 |
212 TEST(WeakPtrTest, InvalidateWeakPtrs) { | 226 TEST(WeakPtrTest, InvalidateWeakPtrs) { |
213 int data; | 227 int data; |
214 WeakPtrFactory<int> factory(&data); | 228 WeakPtrFactory<int> factory(&data); |
215 WeakPtr<int> ptr = factory.GetWeakPtr(); | 229 WeakPtr<int> ptr = factory.GetWeakPtr(); |
216 EXPECT_EQ(&data, ptr.get()); | 230 EXPECT_EQ(&data, ptr.get()); |
217 EXPECT_TRUE(factory.HasWeakPtrs()); | 231 EXPECT_TRUE(factory.HasWeakPtrs()); |
218 factory.InvalidateWeakPtrs(); | 232 factory.InvalidateWeakPtrs(); |
219 EXPECT_TRUE(ptr.get() == NULL); | 233 EXPECT_EQ(NULL, ptr.get()); |
220 EXPECT_FALSE(factory.HasWeakPtrs()); | 234 EXPECT_FALSE(factory.HasWeakPtrs()); |
221 } | 235 } |
222 | 236 |
223 TEST(WeakPtrTest, HasWeakPtrs) { | 237 TEST(WeakPtrTest, HasWeakPtrs) { |
224 int data; | 238 int data; |
225 WeakPtrFactory<int> factory(&data); | 239 WeakPtrFactory<int> factory(&data); |
226 { | 240 { |
227 WeakPtr<int> ptr = factory.GetWeakPtr(); | 241 WeakPtr<int> ptr = factory.GetWeakPtr(); |
228 EXPECT_TRUE(factory.HasWeakPtrs()); | 242 EXPECT_TRUE(factory.HasWeakPtrs()); |
229 } | 243 } |
230 EXPECT_FALSE(factory.HasWeakPtrs()); | 244 EXPECT_FALSE(factory.HasWeakPtrs()); |
231 } | 245 } |
232 | 246 |
233 TEST(WeakPtrTest, SingleThreaded1) { | 247 TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) { |
234 // Test that it is OK to create a class that supports weak references on one | 248 // Test that it is OK to create an object that supports WeakPtr on one thread, |
| 249 // but use it on another. This tests that we do not trip runtime checks that |
| 250 // ensure that a WeakPtr is not used by multiple threads. |
| 251 scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject()); |
| 252 WeakPtr<Target> weak_ptr = target->AsWeakPtr(); |
| 253 EXPECT_EQ(target.get(), weak_ptr.get()); |
| 254 } |
| 255 |
| 256 TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) { |
| 257 // Test that it is OK to create an object that has a WeakPtr member on one |
235 // thread, but use it on another. This tests that we do not trip runtime | 258 // thread, but use it on another. This tests that we do not trip runtime |
236 // checks that ensure that a weak reference is not used by multiple threads. | 259 // checks that ensure that a WeakPtr is not used by multiple threads. |
237 scoped_ptr<Producer> producer(OffThreadObjectCreator<Producer>::NewObject()); | 260 scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject()); |
238 WeakPtr<Producer> weak_producer = producer->AsWeakPtr(); | 261 Target target; |
239 EXPECT_EQ(producer.get(), weak_producer.get()); | 262 arrow->target = target.AsWeakPtr(); |
240 } | 263 EXPECT_EQ(&target, arrow->target.get()); |
241 | 264 } |
242 TEST(WeakPtrTest, SingleThreaded2) { | 265 |
243 // Test that it is OK to create a class that has a WeakPtr member on one | 266 TEST(WeakPtrTest, MoveOwnershipImplicitly) { |
244 // thread, but use it on another. This tests that we do not trip runtime | 267 // Move object ownership to another thread by releasing all weak pointers |
245 // checks that ensure that a weak reference is not used by multiple threads. | 268 // on the original thread first, and then establish WeakPtr on a different |
246 scoped_ptr<Consumer> consumer(OffThreadObjectCreator<Consumer>::NewObject()); | 269 // thread. |
247 Producer producer; | 270 BackgroundThread background; |
248 consumer->producer = producer.AsWeakPtr(); | 271 background.Start(); |
249 EXPECT_EQ(&producer, consumer->producer.get()); | 272 |
250 } | 273 Target* target = new Target(); |
251 | 274 { |
252 TEST(WeakPtrTest, MoveOwnershipImplicit) { | 275 WeakPtr<Target> weak_ptr = target->AsWeakPtr(); |
253 // Move object ownership to other thread by releasing all weak pointers | 276 // Main thread deletes the WeakPtr, then the thread ownership of the |
254 // on the original thread first. Establishing weak pointers on a different | 277 // object can be implicitly moved. |
255 // thread after previous pointers have been destroyed implicitly reattaches | 278 } |
256 // the thread checks. | 279 Arrow* arrow; |
257 // - Thread A creates object and weak pointer | 280 |
258 // - Thread A deletes the weak pointer | 281 // Background thread creates WeakPtr(and implicitly owns the object). |
259 // - Thread B creates weak pointer | 282 background.CreateArrowFromTarget(&arrow, target); |
260 // - Thread B derefs weak pointer | 283 EXPECT_EQ(background.DeRef(arrow), target); |
261 // - Thread B deletes object | 284 |
262 BackgroundThread thread; | 285 { |
263 thread.Start(); | 286 // Main thread creates another WeakPtr, but this does not trigger implicitly |
264 Producer* producer = new Producer(); | 287 // thread ownership move. |
265 { | 288 Arrow arrow; |
266 WeakPtr<Producer> weak_ptr = producer->AsWeakPtr(); | 289 arrow.target = target->AsWeakPtr(); |
267 } | 290 |
268 Consumer* consumer; | 291 // The new WeakPtr is owned by background thread. |
269 thread.CreateConsumerFromProducer(&consumer, producer); | 292 EXPECT_EQ(target, background.DeRef(&arrow)); |
270 EXPECT_EQ(thread.DeRef(consumer), producer); | 293 } |
271 thread.DeleteProducer(producer); | 294 |
272 thread.DeleteConsumer(consumer); | 295 // Target can only be deleted on background thread. |
273 } | 296 background.DeleteTarget(target); |
274 | 297 background.DeleteArrow(arrow); |
275 TEST(WeakPtrTest, MoveOwnershipExplicit) { | 298 } |
276 // Test that we do not trip any checks if we establish weak references | 299 |
277 // on one thread and delete the object on another thread after explicit | 300 TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) { |
278 // detachment. | 301 // Case 1: The target is not bound to any thread yet. So calling |
279 // - Thread A creates object | 302 // DetachFromThread() is a no-op. |
280 // - Thread B creates weak pointer | 303 Target target; |
281 // - Thread B releases weak pointer | 304 target.DetachFromThread(); |
282 // - Detach owner from Thread B | 305 |
283 // - Thread A destroys object | 306 // Case 2: The target is bound to main thread but no WeakPtr is pointing to |
284 BackgroundThread thread; | 307 // it. In this case, it will be re-bound to any thread trying to get a |
285 thread.Start(); | 308 // WeakPtr pointing to it. So detach function call is again no-op. |
286 Producer producer; | 309 { |
287 Consumer* consumer; | 310 WeakPtr<Target> weak_ptr = target.AsWeakPtr(); |
288 thread.CreateConsumerFromProducer(&consumer, &producer); | 311 } |
289 EXPECT_EQ(thread.DeRef(consumer), &producer); | 312 target.DetachFromThread(); |
290 thread.DeleteConsumer(consumer); | 313 } |
291 producer.DetachFromThread(); | 314 |
292 } | 315 TEST(WeakPtrTest, MoveOwnershipExplicitly) { |
293 | 316 BackgroundThread background; |
294 TEST(WeakPtrTest, ThreadARefOutlivesThreadBRef) { | 317 background.Start(); |
| 318 |
| 319 Arrow* arrow; |
| 320 { |
| 321 Target target; |
| 322 // Background thread creates WeakPtr(and implicitly owns the object). |
| 323 background.CreateArrowFromTarget(&arrow, &target); |
| 324 EXPECT_EQ(&target, background.DeRef(arrow)); |
| 325 |
| 326 // Detach from background thread. |
| 327 target.DetachFromThread(); |
| 328 |
| 329 // Re-bind to main thread. |
| 330 EXPECT_EQ(&target, arrow->target.get()); |
| 331 |
| 332 // Main thread can now delete the target. |
| 333 } |
| 334 |
| 335 // WeakPtr can be deleted on non-owner thread. |
| 336 background.DeleteArrow(arrow); |
| 337 } |
| 338 |
| 339 TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) { |
295 // Originating thread has a WeakPtr that outlives others. | 340 // Originating thread has a WeakPtr that outlives others. |
296 // - Thread A creates WeakPtr<> and passes copy to Thread B | 341 // - Main thread creates a WeakPtr |
297 // - Destruct the pointer on Thread B | 342 // - Background thread creates a WeakPtr copy from the one in main thread |
298 // - Destruct the pointer on Thread A | 343 // - Destruct the WeakPtr on background thread |
299 BackgroundThread thread; | 344 // - Destruct the WeakPtr on main thread |
300 thread.Start(); | 345 BackgroundThread background; |
301 Producer producer; | 346 background.Start(); |
302 Consumer consumer; | 347 |
303 consumer.producer = producer.AsWeakPtr(); | 348 Target target; |
304 Consumer* consumer_copy; | 349 Arrow arrow; |
305 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 350 arrow.target = target.AsWeakPtr(); |
306 EXPECT_EQ(consumer_copy->producer, &producer); | 351 |
307 thread.DeleteConsumer(consumer_copy); | 352 Arrow* arrow_copy; |
308 } | 353 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
309 | 354 EXPECT_EQ(arrow_copy->target, &target); |
310 TEST(WeakPtrTest, ThreadBRefOutlivesThreadARef) { | 355 background.DeleteArrow(arrow_copy); |
| 356 } |
| 357 |
| 358 TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) { |
311 // Originating thread drops all references before another thread. | 359 // Originating thread drops all references before another thread. |
312 // - Thread A creates WeakPtr<> and passes copy to Thread B | 360 // - Main thread creates a WeakPtr and passes copy to background thread |
313 // - Destruct the pointer on Thread A | 361 // - Destruct the pointer on main thread |
314 // - Destruct the pointer on Thread B | 362 // - Destruct the pointer on background thread |
315 BackgroundThread thread; | 363 BackgroundThread background; |
316 thread.Start(); | 364 background.Start(); |
317 Producer producer; | 365 |
318 Consumer* consumer_copy; | 366 Target target; |
319 { | 367 Arrow* arrow_copy; |
320 Consumer consumer; | 368 { |
321 consumer.producer = producer.AsWeakPtr(); | 369 Arrow arrow; |
322 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 370 arrow.target = target.AsWeakPtr(); |
323 } | 371 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
324 EXPECT_EQ(consumer_copy->producer, &producer); | 372 } |
325 thread.DeleteConsumer(consumer_copy); | 373 EXPECT_EQ(arrow_copy->target, &target); |
| 374 background.DeleteArrow(arrow_copy); |
326 } | 375 } |
327 | 376 |
328 TEST(WeakPtrTest, OwnerThreadDeletesObject) { | 377 TEST(WeakPtrTest, OwnerThreadDeletesObject) { |
329 // Originating thread invalidates WeakPtrs while its held by other thread. | 378 // Originating thread invalidates WeakPtrs while its held by other thread. |
330 // - Thread A creates WeakPtr<> and passes Copy to Thread B | 379 // - Main thread creates WeakPtr and passes Copy to background thread |
331 // - WeakReferenceOwner gets destroyed on Thread A | 380 // - Object gets destroyed on main thread |
| 381 // (invalidates WeakPtr on background thread) |
332 // - WeakPtr gets destroyed on Thread B | 382 // - WeakPtr gets destroyed on Thread B |
333 BackgroundThread thread; | 383 BackgroundThread background; |
334 thread.Start(); | 384 background.Start(); |
335 Consumer* consumer_copy; | 385 Arrow* arrow_copy; |
336 { | 386 { |
337 Producer producer; | 387 Target target; |
338 Consumer consumer; | 388 Arrow arrow; |
339 consumer.producer = producer.AsWeakPtr(); | 389 arrow.target = target.AsWeakPtr(); |
340 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 390 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
341 } | 391 } |
342 EXPECT_TRUE(consumer_copy->producer == NULL); | 392 EXPECT_EQ(NULL, arrow_copy->target.get()); |
343 thread.DeleteConsumer(consumer_copy); | 393 background.DeleteArrow(arrow_copy); |
344 } | 394 } |
345 | 395 |
346 TEST(WeakPtrTest, Dereference) { | 396 TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) { |
347 Base data; | 397 // Main thread creates a Target object. |
348 data.member = "123456"; | 398 Target target; |
349 WeakPtrFactory<Base> factory(&data); | 399 // Main thread creates an arrow referencing the Target. |
350 WeakPtr<Base> ptr = factory.GetWeakPtr(); | 400 Arrow* arrow = new Arrow(); |
351 EXPECT_EQ(&data, ptr.get()); | 401 arrow->target = target.AsWeakPtr(); |
352 EXPECT_EQ(data.member, (*ptr).member); | 402 |
353 EXPECT_EQ(data.member, ptr->member); | 403 // Background can delete arrow (as well as the WeakPtr inside). |
354 } | 404 BackgroundThread background; |
| 405 background.Start(); |
| 406 background.DeleteArrow(arrow); |
| 407 } |
| 408 |
| 409 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST |
| 410 |
| 411 TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) { |
| 412 // The default style "fast" does not support multi-threaded tests |
| 413 // (introduces deadlock on Linux). |
| 414 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| 415 |
| 416 BackgroundThread background; |
| 417 background.Start(); |
| 418 |
| 419 // Main thread creates a Target object. |
| 420 Target target; |
| 421 // Main thread creates an arrow referencing the Target. |
| 422 Arrow arrow; |
| 423 arrow.target = target.AsWeakPtr(); |
| 424 |
| 425 // Background copies the WeakPtr. |
| 426 Arrow* arrow_copy; |
| 427 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
| 428 |
| 429 // The copy is still bound to main thread so I can deref. |
| 430 EXPECT_EQ(arrow.target.get(), arrow_copy->target.get()); |
| 431 |
| 432 // Although background thread created the copy, it can not deref the copied |
| 433 // WeakPtr. |
| 434 ASSERT_DEATH(background.DeRef(arrow_copy), ""); |
| 435 |
| 436 background.DeleteArrow(arrow_copy); |
| 437 } |
| 438 |
| 439 TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) { |
| 440 // The default style "fast" does not support multi-threaded tests |
| 441 // (introduces deadlock on Linux). |
| 442 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| 443 |
| 444 // Main thread creates a Target object. |
| 445 Target target; |
| 446 |
| 447 // Main thread creates an arrow referencing the Target (so target's |
| 448 // thread ownership can not be implicitly moved). |
| 449 Arrow arrow; |
| 450 arrow.target = target.AsWeakPtr(); |
| 451 |
| 452 // Background thread tries to deref target, which violates thread ownership. |
| 453 BackgroundThread background; |
| 454 background.Start(); |
| 455 ASSERT_DEATH(background.DeRef(&arrow), ""); |
| 456 } |
| 457 |
| 458 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObject) { |
| 459 // The default style "fast" does not support multi-threaded tests |
| 460 // (introduces deadlock on Linux). |
| 461 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| 462 |
| 463 scoped_ptr<Target> target(new Target()); |
| 464 // Main thread creates an arrow referencing the Target (so target's thread |
| 465 // ownership can not be implicitly moved). |
| 466 Arrow arrow; |
| 467 arrow.target = target->AsWeakPtr(); |
| 468 |
| 469 // Background thread tries to delete target, which violates thread ownership. |
| 470 BackgroundThread background; |
| 471 background.Start(); |
| 472 ASSERT_DEATH(background.DeleteTarget(target.release()), ""); |
| 473 } |
| 474 |
| 475 #endif |
355 | 476 |
356 } // namespace base | 477 } // namespace base |
OLD | NEW |