| 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 <utility> |
| 8 #include <vector> | 9 #include <vector> |
| 9 | 10 |
| 11 #include "base/bind.h" |
| 10 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
| 11 #include "base/location.h" | 13 #include "base/location.h" |
| 12 #include "base/memory/weak_ptr.h" | 14 #include "base/memory/weak_ptr.h" |
| 13 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
| 16 #include "base/sequenced_task_runner.h" |
| 14 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 18 #include "base/synchronization/waitable_event.h" |
| 19 #include "base/task_scheduler/post_task.h" |
| 20 #include "base/task_scheduler/task_scheduler.h" |
| 21 #include "base/test/scoped_task_environment.h" |
| 22 #include "base/test/scoped_task_scheduler.h" |
| 15 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
| 17 | 25 |
| 18 namespace base { | 26 namespace base { |
| 19 namespace { | 27 namespace { |
| 20 | 28 |
| 21 class Foo { | 29 class Foo { |
| 22 public: | 30 public: |
| 23 virtual void Observe(int x) = 0; | 31 virtual void Observe(int x) = 0; |
| 24 virtual ~Foo() {} | 32 virtual ~Foo() {} |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 } | 66 } |
| 59 | 67 |
| 60 void SetDoomed(Foo* doomed) { doomed_ = doomed; } | 68 void SetDoomed(Foo* doomed) { doomed_ = doomed; } |
| 61 | 69 |
| 62 private: | 70 private: |
| 63 ObserverList<Foo>* list_; | 71 ObserverList<Foo>* list_; |
| 64 Foo* doomed_; | 72 Foo* doomed_; |
| 65 bool remove_self_; | 73 bool remove_self_; |
| 66 }; | 74 }; |
| 67 | 75 |
| 68 class ThreadSafeDisrupter : public Foo { | |
| 69 public: | |
| 70 ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed) | |
| 71 : list_(list), | |
| 72 doomed_(doomed) { | |
| 73 } | |
| 74 ~ThreadSafeDisrupter() override {} | |
| 75 void Observe(int x) override { list_->RemoveObserver(doomed_); } | |
| 76 | |
| 77 private: | |
| 78 ObserverListThreadSafe<Foo>* list_; | |
| 79 Foo* doomed_; | |
| 80 }; | |
| 81 | |
| 82 template <typename ObserverListType> | 76 template <typename ObserverListType> |
| 83 class AddInObserve : public Foo { | 77 class AddInObserve : public Foo { |
| 84 public: | 78 public: |
| 85 explicit AddInObserve(ObserverListType* observer_list) | 79 explicit AddInObserve(ObserverListType* observer_list) |
| 86 : observer_list(observer_list), to_add_() {} | 80 : observer_list(observer_list), to_add_() {} |
| 87 | 81 |
| 88 void SetToAdd(Foo* to_add) { to_add_ = to_add; } | 82 void SetToAdd(Foo* to_add) { to_add_ = to_add; } |
| 89 | 83 |
| 90 void Observe(int x) override { | 84 void Observe(int x) override { |
| 91 if (to_add_) { | 85 if (to_add_) { |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 | 263 |
| 270 TEST(ObserverListThreadSafeTest, BasicTest) { | 264 TEST(ObserverListThreadSafeTest, BasicTest) { |
| 271 MessageLoop loop; | 265 MessageLoop loop; |
| 272 | 266 |
| 273 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 267 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 274 new ObserverListThreadSafe<Foo>); | 268 new ObserverListThreadSafe<Foo>); |
| 275 Adder a(1); | 269 Adder a(1); |
| 276 Adder b(-1); | 270 Adder b(-1); |
| 277 Adder c(1); | 271 Adder c(1); |
| 278 Adder d(-1); | 272 Adder d(-1); |
| 279 ThreadSafeDisrupter evil(observer_list.get(), &c); | |
| 280 | 273 |
| 281 observer_list->AddObserver(&a); | 274 observer_list->AddObserver(&a); |
| 282 observer_list->AddObserver(&b); | 275 observer_list->AddObserver(&b); |
| 283 | 276 |
| 284 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 277 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 285 RunLoop().RunUntilIdle(); | 278 RunLoop().RunUntilIdle(); |
| 286 | 279 |
| 287 observer_list->AddObserver(&evil); | |
| 288 observer_list->AddObserver(&c); | 280 observer_list->AddObserver(&c); |
| 289 observer_list->AddObserver(&d); | 281 observer_list->AddObserver(&d); |
| 290 | 282 |
| 291 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 283 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 284 observer_list->RemoveObserver(&c); |
| 292 RunLoop().RunUntilIdle(); | 285 RunLoop().RunUntilIdle(); |
| 293 | 286 |
| 294 EXPECT_EQ(20, a.total); | 287 EXPECT_EQ(20, a.total); |
| 295 EXPECT_EQ(-20, b.total); | 288 EXPECT_EQ(-20, b.total); |
| 296 EXPECT_EQ(0, c.total); | 289 EXPECT_EQ(0, c.total); |
| 297 EXPECT_EQ(-10, d.total); | 290 EXPECT_EQ(-10, d.total); |
| 298 } | 291 } |
| 299 | 292 |
| 300 TEST(ObserverListThreadSafeTest, RemoveObserver) { | 293 TEST(ObserverListThreadSafeTest, RemoveObserver) { |
| 301 MessageLoop loop; | 294 MessageLoop loop; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 322 // Should also do nothing. | 315 // Should also do nothing. |
| 323 observer_list->RemoveObserver(&b); | 316 observer_list->RemoveObserver(&b); |
| 324 | 317 |
| 325 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 318 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 326 RunLoop().RunUntilIdle(); | 319 RunLoop().RunUntilIdle(); |
| 327 | 320 |
| 328 EXPECT_EQ(10, a.total); | 321 EXPECT_EQ(10, a.total); |
| 329 EXPECT_EQ(0, b.total); | 322 EXPECT_EQ(0, b.total); |
| 330 } | 323 } |
| 331 | 324 |
| 332 TEST(ObserverListThreadSafeTest, WithoutMessageLoop) { | 325 TEST(ObserverListThreadSafeTest, WithoutSequence) { |
| 333 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 326 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 334 new ObserverListThreadSafe<Foo>); | 327 new ObserverListThreadSafe<Foo>); |
| 335 | 328 |
| 336 Adder a(1), b(1), c(1); | 329 Adder a(1), b(1), c(1); |
| 337 | 330 |
| 338 // No MessageLoop, so these should not be added. | 331 // No sequence, so these should not be added. |
| 339 observer_list->AddObserver(&a); | 332 observer_list->AddObserver(&a); |
| 340 observer_list->AddObserver(&b); | 333 observer_list->AddObserver(&b); |
| 341 | 334 |
| 342 { | 335 { |
| 343 // Add c when there's a loop. | 336 // Add c when there's a sequence. |
| 344 MessageLoop loop; | 337 MessageLoop loop; |
| 345 observer_list->AddObserver(&c); | 338 observer_list->AddObserver(&c); |
| 346 | 339 |
| 347 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 340 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 348 RunLoop().RunUntilIdle(); | 341 RunLoop().RunUntilIdle(); |
| 349 | 342 |
| 350 EXPECT_EQ(0, a.total); | 343 EXPECT_EQ(0, a.total); |
| 351 EXPECT_EQ(0, b.total); | 344 EXPECT_EQ(0, b.total); |
| 352 EXPECT_EQ(10, c.total); | 345 EXPECT_EQ(10, c.total); |
| 353 | 346 |
| 354 // Now add a when there's a loop. | 347 // Now add a when there's a sequence. |
| 355 observer_list->AddObserver(&a); | 348 observer_list->AddObserver(&a); |
| 356 | 349 |
| 357 // Remove c when there's a loop. | 350 // Remove c when there's a sequence. |
| 358 observer_list->RemoveObserver(&c); | 351 observer_list->RemoveObserver(&c); |
| 359 | 352 |
| 360 // Notify again. | 353 // Notify again. |
| 361 observer_list->Notify(FROM_HERE, &Foo::Observe, 20); | 354 observer_list->Notify(FROM_HERE, &Foo::Observe, 20); |
| 362 RunLoop().RunUntilIdle(); | 355 RunLoop().RunUntilIdle(); |
| 363 | 356 |
| 364 EXPECT_EQ(20, a.total); | 357 EXPECT_EQ(20, a.total); |
| 365 EXPECT_EQ(0, b.total); | 358 EXPECT_EQ(0, b.total); |
| 366 EXPECT_EQ(10, c.total); | 359 EXPECT_EQ(10, c.total); |
| 367 } | 360 } |
| 368 | 361 |
| 369 // Removing should always succeed with or without a loop. | 362 // Removing should always succeed with or without a sequence. |
| 370 observer_list->RemoveObserver(&a); | 363 observer_list->RemoveObserver(&a); |
| 371 | 364 |
| 372 // Notifying should not fail but should also be a no-op. | 365 // Notifying should not fail but should also be a no-op. |
| 373 MessageLoop loop; | 366 MessageLoop loop; |
| 374 observer_list->AddObserver(&b); | 367 observer_list->AddObserver(&b); |
| 375 observer_list->Notify(FROM_HERE, &Foo::Observe, 30); | 368 observer_list->Notify(FROM_HERE, &Foo::Observe, 30); |
| 376 RunLoop().RunUntilIdle(); | 369 RunLoop().RunUntilIdle(); |
| 377 | 370 |
| 378 EXPECT_EQ(20, a.total); | 371 EXPECT_EQ(20, a.total); |
| 379 EXPECT_EQ(30, b.total); | 372 EXPECT_EQ(30, b.total); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 477 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 485 new ObserverListThreadSafe<Foo>); | 478 new ObserverListThreadSafe<Foo>); |
| 486 | 479 |
| 487 Adder a(1); | 480 Adder a(1); |
| 488 observer_list->AddObserver(&a); | 481 observer_list->AddObserver(&a); |
| 489 delete loop; | 482 delete loop; |
| 490 // Test passes if we don't crash here. | 483 // Test passes if we don't crash here. |
| 491 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | 484 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 492 } | 485 } |
| 493 | 486 |
| 487 namespace { |
| 488 |
| 489 class SequenceVerificationObserver : public Foo { |
| 490 public: |
| 491 explicit SequenceVerificationObserver( |
| 492 scoped_refptr<SequencedTaskRunner> task_runner) |
| 493 : task_runner_(std::move(task_runner)) {} |
| 494 ~SequenceVerificationObserver() override = default; |
| 495 |
| 496 void Observe(int x) override { |
| 497 called_on_valid_sequence_ = task_runner_->RunsTasksOnCurrentThread(); |
| 498 } |
| 499 |
| 500 bool called_on_valid_sequence() const { return called_on_valid_sequence_; } |
| 501 |
| 502 private: |
| 503 const scoped_refptr<SequencedTaskRunner> task_runner_; |
| 504 bool called_on_valid_sequence_ = false; |
| 505 |
| 506 DISALLOW_COPY_AND_ASSIGN(SequenceVerificationObserver); |
| 507 }; |
| 508 |
| 509 } // namespace |
| 510 |
| 511 // Verify that observers are notified on the correct sequence. |
| 512 TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) { |
| 513 test::ScopedTaskEnvironment scoped_task_environment; |
| 514 |
| 515 auto task_runner_1 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); |
| 516 auto task_runner_2 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); |
| 517 |
| 518 auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>()); |
| 519 |
| 520 SequenceVerificationObserver observer_1(task_runner_1); |
| 521 SequenceVerificationObserver observer_2(task_runner_2); |
| 522 |
| 523 task_runner_1->PostTask( |
| 524 FROM_HERE, Bind(&ObserverListThreadSafe<Foo>::AddObserver, observer_list, |
| 525 Unretained(&observer_1))); |
| 526 task_runner_2->PostTask( |
| 527 FROM_HERE, Bind(&ObserverListThreadSafe<Foo>::AddObserver, observer_list, |
| 528 Unretained(&observer_2))); |
| 529 |
| 530 TaskScheduler::GetInstance()->FlushForTesting(); |
| 531 |
| 532 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 533 |
| 534 TaskScheduler::GetInstance()->FlushForTesting(); |
| 535 |
| 536 EXPECT_TRUE(observer_1.called_on_valid_sequence()); |
| 537 EXPECT_TRUE(observer_2.called_on_valid_sequence()); |
| 538 } |
| 539 |
| 540 // Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe |
| 541 // from a notification, it is itself notified. |
| 542 TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) { |
| 543 test::ScopedTaskEnvironment scoped_task_environment; |
| 544 auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>()); |
| 545 |
| 546 Adder observer_added_from_notification(1); |
| 547 |
| 548 AddInObserve<ObserverListThreadSafe<Foo>> initial_observer( |
| 549 observer_list.get()); |
| 550 initial_observer.SetToAdd(&observer_added_from_notification); |
| 551 observer_list->AddObserver(&initial_observer); |
| 552 |
| 553 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 554 |
| 555 base::RunLoop().RunUntilIdle(); |
| 556 |
| 557 EXPECT_EQ(1, observer_added_from_notification.GetValue()); |
| 558 } |
| 559 |
| 560 namespace { |
| 561 |
| 562 class RemoveWhileNotificationIsRunningObserver : public Foo { |
| 563 public: |
| 564 RemoveWhileNotificationIsRunningObserver() |
| 565 : notification_running_(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 566 WaitableEvent::InitialState::NOT_SIGNALED), |
| 567 barrier_(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 568 WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 569 ~RemoveWhileNotificationIsRunningObserver() override = default; |
| 570 |
| 571 void Observe(int x) override { |
| 572 notification_running_.Signal(); |
| 573 barrier_.Wait(); |
| 574 } |
| 575 |
| 576 void WaitForNotificationRunning() { notification_running_.Wait(); } |
| 577 void Unblock() { barrier_.Signal(); } |
| 578 |
| 579 private: |
| 580 WaitableEvent notification_running_; |
| 581 WaitableEvent barrier_; |
| 582 |
| 583 DISALLOW_COPY_AND_ASSIGN(RemoveWhileNotificationIsRunningObserver); |
| 584 }; |
| 585 |
| 586 } // namespace |
| 587 |
| 588 // Verify that there is no crash when an observer is removed while it is being |
| 589 // notified. |
| 590 TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) { |
| 591 auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>()); |
| 592 RemoveWhileNotificationIsRunningObserver observer; |
| 593 |
| 594 WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 595 WaitableEvent::InitialState::NOT_SIGNALED); |
| 596 WaitableEvent barrier(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 597 WaitableEvent::InitialState::NOT_SIGNALED); |
| 598 |
| 599 // This must be after the declaration of |barrier| so that tasks posted to |
| 600 // TaskScheduler can safely use |barrier|. |
| 601 test::ScopedTaskEnvironment scoped_task_environment; |
| 602 |
| 603 CreateSequencedTaskRunnerWithTraits(TaskTraits().WithBaseSyncPrimitives()) |
| 604 ->PostTask(FROM_HERE, |
| 605 base::Bind(&ObserverListThreadSafe<Foo>::AddObserver, |
| 606 observer_list, Unretained(&observer))); |
| 607 TaskScheduler::GetInstance()->FlushForTesting(); |
| 608 |
| 609 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 610 observer.WaitForNotificationRunning(); |
| 611 observer_list->RemoveObserver(&observer); |
| 612 |
| 613 observer.Unblock(); |
| 614 } |
| 615 |
| 494 TEST(ObserverListTest, Existing) { | 616 TEST(ObserverListTest, Existing) { |
| 495 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); | 617 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); |
| 496 Adder a(1); | 618 Adder a(1); |
| 497 AddInObserve<ObserverList<Foo> > b(&observer_list); | 619 AddInObserve<ObserverList<Foo> > b(&observer_list); |
| 498 Adder c(1); | 620 Adder c(1); |
| 499 b.SetToAdd(&c); | 621 b.SetToAdd(&c); |
| 500 | 622 |
| 501 observer_list.AddObserver(&a); | 623 observer_list.AddObserver(&a); |
| 502 observer_list.AddObserver(&b); | 624 observer_list.AddObserver(&b); |
| 503 | 625 |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 // However, the first Observe() call will add a second observer: at this | 1048 // However, the first Observe() call will add a second observer: at this |
| 927 // point, it != observer_list.end() should be true, and Observe() should be | 1049 // point, it != observer_list.end() should be true, and Observe() should be |
| 928 // called on the newly added observer on the next iteration of the loop. | 1050 // called on the newly added observer on the next iteration of the loop. |
| 929 observer.Observe(10); | 1051 observer.Observe(10); |
| 930 } | 1052 } |
| 931 | 1053 |
| 932 EXPECT_EQ(-10, b.total); | 1054 EXPECT_EQ(-10, b.total); |
| 933 } | 1055 } |
| 934 | 1056 |
| 935 } // namespace base | 1057 } // namespace base |
| OLD | NEW |