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