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