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 test::ScopedTaskEnvironment scoped_task_environment; | |
592 auto observer_list = make_scoped_refptr(new ObserverListThreadSafe<Foo>()); | |
593 RemoveWhileNotificationIsRunningObserver observer; | |
594 | |
595 WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC, | |
596 WaitableEvent::InitialState::NOT_SIGNALED); | |
597 WaitableEvent barrier(WaitableEvent::ResetPolicy::AUTOMATIC, | |
598 WaitableEvent::InitialState::NOT_SIGNALED); | |
599 | |
600 CreateSequencedTaskRunnerWithTraits(TaskTraits().WithBaseSyncPrimitives()) | |
601 ->PostTask(FROM_HERE, | |
602 base::Bind(&ObserverListThreadSafe<Foo>::AddObserver, | |
603 observer_list, Unretained(&observer))); | |
604 TaskScheduler::GetInstance()->FlushForTesting(); | |
605 | |
606 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | |
607 observer.WaitForNotificationRunning(); | |
608 observer_list->RemoveObserver(&observer); | |
609 | |
610 observer.Unblock(); | |
611 TaskScheduler::GetInstance()->FlushForTesting(); | |
gab
2017/04/10 16:23:45
Why is it racy without this? Doesn't the ScopedTas
fdoray
2017/04/10 16:34:09
Yes. But without this, a task may still be waiting
gab
2017/04/10 16:36:14
Hmmm ok, then flip the order of their definition o
fdoray
2017/04/10 19:07:16
Done.
| |
612 } | |
613 | |
494 TEST(ObserverListTest, Existing) { | 614 TEST(ObserverListTest, Existing) { |
495 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); | 615 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); |
496 Adder a(1); | 616 Adder a(1); |
497 AddInObserve<ObserverList<Foo> > b(&observer_list); | 617 AddInObserve<ObserverList<Foo> > b(&observer_list); |
498 Adder c(1); | 618 Adder c(1); |
499 b.SetToAdd(&c); | 619 b.SetToAdd(&c); |
500 | 620 |
501 observer_list.AddObserver(&a); | 621 observer_list.AddObserver(&a); |
502 observer_list.AddObserver(&b); | 622 observer_list.AddObserver(&b); |
503 | 623 |
(...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 | 1046 // 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 | 1047 // 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. | 1048 // called on the newly added observer on the next iteration of the loop. |
929 observer.Observe(10); | 1049 observer.Observe(10); |
930 } | 1050 } |
931 | 1051 |
932 EXPECT_EQ(-10, b.total); | 1052 EXPECT_EQ(-10, b.total); |
933 } | 1053 } |
934 | 1054 |
935 } // namespace base | 1055 } // namespace base |
OLD | NEW |