Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: base/observer_list_unittest.cc

Issue 2805933002: [reland] Allow ObserverListThreadSafe to be used from sequenced tasks. (Closed)
Patch Set: CR-gab Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/observer_list_threadsafe.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « base/observer_list_threadsafe.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698