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/observer_list.h" | 5 #include "base/observer_list.h" |
6 #include "base/observer_list_threadsafe.h" | 6 #include "base/observer_list_threadsafe.h" |
7 | 7 |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/memory/weak_ptr.h" | 11 #include "base/memory/weak_ptr.h" |
12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "base/run_loop.h" |
13 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
14 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
15 | 16 |
16 using base::PlatformThread; | 17 namespace base { |
17 using base::Time; | |
18 | |
19 namespace { | 18 namespace { |
20 | 19 |
21 class Foo { | 20 class Foo { |
22 public: | 21 public: |
23 virtual void Observe(int x) = 0; | 22 virtual void Observe(int x) = 0; |
24 virtual ~Foo() {} | 23 virtual ~Foo() {} |
25 }; | 24 }; |
26 | 25 |
27 class Adder : public Foo { | 26 class Adder : public Foo { |
28 public: | 27 public: |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 Adder a(1); | 215 Adder a(1); |
217 Adder b(-1); | 216 Adder b(-1); |
218 Adder c(1); | 217 Adder c(1); |
219 Adder d(-1); | 218 Adder d(-1); |
220 ThreadSafeDisrupter evil(observer_list.get(), &c); | 219 ThreadSafeDisrupter evil(observer_list.get(), &c); |
221 | 220 |
222 observer_list->AddObserver(&a); | 221 observer_list->AddObserver(&a); |
223 observer_list->AddObserver(&b); | 222 observer_list->AddObserver(&b); |
224 | 223 |
225 observer_list->Notify(&Foo::Observe, 10); | 224 observer_list->Notify(&Foo::Observe, 10); |
226 loop.RunUntilIdle(); | 225 RunLoop().RunUntilIdle(); |
227 | 226 |
228 observer_list->AddObserver(&evil); | 227 observer_list->AddObserver(&evil); |
229 observer_list->AddObserver(&c); | 228 observer_list->AddObserver(&c); |
230 observer_list->AddObserver(&d); | 229 observer_list->AddObserver(&d); |
231 | 230 |
232 observer_list->Notify(&Foo::Observe, 10); | 231 observer_list->Notify(&Foo::Observe, 10); |
233 loop.RunUntilIdle(); | 232 RunLoop().RunUntilIdle(); |
234 | 233 |
235 EXPECT_EQ(20, a.total); | 234 EXPECT_EQ(20, a.total); |
236 EXPECT_EQ(-20, b.total); | 235 EXPECT_EQ(-20, b.total); |
237 EXPECT_EQ(0, c.total); | 236 EXPECT_EQ(0, c.total); |
238 EXPECT_EQ(-10, d.total); | 237 EXPECT_EQ(-10, d.total); |
239 } | 238 } |
240 | 239 |
241 TEST(ObserverListThreadSafeTest, RemoveObserver) { | 240 TEST(ObserverListThreadSafeTest, RemoveObserver) { |
242 MessageLoop loop; | 241 MessageLoop loop; |
243 | 242 |
244 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 243 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
245 new ObserverListThreadSafe<Foo>); | 244 new ObserverListThreadSafe<Foo>); |
246 Adder a(1), b(1); | 245 Adder a(1), b(1); |
247 | 246 |
248 // A workaround for the compiler bug. See http://crbug.com/121960. | 247 // A workaround for the compiler bug. See http://crbug.com/121960. |
249 EXPECT_NE(&a, &b); | 248 EXPECT_NE(&a, &b); |
250 | 249 |
251 // Should do nothing. | 250 // Should do nothing. |
252 observer_list->RemoveObserver(&a); | 251 observer_list->RemoveObserver(&a); |
253 observer_list->RemoveObserver(&b); | 252 observer_list->RemoveObserver(&b); |
254 | 253 |
255 observer_list->Notify(&Foo::Observe, 10); | 254 observer_list->Notify(&Foo::Observe, 10); |
256 loop.RunUntilIdle(); | 255 RunLoop().RunUntilIdle(); |
257 | 256 |
258 EXPECT_EQ(0, a.total); | 257 EXPECT_EQ(0, a.total); |
259 EXPECT_EQ(0, b.total); | 258 EXPECT_EQ(0, b.total); |
260 | 259 |
261 observer_list->AddObserver(&a); | 260 observer_list->AddObserver(&a); |
262 | 261 |
263 // Should also do nothing. | 262 // Should also do nothing. |
264 observer_list->RemoveObserver(&b); | 263 observer_list->RemoveObserver(&b); |
265 | 264 |
266 observer_list->Notify(&Foo::Observe, 10); | 265 observer_list->Notify(&Foo::Observe, 10); |
267 loop.RunUntilIdle(); | 266 RunLoop().RunUntilIdle(); |
268 | 267 |
269 EXPECT_EQ(10, a.total); | 268 EXPECT_EQ(10, a.total); |
270 EXPECT_EQ(0, b.total); | 269 EXPECT_EQ(0, b.total); |
271 } | 270 } |
272 | 271 |
273 TEST(ObserverListThreadSafeTest, WithoutMessageLoop) { | 272 TEST(ObserverListThreadSafeTest, WithoutMessageLoop) { |
274 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 273 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
275 new ObserverListThreadSafe<Foo>); | 274 new ObserverListThreadSafe<Foo>); |
276 | 275 |
277 Adder a(1), b(1), c(1); | 276 Adder a(1), b(1), c(1); |
278 | 277 |
279 // No MessageLoop, so these should not be added. | 278 // No MessageLoop, so these should not be added. |
280 observer_list->AddObserver(&a); | 279 observer_list->AddObserver(&a); |
281 observer_list->AddObserver(&b); | 280 observer_list->AddObserver(&b); |
282 | 281 |
283 { | 282 { |
284 // Add c when there's a loop. | 283 // Add c when there's a loop. |
285 MessageLoop loop; | 284 MessageLoop loop; |
286 observer_list->AddObserver(&c); | 285 observer_list->AddObserver(&c); |
287 | 286 |
288 observer_list->Notify(&Foo::Observe, 10); | 287 observer_list->Notify(&Foo::Observe, 10); |
289 loop.RunUntilIdle(); | 288 RunLoop().RunUntilIdle(); |
290 | 289 |
291 EXPECT_EQ(0, a.total); | 290 EXPECT_EQ(0, a.total); |
292 EXPECT_EQ(0, b.total); | 291 EXPECT_EQ(0, b.total); |
293 EXPECT_EQ(10, c.total); | 292 EXPECT_EQ(10, c.total); |
294 | 293 |
295 // Now add a when there's a loop. | 294 // Now add a when there's a loop. |
296 observer_list->AddObserver(&a); | 295 observer_list->AddObserver(&a); |
297 | 296 |
298 // Remove c when there's a loop. | 297 // Remove c when there's a loop. |
299 observer_list->RemoveObserver(&c); | 298 observer_list->RemoveObserver(&c); |
300 | 299 |
301 // Notify again. | 300 // Notify again. |
302 observer_list->Notify(&Foo::Observe, 20); | 301 observer_list->Notify(&Foo::Observe, 20); |
303 loop.RunUntilIdle(); | 302 RunLoop().RunUntilIdle(); |
304 | 303 |
305 EXPECT_EQ(20, a.total); | 304 EXPECT_EQ(20, a.total); |
306 EXPECT_EQ(0, b.total); | 305 EXPECT_EQ(0, b.total); |
307 EXPECT_EQ(10, c.total); | 306 EXPECT_EQ(10, c.total); |
308 } | 307 } |
309 | 308 |
310 // Removing should always succeed with or without a loop. | 309 // Removing should always succeed with or without a loop. |
311 observer_list->RemoveObserver(&a); | 310 observer_list->RemoveObserver(&a); |
312 | 311 |
313 // Notifying should not fail but should also be a no-op. | 312 // Notifying should not fail but should also be a no-op. |
314 MessageLoop loop; | 313 MessageLoop loop; |
315 observer_list->AddObserver(&b); | 314 observer_list->AddObserver(&b); |
316 observer_list->Notify(&Foo::Observe, 30); | 315 observer_list->Notify(&Foo::Observe, 30); |
317 loop.RunUntilIdle(); | 316 RunLoop().RunUntilIdle(); |
318 | 317 |
319 EXPECT_EQ(20, a.total); | 318 EXPECT_EQ(20, a.total); |
320 EXPECT_EQ(30, b.total); | 319 EXPECT_EQ(30, b.total); |
321 EXPECT_EQ(10, c.total); | 320 EXPECT_EQ(10, c.total); |
322 } | 321 } |
323 | 322 |
324 class FooRemover : public Foo { | 323 class FooRemover : public Foo { |
325 public: | 324 public: |
326 explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {} | 325 explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {} |
327 virtual ~FooRemover() {} | 326 virtual ~FooRemover() {} |
(...skipping 24 matching lines...) Expand all Loading... |
352 FooRemover a(observer_list); | 351 FooRemover a(observer_list); |
353 Adder b(1); | 352 Adder b(1); |
354 | 353 |
355 observer_list->AddObserver(&a); | 354 observer_list->AddObserver(&a); |
356 observer_list->AddObserver(&b); | 355 observer_list->AddObserver(&b); |
357 | 356 |
358 a.AddFooToRemove(&a); | 357 a.AddFooToRemove(&a); |
359 a.AddFooToRemove(&b); | 358 a.AddFooToRemove(&b); |
360 | 359 |
361 observer_list->Notify(&Foo::Observe, 1); | 360 observer_list->Notify(&Foo::Observe, 1); |
362 loop.RunUntilIdle(); | 361 RunLoop().RunUntilIdle(); |
363 } | 362 } |
364 | 363 |
365 // A test driver for a multi-threaded notification loop. Runs a number | 364 // A test driver for a multi-threaded notification loop. Runs a number |
366 // of observer threads, each of which constantly adds/removes itself | 365 // of observer threads, each of which constantly adds/removes itself |
367 // from the observer list. Optionally, if cross_thread_notifies is set | 366 // from the observer list. Optionally, if cross_thread_notifies is set |
368 // to true, the observer threads will also trigger notifications to | 367 // to true, the observer threads will also trigger notifications to |
369 // all observers. | 368 // all observers. |
370 static void ThreadSafeObserverHarness(int num_threads, | 369 static void ThreadSafeObserverHarness(int num_threads, |
371 bool cross_thread_notifies) { | 370 bool cross_thread_notifies) { |
372 MessageLoop loop; | 371 MessageLoop loop; |
(...skipping 19 matching lines...) Expand all Loading... |
392 threaded_observer[index], &threads[index])); | 391 threaded_observer[index], &threads[index])); |
393 } | 392 } |
394 | 393 |
395 Time start = Time::Now(); | 394 Time start = Time::Now(); |
396 while (true) { | 395 while (true) { |
397 if ((Time::Now() - start).InMilliseconds() > kThreadRunTime) | 396 if ((Time::Now() - start).InMilliseconds() > kThreadRunTime) |
398 break; | 397 break; |
399 | 398 |
400 observer_list->Notify(&Foo::Observe, 10); | 399 observer_list->Notify(&Foo::Observe, 10); |
401 | 400 |
402 loop.RunUntilIdle(); | 401 RunLoop().RunUntilIdle(); |
403 } | 402 } |
404 | 403 |
405 for (int index = 0; index < num_threads; index++) { | 404 for (int index = 0; index < num_threads; index++) { |
406 threaded_observer[index]->Quit(); | 405 threaded_observer[index]->Quit(); |
407 PlatformThread::Join(threads[index]); | 406 PlatformThread::Join(threads[index]); |
408 } | 407 } |
409 } | 408 } |
410 | 409 |
411 TEST(ObserverListThreadSafeTest, CrossThreadObserver) { | 410 TEST(ObserverListThreadSafeTest, CrossThreadObserver) { |
412 // Use 7 observer threads. Notifications only come from | 411 // Use 7 observer threads. Notifications only come from |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 MessageLoop loop; | 456 MessageLoop loop; |
458 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 457 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
459 new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY)); | 458 new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY)); |
460 Adder a(1); | 459 Adder a(1); |
461 AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get()); | 460 AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get()); |
462 | 461 |
463 observer_list->AddObserver(&a); | 462 observer_list->AddObserver(&a); |
464 observer_list->AddObserver(&b); | 463 observer_list->AddObserver(&b); |
465 | 464 |
466 observer_list->Notify(&Foo::Observe, 1); | 465 observer_list->Notify(&Foo::Observe, 1); |
467 loop.RunUntilIdle(); | 466 RunLoop().RunUntilIdle(); |
468 | 467 |
469 EXPECT_TRUE(b.added); | 468 EXPECT_TRUE(b.added); |
470 // B's adder should not have been notified because it was added during | 469 // B's adder should not have been notified because it was added during |
471 // notificaiton. | 470 // notificaiton. |
472 EXPECT_EQ(0, b.adder.total); | 471 EXPECT_EQ(0, b.adder.total); |
473 | 472 |
474 // Notify again to make sure b's adder is notified. | 473 // Notify again to make sure b's adder is notified. |
475 observer_list->Notify(&Foo::Observe, 1); | 474 observer_list->Notify(&Foo::Observe, 1); |
476 loop.RunUntilIdle(); | 475 RunLoop().RunUntilIdle(); |
477 EXPECT_EQ(1, b.adder.total); | 476 EXPECT_EQ(1, b.adder.total); |
478 } | 477 } |
479 | 478 |
480 class AddInClearObserve : public Foo { | 479 class AddInClearObserve : public Foo { |
481 public: | 480 public: |
482 explicit AddInClearObserve(ObserverList<Foo>* list) | 481 explicit AddInClearObserve(ObserverList<Foo>* list) |
483 : list_(list), added_(false), adder_(1) {} | 482 : list_(list), added_(false), adder_(1) {} |
484 | 483 |
485 virtual void Observe(int /* x */) OVERRIDE { | 484 virtual void Observe(int /* x */) OVERRIDE { |
486 list_->Clear(); | 485 list_->Clear(); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 ObserverList<Foo>* observer_list = new ObserverList<Foo>; | 539 ObserverList<Foo>* observer_list = new ObserverList<Foo>; |
541 ListDestructor a(observer_list); | 540 ListDestructor a(observer_list); |
542 observer_list->AddObserver(&a); | 541 observer_list->AddObserver(&a); |
543 | 542 |
544 FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); | 543 FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0)); |
545 // If this test fails, there'll be Valgrind errors when this function goes out | 544 // If this test fails, there'll be Valgrind errors when this function goes out |
546 // of scope. | 545 // of scope. |
547 } | 546 } |
548 | 547 |
549 } // namespace | 548 } // namespace |
| 549 } // namespace base |
OLD | NEW |