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_TRUE(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_TRUE(ptr.get() == NULL); |
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_TRUE(ptr.get() == NULL); |
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_TRUE(a.get() == NULL); |
175 EXPECT_TRUE(b.get() == NULL); | 179 EXPECT_TRUE(b.get() == NULL); |
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(a.get() != NULL); |
188 } | 192 } |
189 EXPECT_TRUE(a.get() == NULL); | 193 EXPECT_TRUE(a.get() == NULL); |
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 f; |
jar (doing other things)
2012/07/10 23:00:56
Sorry I didn't notice this before... (and this ex
kaiwang
2012/07/11 01:17:05
Done, for 169 and 183, it's just an int. So I thin
| |
202 WeakPtr<Producer> ptr = f.AsWeakPtr(); | 216 WeakPtr<Target> ptr = f.AsWeakPtr(); |
203 EXPECT_EQ(&f, ptr.get()); | 217 EXPECT_EQ(&f, ptr.get()); |
204 } | 218 } |
205 | 219 |
206 TEST(WeakPtrTest, DerivedProducer) { | 220 TEST(WeakPtrTest, DerivedTarget) { |
207 DerivedProducer f; | 221 DerivedTarget f; |
208 WeakPtr<DerivedProducer> ptr = AsWeakPtr(&f); | 222 WeakPtr<DerivedTarget> ptr = AsWeakPtr(&f); |
209 EXPECT_EQ(&f, ptr.get()); | 223 EXPECT_EQ(&f, 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_TRUE(ptr.get() == NULL); |
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 | |
245 // checks that ensure that a weak reference is not used by multiple threads. | |
246 scoped_ptr<Consumer> consumer(OffThreadObjectCreator<Consumer>::NewObject()); | |
247 Producer producer; | |
248 consumer->producer = producer.AsWeakPtr(); | |
249 EXPECT_EQ(&producer, consumer->producer.get()); | |
250 } | |
251 | |
252 TEST(WeakPtrTest, MoveOwnershipImplicit) { | |
253 // Move object ownership to other thread by releasing all weak pointers | 267 // Move object ownership to other thread by releasing all weak pointers |
254 // on the original thread first. Establishing weak pointers on a different | 268 // on the original thread first. Establishing weak pointers on a different |
255 // thread after previous pointers have been destroyed implicitly reattaches | 269 // thread after previous pointers have been destroyed implicitly reattaches |
256 // the thread checks. | 270 // the thread checks. |
257 // - Thread A creates object and weak pointer | 271 // - Main thread creates object and weak pointer |
258 // - Thread A deletes the weak pointer | 272 // - Main thread deletes the weak pointer, then the thread ownership of the |
259 // - Thread B creates weak pointer | 273 // object can be implicitly moved. |
260 // - Thread B derefs weak pointer | 274 // - Background thread creates weak pointer(and implicitly owns the object) |
261 // - Thread B deletes object | 275 // - Background thread derefs weak pointer |
262 BackgroundThread thread; | 276 // - Background thread deletes object |
263 thread.Start(); | 277 // - Background thread deletes weak pointer |
264 Producer* producer = new Producer(); | 278 BackgroundThread background; |
265 { | 279 background.Start(); |
266 WeakPtr<Producer> weak_ptr = producer->AsWeakPtr(); | 280 Target* target = new Target(); |
267 } | 281 { |
268 Consumer* consumer; | 282 WeakPtr<Target> weak_ptr = target->AsWeakPtr(); |
269 thread.CreateConsumerFromProducer(&consumer, producer); | 283 } |
270 EXPECT_EQ(thread.DeRef(consumer), producer); | 284 Arrow* arrow; |
271 thread.DeleteProducer(producer); | 285 background.CreateArrowFromTarget(&arrow, target); |
272 thread.DeleteConsumer(consumer); | 286 EXPECT_EQ(background.DeRef(arrow), target); |
273 } | 287 background.DeleteTarget(target); |
274 | 288 background.DeleteArrow(arrow); |
275 TEST(WeakPtrTest, MoveOwnershipExplicit) { | 289 } |
276 // Test that we do not trip any checks if we establish weak references | 290 |
277 // on one thread and delete the object on another thread after explicit | 291 TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) { |
278 // detachment. | 292 // Case 1: The target is not bound to any thread yet. So calling |
279 // - Thread A creates object | 293 // DetachFromThread() is a no-op. |
280 // - Thread B creates weak pointer | 294 Target target; |
281 // - Thread B releases weak pointer | 295 target.DetachFromThread(); |
282 // - Detach owner from Thread B | 296 |
283 // - Thread A destroys object | 297 // Case 2: The target is bound to main thread but no WeakPtr is pointing to |
284 BackgroundThread thread; | 298 // it. In this case, it will be re-bound to any thread trying to get a |
285 thread.Start(); | 299 // WeakPtr pointing to it. So detach function call is again no-op. |
286 Producer producer; | 300 { |
287 Consumer* consumer; | 301 WeakPtr<Target> weak_ptr = target.AsWeakPtr(); |
288 thread.CreateConsumerFromProducer(&consumer, &producer); | 302 } |
289 EXPECT_EQ(thread.DeRef(consumer), &producer); | 303 target.DetachFromThread(); |
290 thread.DeleteConsumer(consumer); | 304 } |
291 producer.DetachFromThread(); | 305 |
292 } | 306 TEST(WeakPtrTest, MoveOwnershipExplicitly) { |
293 | 307 // Test that we do not trip any checks if we establish WeakPtr on one thread |
294 TEST(WeakPtrTest, ThreadARefOutlivesThreadBRef) { | 308 // and delete the object on another thread after explicit detachment. |
309 // - Main thread creates object | |
310 // - Background thread creates weak pointer(and implicitly owns the object) | |
311 // - Object detach from background thread | |
312 // - Main thread destroys object | |
313 BackgroundThread background; | |
314 background.Start(); | |
315 Target target; | |
316 Arrow* arrow; | |
317 | |
318 background.CreateArrowFromTarget(&arrow, &target); | |
319 EXPECT_EQ(background.DeRef(arrow), &target); | |
320 target.DetachFromThread(); | |
321 // Detached target getting destructed will not cause thread ownership | |
322 // violation. | |
jar (doing other things)
2012/07/10 23:00:56
Will this leak arrow?
kaiwang
2012/07/11 01:17:05
Done.
| |
323 } | |
324 | |
325 TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) { | |
295 // Originating thread has a WeakPtr that outlives others. | 326 // Originating thread has a WeakPtr that outlives others. |
296 // - Thread A creates WeakPtr<> and passes copy to Thread B | 327 // - Main thread creates a WeakPtr |
297 // - Destruct the pointer on Thread B | 328 // - Background thread creates a WeakPtr copy from the one in main thread |
298 // - Destruct the pointer on Thread A | 329 // - Destruct the WeakPtr on background thread |
299 BackgroundThread thread; | 330 // - Destruct the WeakPtr on main thread |
300 thread.Start(); | 331 BackgroundThread background; |
301 Producer producer; | 332 background.Start(); |
302 Consumer consumer; | 333 |
303 consumer.producer = producer.AsWeakPtr(); | 334 Target target; |
304 Consumer* consumer_copy; | 335 Arrow arrow; |
305 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 336 arrow.target = target.AsWeakPtr(); |
306 EXPECT_EQ(consumer_copy->producer, &producer); | 337 |
307 thread.DeleteConsumer(consumer_copy); | 338 Arrow* arrow_copy; |
308 } | 339 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
309 | 340 EXPECT_EQ(arrow_copy->target, &target); |
310 TEST(WeakPtrTest, ThreadBRefOutlivesThreadARef) { | 341 background.DeleteArrow(arrow_copy); |
342 } | |
343 | |
344 TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) { | |
311 // Originating thread drops all references before another thread. | 345 // Originating thread drops all references before another thread. |
312 // - Thread A creates WeakPtr<> and passes copy to Thread B | 346 // - Main thread creates a WeakPtr and passes copy to background thread |
313 // - Destruct the pointer on Thread A | 347 // - Destruct the pointer on main thread |
314 // - Destruct the pointer on Thread B | 348 // - Destruct the pointer on background thread |
315 BackgroundThread thread; | 349 BackgroundThread background; |
316 thread.Start(); | 350 background.Start(); |
317 Producer producer; | 351 |
318 Consumer* consumer_copy; | 352 Target target; |
319 { | 353 Arrow* arrow_copy; |
320 Consumer consumer; | 354 { |
321 consumer.producer = producer.AsWeakPtr(); | 355 Arrow arrow; |
322 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 356 arrow.target = target.AsWeakPtr(); |
323 } | 357 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
324 EXPECT_EQ(consumer_copy->producer, &producer); | 358 } |
325 thread.DeleteConsumer(consumer_copy); | 359 EXPECT_EQ(arrow_copy->target, &target); |
360 background.DeleteArrow(arrow_copy); | |
326 } | 361 } |
327 | 362 |
328 TEST(WeakPtrTest, OwnerThreadDeletesObject) { | 363 TEST(WeakPtrTest, OwnerThreadDeletesObject) { |
329 // Originating thread invalidates WeakPtrs while its held by other thread. | 364 // Originating thread invalidates WeakPtrs while its held by other thread. |
330 // - Thread A creates WeakPtr<> and passes Copy to Thread B | 365 // - Main thread creates WeakPtr and passes Copy to background thread |
331 // - WeakReferenceOwner gets destroyed on Thread A | 366 // - Object gets destroyed on main thread |
367 // (invalidates WeakPtr on background thread) | |
332 // - WeakPtr gets destroyed on Thread B | 368 // - WeakPtr gets destroyed on Thread B |
333 BackgroundThread thread; | 369 BackgroundThread background; |
334 thread.Start(); | 370 background.Start(); |
335 Consumer* consumer_copy; | 371 Arrow* arrow_copy; |
336 { | 372 { |
337 Producer producer; | 373 Target target; |
338 Consumer consumer; | 374 Arrow arrow; |
339 consumer.producer = producer.AsWeakPtr(); | 375 arrow.target = target.AsWeakPtr(); |
340 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer); | 376 background.CreateArrowFromArrow(&arrow_copy, &arrow); |
341 } | 377 } |
342 EXPECT_TRUE(consumer_copy->producer == NULL); | 378 EXPECT_TRUE(arrow_copy->target == NULL); |
343 thread.DeleteConsumer(consumer_copy); | 379 background.DeleteArrow(arrow_copy); |
344 } | 380 } |
345 | 381 |
346 TEST(WeakPtrTest, Dereference) { | 382 TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) { |
347 Base data; | 383 // Main thread creates a Target object. |
348 data.member = "123456"; | 384 Target target; |
349 WeakPtrFactory<Base> factory(&data); | 385 // Main thread creates an arrow referencing the Target. |
350 WeakPtr<Base> ptr = factory.GetWeakPtr(); | 386 Arrow* arrow = new Arrow(); |
351 EXPECT_EQ(&data, ptr.get()); | 387 arrow->target = target.AsWeakPtr(); |
352 EXPECT_EQ(data.member, (*ptr).member); | 388 |
353 EXPECT_EQ(data.member, ptr->member); | 389 // Background can delete arrow (as well as the WeakPtr inside). |
354 } | 390 BackgroundThread background; |
391 background.Start(); | |
392 background.DeleteArrow(arrow); | |
393 } | |
394 | |
395 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) | |
396 | |
397 TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) { | |
398 // The default value "fast" can not well support multi-threaded tests | |
399 // (introduces deadlock on linux). | |
Ryan Sleevi
2012/07/10 22:41:54
nit:
s/can not well/does not/
s/linux/Linux/
Same
kaiwang
2012/07/11 01:17:05
Done.
| |
400 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; | |
401 | |
402 BackgroundThread background; | |
403 background.Start(); | |
404 | |
405 // Main thread creates a Target object. | |
406 Target target; | |
407 // Main thread creates an arrow referencing the Target. | |
408 Arrow arrow; | |
409 arrow.target = target.AsWeakPtr(); | |
410 | |
411 // Background copies the WeakPtr. | |
412 Arrow* arrow_copy; | |
413 background.CreateArrowFromArrow(&arrow_copy, &arrow); | |
Ryan Sleevi
2012/07/10 22:41:54
You're now leaking the arrow_copy, I believe. This
kaiwang
2012/07/11 01:17:05
since we are modifying the pointer in background t
| |
414 | |
415 // The copy is still bound to main thread so I can deref. | |
416 EXPECT_EQ(arrow.target.get(), arrow_copy->target.get()); | |
417 | |
418 // Although background thread created the copy, it can not deref the copied | |
419 // WeakPtr. | |
420 ASSERT_DEATH(background.DeRef(arrow_copy), ""); | |
421 } | |
422 | |
423 TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) { | |
424 // The default value "fast" can not well support multi-threaded tests | |
425 // (introduces deadlock on linux). | |
426 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; | |
427 | |
428 // Main thread creates a Target object. | |
429 Target target; | |
430 // Main thread creates an arrow referencing the Target (so target's | |
431 // thread ownership can not be implicitly moved). | |
432 Arrow arrow; | |
433 arrow.target = target.AsWeakPtr(); | |
434 | |
435 // Background thread tries to deref target, which violates thread ownership. | |
436 BackgroundThread background; | |
437 background.Start(); | |
438 ASSERT_DEATH(background.DeRef(&arrow), ""); | |
439 } | |
440 | |
441 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObject) { | |
442 // The default value "fast" can not well support multi-threaded tests | |
443 // (introduces deadlock on linux). | |
444 ::testing::FLAGS_gtest_death_test_style = "threadsafe"; | |
445 | |
446 scoped_ptr<Target> target(new Target()); | |
447 // Main thread creates an arrow referencing the Target (so target's thread | |
448 // ownership can not be implicitly moved). | |
449 Arrow arrow; | |
450 arrow.target = target->AsWeakPtr(); | |
451 | |
452 // Background thread tries to delete target, which violates thread ownership. | |
453 BackgroundThread background; | |
454 background.Start(); | |
455 ASSERT_DEATH(background.DeleteTarget(target.release()), ""); | |
456 } | |
457 | |
458 #endif | |
355 | 459 |
356 } // namespace base | 460 } // namespace base |
OLD | NEW |