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 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 |