Chromium Code Reviews| 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 |