blob: c244ec05ab516fd7db1ecfe42ea4cf5b780121cb [file] [log] [blame]
[email protected]3b63f8f42011-03-28 01:54:151// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]3125d6462009-09-01 20:50:172// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]3b63f8f42011-03-28 01:54:155#include "base/memory/scoped_ptr.h"
6#include "base/memory/weak_ptr.h"
[email protected]3125d6462009-09-01 20:50:177#include "testing/gtest/include/gtest/gtest.h"
[email protected]d9b14782010-04-15 08:08:078#include "base/message_loop.h"
[email protected]1edefc42011-08-26 17:32:299#include "base/synchronization/waitable_event.h"
[email protected]34b99632011-01-01 01:01:0610#include "base/threading/thread.h"
[email protected]3125d6462009-09-01 20:50:1711
12namespace base {
13namespace {
14
15template <class T>
16class OffThreadObjectCreator {
17 public:
18 static T* NewObject() {
19 T* result;
20 {
21 Thread creator_thread("creator_thread");
22 creator_thread.Start();
[email protected]0586b0e2010-02-12 21:38:3723 creator_thread.message_loop()->PostTask(
24 FROM_HERE,
[email protected]3125d6462009-09-01 20:50:1725 NewRunnableFunction(OffThreadObjectCreator::CreateObject, &result));
26 }
27 DCHECK(result); // We synchronized on thread destruction above.
28 return result;
29 }
30 private:
31 static void CreateObject(T** result) {
32 *result = new T;
33 }
34};
35
36struct Base {};
37struct Derived : Base {};
38
39struct Producer : SupportsWeakPtr<Producer> {};
40struct Consumer { WeakPtr<Producer> producer; };
41
[email protected]1edefc42011-08-26 17:32:2942// Helper class to create and destroy weak pointer copies
43// and delete objects on a background thread.
44class BackgroundThread : public Thread {
45 public:
46 BackgroundThread()
47 : Thread("owner_thread") {
48 }
49
50 void CreateConsumerFromProducer(Consumer** consumer, Producer* producer) {
51 WaitableEvent completion(true, false);
52 message_loop()->PostTask(
53 FROM_HERE,
54 NewRunnableFunction(&BackgroundThread::DoCreateFromProducer,
55 consumer,
56 producer,
57 &completion));
58 completion.Wait();
59 }
60
61 void CreateConsumerFromConsumer(Consumer** consumer, const Consumer* other) {
62 WaitableEvent completion(true, false);
63 message_loop()->PostTask(
64 FROM_HERE,
65 NewRunnableFunction(&BackgroundThread::DoCreateFromConsumer,
66 consumer,
67 other,
68 &completion));
69 completion.Wait();
70 }
71
72 void DeleteProducer(Producer* object) {
73 WaitableEvent completion(true, false);
74 message_loop()->PostTask(
75 FROM_HERE,
76 NewRunnableFunction(&BackgroundThread::DoDeleteProducer,
77 object,
78 &completion));
79 completion.Wait();
80 }
81
82 void DeleteConsumer(Consumer* object) {
83 WaitableEvent completion(true, false);
84 message_loop()->PostTask(
85 FROM_HERE,
86 NewRunnableFunction(&BackgroundThread::DoDeleteConsumer,
87 object,
88 &completion));
89 completion.Wait();
90 }
91
92 Producer* DeRef(const Consumer* consumer) {
93 WaitableEvent completion(true, false);
94 Producer* result = NULL;
95 message_loop()->PostTask(
96 FROM_HERE,
97 NewRunnableFunction(&BackgroundThread::DoDeRef,
98 consumer,
99 &result,
100 &completion));
101 completion.Wait();
102 return result;
103 }
104
105 protected:
106 static void DoCreateFromConsumer(Consumer** consumer,
107 const Consumer* other,
108 WaitableEvent* completion) {
109 *consumer = new Consumer;
110 **consumer = *other;
111 completion->Signal();
112 }
113
114 static void DoCreateFromProducer(Consumer** consumer,
115 Producer* producer,
116 WaitableEvent* completion) {
117 *consumer = new Consumer;
118 (*consumer)->producer = producer->AsWeakPtr();
119 completion->Signal();
120 }
121
122 static void DoDeRef(const Consumer* consumer,
123 Producer** result,
124 WaitableEvent* completion) {
125 *result = consumer->producer.get();
126 completion->Signal();
127 }
128
129 static void DoDeleteProducer(Producer* object, WaitableEvent* completion) {
130 delete object;
131 completion->Signal();
132 }
133
134 static void DoDeleteConsumer(Consumer* object, WaitableEvent* completion) {
135 delete object;
136 completion->Signal();
137 }
138};
139
[email protected]3125d6462009-09-01 20:50:17140} // namespace
141
142TEST(WeakPtrTest, Basic) {
143 int data;
144 WeakPtrFactory<int> factory(&data);
145 WeakPtr<int> ptr = factory.GetWeakPtr();
146 EXPECT_EQ(&data, ptr.get());
147}
148
149TEST(WeakPtrTest, Comparison) {
150 int data;
151 WeakPtrFactory<int> factory(&data);
152 WeakPtr<int> ptr = factory.GetWeakPtr();
153 WeakPtr<int> ptr2 = ptr;
154 EXPECT_TRUE(ptr == ptr2);
155}
156
157TEST(WeakPtrTest, OutOfScope) {
158 WeakPtr<int> ptr;
[email protected]9b6fee12009-09-29 18:13:07159 EXPECT_TRUE(ptr.get() == NULL);
[email protected]3125d6462009-09-01 20:50:17160 {
161 int data;
162 WeakPtrFactory<int> factory(&data);
163 ptr = factory.GetWeakPtr();
164 }
[email protected]9b6fee12009-09-29 18:13:07165 EXPECT_TRUE(ptr.get() == NULL);
[email protected]3125d6462009-09-01 20:50:17166}
167
168TEST(WeakPtrTest, Multiple) {
169 WeakPtr<int> a, b;
170 {
171 int data;
172 WeakPtrFactory<int> factory(&data);
173 a = factory.GetWeakPtr();
174 b = factory.GetWeakPtr();
175 EXPECT_EQ(&data, a.get());
176 EXPECT_EQ(&data, b.get());
177 }
[email protected]9b6fee12009-09-29 18:13:07178 EXPECT_TRUE(a.get() == NULL);
179 EXPECT_TRUE(b.get() == NULL);
[email protected]3125d6462009-09-01 20:50:17180}
181
[email protected]09733b452011-05-24 23:49:07182TEST(WeakPtrTest, MultipleStaged) {
183 WeakPtr<int> a;
184 {
185 int data;
186 WeakPtrFactory<int> factory(&data);
187 a = factory.GetWeakPtr();
188 {
189 WeakPtr<int> b = factory.GetWeakPtr();
190 }
191 EXPECT_TRUE(a.get() != NULL);
192 }
193 EXPECT_TRUE(a.get() == NULL);
194}
195
[email protected]3125d6462009-09-01 20:50:17196TEST(WeakPtrTest, UpCast) {
197 Derived data;
198 WeakPtrFactory<Derived> factory(&data);
199 WeakPtr<Base> ptr = factory.GetWeakPtr();
200 ptr = factory.GetWeakPtr();
201 EXPECT_EQ(ptr.get(), &data);
202}
203
204TEST(WeakPtrTest, SupportsWeakPtr) {
205 Producer f;
206 WeakPtr<Producer> ptr = f.AsWeakPtr();
207 EXPECT_EQ(&f, ptr.get());
208}
209
210TEST(WeakPtrTest, InvalidateWeakPtrs) {
211 int data;
212 WeakPtrFactory<int> factory(&data);
213 WeakPtr<int> ptr = factory.GetWeakPtr();
214 EXPECT_EQ(&data, ptr.get());
[email protected]59326aac2009-09-25 23:34:34215 EXPECT_TRUE(factory.HasWeakPtrs());
[email protected]3125d6462009-09-01 20:50:17216 factory.InvalidateWeakPtrs();
[email protected]9b6fee12009-09-29 18:13:07217 EXPECT_TRUE(ptr.get() == NULL);
[email protected]59326aac2009-09-25 23:34:34218 EXPECT_FALSE(factory.HasWeakPtrs());
219}
220
221TEST(WeakPtrTest, HasWeakPtrs) {
222 int data;
223 WeakPtrFactory<int> factory(&data);
224 {
225 WeakPtr<int> ptr = factory.GetWeakPtr();
226 EXPECT_TRUE(factory.HasWeakPtrs());
227 }
228 EXPECT_FALSE(factory.HasWeakPtrs());
[email protected]3125d6462009-09-01 20:50:17229}
230
231TEST(WeakPtrTest, SingleThreaded1) {
232 // Test that it is OK to create a class that supports weak references on one
233 // thread, but use it on another. This tests that we do not trip runtime
234 // checks that ensure that a weak reference is not used by multiple threads.
235 scoped_ptr<Producer> producer(OffThreadObjectCreator<Producer>::NewObject());
236 WeakPtr<Producer> weak_producer = producer->AsWeakPtr();
237 EXPECT_EQ(producer.get(), weak_producer.get());
238}
239
240TEST(WeakPtrTest, SingleThreaded2) {
241 // Test that it is OK to create a class that has a WeakPtr member on one
242 // thread, but use it on another. This tests that we do not trip runtime
243 // checks that ensure that a weak reference is not used by multiple threads.
244 scoped_ptr<Consumer> consumer(OffThreadObjectCreator<Consumer>::NewObject());
245 Producer producer;
246 consumer->producer = producer.AsWeakPtr();
247 EXPECT_EQ(&producer, consumer->producer.get());
248}
249
[email protected]1edefc42011-08-26 17:32:29250TEST(WeakPtrTest, MoveOwnershipImplicit) {
251 // Move object ownership to other thread by releasing all weak pointers
252 // on the original thread first. Establishing weak pointers on a different
253 // thread after previous pointers have been destroyed implicitly reattaches
254 // the thread checks.
255 // - Thread A creates object and weak pointer
256 // - Thread A deletes the weak pointer
257 // - Thread B creates weak pointer
258 // - Thread B derefs weak pointer
259 // - Thread B deletes object
260 BackgroundThread thread;
261 thread.Start();
262 Producer* producer = new Producer();
263 {
264 WeakPtr<Producer> weak_ptr = producer->AsWeakPtr();
265 }
266 Consumer* consumer;
267 thread.CreateConsumerFromProducer(&consumer, producer);
268 EXPECT_EQ(thread.DeRef(consumer), producer);
269 thread.DeleteProducer(producer);
270 thread.DeleteConsumer(consumer);
271}
272
273TEST(WeakPtrTest, MoveOwnershipExplicit) {
274 // Test that we do not trip any checks if we establish weak references
275 // on one thread and delete the object on another thread after explicit
276 // detachment.
277 // - Thread A creates object
278 // - Thread B creates weak pointer
279 // - Thread B releases weak pointer
280 // - Detach owner from Thread B
281 // - Thread A destroys object
282 BackgroundThread thread;
283 thread.Start();
284 Producer producer;
285 Consumer* consumer;
286 thread.CreateConsumerFromProducer(&consumer, &producer);
287 EXPECT_EQ(thread.DeRef(consumer), &producer);
288 thread.DeleteConsumer(consumer);
289 producer.DetachFromThread();
290}
291
292TEST(WeakPtrTest, ThreadARefOutlivesThreadBRef) {
293 // Originating thread has a WeakPtr that outlives others.
294 // - Thread A creates WeakPtr<> and passes copy to Thread B
295 // - Destruct the pointer on Thread B
296 // - Destruct the pointer on Thread A
297 BackgroundThread thread;
298 thread.Start();
299 Producer producer;
300 Consumer consumer;
301 consumer.producer = producer.AsWeakPtr();
302 Consumer* consumer_copy;
303 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer);
304 EXPECT_EQ(consumer_copy->producer, &producer);
305 thread.DeleteConsumer(consumer_copy);
306}
307
308TEST(WeakPtrTest, ThreadBRefOutlivesThreadARef) {
309 // Originating thread drops all references before another thread.
310 // - Thread A creates WeakPtr<> and passes copy to Thread B
311 // - Destruct the pointer on Thread A
312 // - Destruct the pointer on Thread B
313 BackgroundThread thread;
314 thread.Start();
315 Producer producer;
316 Consumer* consumer_copy;
317 {
318 Consumer consumer;
319 consumer.producer = producer.AsWeakPtr();
320 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer);
321 }
322 EXPECT_EQ(consumer_copy->producer, &producer);
323 thread.DeleteConsumer(consumer_copy);
324}
325
326TEST(WeakPtrTest, OwnerThreadDeletesObject) {
327 // Originating thread invalidates WeakPtrs while its held by other thread.
328 // - Thread A creates WeakPtr<> and passes Copy to Thread B
329 // - WeakReferenceOwner gets destroyed on Thread A
330 // - WeakPtr gets destroyed on Thread B
331 BackgroundThread thread;
332 thread.Start();
333 Consumer* consumer_copy;
334 {
335 Producer producer;
336 Consumer consumer;
337 consumer.producer = producer.AsWeakPtr();
338 thread.CreateConsumerFromConsumer(&consumer_copy, &consumer);
339 }
340 EXPECT_TRUE(consumer_copy->producer == NULL);
341 thread.DeleteConsumer(consumer_copy);
342}
343
[email protected]3125d6462009-09-01 20:50:17344} // namespace base