observer_list_threadsafe_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/observer_list_threadsafe.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "base/bind.h"
  8. #include "base/compiler_specific.h"
  9. #include "base/location.h"
  10. #include "base/logging.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/run_loop.h"
  14. #include "base/synchronization/waitable_event.h"
  15. #include "base/task/sequenced_task_runner.h"
  16. #include "base/task/single_thread_task_runner.h"
  17. #include "base/task/thread_pool.h"
  18. #include "base/task/thread_pool/thread_pool_instance.h"
  19. #include "base/test/bind.h"
  20. #include "base/test/task_environment.h"
  21. #include "base/threading/platform_thread.h"
  22. #include "base/threading/thread_restrictions.h"
  23. #include "base/threading/thread_task_runner_handle.h"
  24. #include "build/build_config.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. #include "third_party/abseil-cpp/absl/types/optional.h"
  27. namespace base {
  28. namespace {
  29. constexpr int kThreadRunTime = 2000; // ms to run the multi-threaded test.
  30. class Foo {
  31. public:
  32. virtual void Observe(int x) = 0;
  33. virtual ~Foo() = default;
  34. virtual int GetValue() const { return 0; }
  35. };
  36. class Adder : public Foo {
  37. public:
  38. explicit Adder(int scaler) : total(0), scaler_(scaler) {}
  39. ~Adder() override = default;
  40. void Observe(int x) override { total += x * scaler_; }
  41. int GetValue() const override { return total; }
  42. int total;
  43. private:
  44. int scaler_;
  45. };
  46. class AddInObserve : public Foo {
  47. public:
  48. explicit AddInObserve(ObserverListThreadSafe<Foo>* observer_list)
  49. : observer_list(observer_list), to_add_() {}
  50. void SetToAdd(Foo* to_add) { to_add_ = to_add; }
  51. void Observe(int x) override {
  52. if (to_add_) {
  53. observer_list->AddObserver(to_add_.get());
  54. to_add_ = nullptr;
  55. }
  56. }
  57. raw_ptr<ObserverListThreadSafe<Foo>> observer_list;
  58. raw_ptr<Foo> to_add_;
  59. };
  60. // A task for use in the ThreadSafeObserver test which will add and remove
  61. // itself from the notification list repeatedly.
  62. class AddRemoveThread : public Foo {
  63. public:
  64. AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
  65. : list_(list),
  66. task_runner_(ThreadPool::CreateSingleThreadTaskRunner(
  67. {},
  68. SingleThreadTaskRunnerThreadMode::DEDICATED)),
  69. in_list_(false),
  70. start_(Time::Now()),
  71. do_notifies_(notify) {
  72. task_runner_->PostTask(
  73. FROM_HERE,
  74. base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
  75. }
  76. ~AddRemoveThread() override = default;
  77. // This task just keeps posting to itself in an attempt to race with the
  78. // notifier.
  79. void AddTask() {
  80. if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
  81. VLOG(1) << "DONE!";
  82. return;
  83. }
  84. if (!in_list_) {
  85. list_->AddObserver(this);
  86. in_list_ = true;
  87. }
  88. if (do_notifies_) {
  89. list_->Notify(FROM_HERE, &Foo::Observe, 10);
  90. }
  91. ThreadTaskRunnerHandle::Get()->PostTask(
  92. FROM_HERE,
  93. base::BindOnce(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
  94. }
  95. void Observe(int x) override {
  96. // If we're getting called after we removed ourselves from the list, that is
  97. // very bad!
  98. EXPECT_TRUE(in_list_);
  99. // This callback should fire on the appropriate thread
  100. EXPECT_TRUE(task_runner_->BelongsToCurrentThread());
  101. list_->RemoveObserver(this);
  102. in_list_ = false;
  103. }
  104. private:
  105. raw_ptr<ObserverListThreadSafe<Foo>> list_;
  106. scoped_refptr<SingleThreadTaskRunner> task_runner_;
  107. bool in_list_; // Are we currently registered for notifications.
  108. // in_list_ is only used on |this| thread.
  109. Time start_; // The time we started the test.
  110. bool do_notifies_; // Whether these threads should do notifications.
  111. base::WeakPtrFactory<AddRemoveThread> weak_factory_{this};
  112. };
  113. } // namespace
  114. TEST(ObserverListThreadSafeTest, BasicTest) {
  115. using List = ObserverListThreadSafe<Foo>;
  116. test::TaskEnvironment task_environment;
  117. scoped_refptr<List> observer_list(new List);
  118. Adder a(1);
  119. Adder b(-1);
  120. Adder c(1);
  121. Adder d(-1);
  122. List::AddObserverResult result;
  123. result = observer_list->AddObserver(&a);
  124. EXPECT_EQ(result, List::AddObserverResult::kBecameNonEmpty);
  125. result = observer_list->AddObserver(&b);
  126. EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
  127. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  128. RunLoop().RunUntilIdle();
  129. result = observer_list->AddObserver(&c);
  130. EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
  131. result = observer_list->AddObserver(&d);
  132. EXPECT_EQ(result, List::AddObserverResult::kWasAlreadyNonEmpty);
  133. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  134. observer_list->RemoveObserver(&c);
  135. RunLoop().RunUntilIdle();
  136. EXPECT_EQ(20, a.total);
  137. EXPECT_EQ(-20, b.total);
  138. EXPECT_EQ(0, c.total);
  139. EXPECT_EQ(-10, d.total);
  140. }
  141. TEST(ObserverListThreadSafeTest, RemoveObserver) {
  142. using List = ObserverListThreadSafe<Foo>;
  143. test::TaskEnvironment task_environment;
  144. scoped_refptr<List> observer_list(new List);
  145. Adder a(1), b(1);
  146. // A workaround for the compiler bug. See http://crbug.com/121960.
  147. EXPECT_NE(&a, &b);
  148. List::RemoveObserverResult result;
  149. // Should do nothing.
  150. result = observer_list->RemoveObserver(&a);
  151. EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
  152. result = observer_list->RemoveObserver(&b);
  153. EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
  154. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  155. RunLoop().RunUntilIdle();
  156. EXPECT_EQ(0, a.total);
  157. EXPECT_EQ(0, b.total);
  158. observer_list->AddObserver(&a);
  159. // Should also do nothing.
  160. result = observer_list->RemoveObserver(&b);
  161. EXPECT_EQ(result, List::RemoveObserverResult::kRemainsNonEmpty);
  162. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  163. RunLoop().RunUntilIdle();
  164. EXPECT_EQ(10, a.total);
  165. EXPECT_EQ(0, b.total);
  166. result = observer_list->RemoveObserver(&a);
  167. EXPECT_EQ(result, List::RemoveObserverResult::kWasOrBecameEmpty);
  168. }
  169. class FooRemover : public Foo {
  170. public:
  171. explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
  172. ~FooRemover() override = default;
  173. void AddFooToRemove(Foo* foo) { foos_.push_back(foo); }
  174. void Observe(int x) override {
  175. std::vector<Foo*> tmp;
  176. tmp.swap(foos_);
  177. for (auto* it : tmp) {
  178. list_->RemoveObserver(it);
  179. }
  180. }
  181. private:
  182. const scoped_refptr<ObserverListThreadSafe<Foo>> list_;
  183. std::vector<Foo*> foos_;
  184. };
  185. TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
  186. test::TaskEnvironment task_environment;
  187. scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
  188. new ObserverListThreadSafe<Foo>);
  189. FooRemover a(observer_list.get());
  190. Adder b(1);
  191. observer_list->AddObserver(&a);
  192. observer_list->AddObserver(&b);
  193. a.AddFooToRemove(&a);
  194. a.AddFooToRemove(&b);
  195. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  196. RunLoop().RunUntilIdle();
  197. }
  198. // A test driver for a multi-threaded notification loop. Runs a number of
  199. // observer threads, each of which constantly adds/removes itself from the
  200. // observer list. Optionally, if cross_thread_notifies is set to true, the
  201. // observer threads will also trigger notifications to all observers.
  202. static void ThreadSafeObserverHarness(int num_threads,
  203. bool cross_thread_notifies) {
  204. test::TaskEnvironment task_environment;
  205. scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
  206. new ObserverListThreadSafe<Foo>);
  207. Adder a(1);
  208. Adder b(-1);
  209. observer_list->AddObserver(&a);
  210. observer_list->AddObserver(&b);
  211. std::vector<std::unique_ptr<AddRemoveThread>> threaded_observer;
  212. threaded_observer.reserve(num_threads);
  213. for (int index = 0; index < num_threads; index++) {
  214. threaded_observer.push_back(std::make_unique<AddRemoveThread>(
  215. observer_list.get(), cross_thread_notifies));
  216. }
  217. ASSERT_EQ(static_cast<size_t>(num_threads), threaded_observer.size());
  218. Time start = Time::Now();
  219. while (true) {
  220. if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
  221. break;
  222. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  223. RunLoop().RunUntilIdle();
  224. }
  225. task_environment.RunUntilIdle();
  226. }
  227. TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
  228. // Use 7 observer threads. Notifications only come from the main thread.
  229. ThreadSafeObserverHarness(7, false);
  230. }
  231. TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
  232. // Use 3 observer threads. Notifications will fire from the main thread and
  233. // all 3 observer threads.
  234. ThreadSafeObserverHarness(3, true);
  235. }
  236. TEST(ObserverListThreadSafeTest, OutlivesTaskEnvironment) {
  237. absl::optional<test::TaskEnvironment> task_environment(absl::in_place);
  238. scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
  239. new ObserverListThreadSafe<Foo>);
  240. Adder a(1);
  241. observer_list->AddObserver(&a);
  242. task_environment.reset();
  243. // Test passes if we don't crash here.
  244. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  245. }
  246. namespace {
  247. class SequenceVerificationObserver : public Foo {
  248. public:
  249. explicit SequenceVerificationObserver(
  250. scoped_refptr<SequencedTaskRunner> task_runner)
  251. : task_runner_(std::move(task_runner)) {}
  252. SequenceVerificationObserver(const SequenceVerificationObserver&) = delete;
  253. SequenceVerificationObserver& operator=(const SequenceVerificationObserver&) =
  254. delete;
  255. ~SequenceVerificationObserver() override = default;
  256. void Observe(int x) override {
  257. called_on_valid_sequence_ = task_runner_->RunsTasksInCurrentSequence();
  258. }
  259. bool called_on_valid_sequence() const { return called_on_valid_sequence_; }
  260. private:
  261. const scoped_refptr<SequencedTaskRunner> task_runner_;
  262. bool called_on_valid_sequence_ = false;
  263. };
  264. } // namespace
  265. // Verify that observers are notified on the correct sequence.
  266. TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) {
  267. test::TaskEnvironment task_environment;
  268. auto task_runner_1 = ThreadPool::CreateSequencedTaskRunner({});
  269. auto task_runner_2 = ThreadPool::ThreadPool::CreateSequencedTaskRunner({});
  270. auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
  271. SequenceVerificationObserver observer_1(task_runner_1);
  272. SequenceVerificationObserver observer_2(task_runner_2);
  273. task_runner_1->PostTask(
  274. FROM_HERE,
  275. BindOnce(base::IgnoreResult(&ObserverListThreadSafe<Foo>::AddObserver),
  276. observer_list, Unretained(&observer_1)));
  277. task_runner_2->PostTask(
  278. FROM_HERE,
  279. BindOnce(base::IgnoreResult(&ObserverListThreadSafe<Foo>::AddObserver),
  280. observer_list, Unretained(&observer_2)));
  281. ThreadPoolInstance::Get()->FlushForTesting();
  282. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  283. ThreadPoolInstance::Get()->FlushForTesting();
  284. EXPECT_TRUE(observer_1.called_on_valid_sequence());
  285. EXPECT_TRUE(observer_2.called_on_valid_sequence());
  286. }
  287. // Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe
  288. // from a notification, it is itself notified.
  289. TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) {
  290. test::TaskEnvironment task_environment;
  291. auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
  292. Adder observer_added_from_notification(1);
  293. AddInObserve initial_observer(observer_list.get());
  294. initial_observer.SetToAdd(&observer_added_from_notification);
  295. observer_list->AddObserver(&initial_observer);
  296. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  297. base::RunLoop().RunUntilIdle();
  298. EXPECT_EQ(1, observer_added_from_notification.GetValue());
  299. }
  300. namespace {
  301. class RemoveWhileNotificationIsRunningObserver : public Foo {
  302. public:
  303. RemoveWhileNotificationIsRunningObserver()
  304. : notification_running_(WaitableEvent::ResetPolicy::AUTOMATIC,
  305. WaitableEvent::InitialState::NOT_SIGNALED),
  306. barrier_(WaitableEvent::ResetPolicy::AUTOMATIC,
  307. WaitableEvent::InitialState::NOT_SIGNALED) {}
  308. RemoveWhileNotificationIsRunningObserver(
  309. const RemoveWhileNotificationIsRunningObserver&) = delete;
  310. RemoveWhileNotificationIsRunningObserver& operator=(
  311. const RemoveWhileNotificationIsRunningObserver&) = delete;
  312. ~RemoveWhileNotificationIsRunningObserver() override = default;
  313. void Observe(int x) override {
  314. notification_running_.Signal();
  315. ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives;
  316. barrier_.Wait();
  317. }
  318. void WaitForNotificationRunning() { notification_running_.Wait(); }
  319. void Unblock() { barrier_.Signal(); }
  320. private:
  321. WaitableEvent notification_running_;
  322. WaitableEvent barrier_;
  323. };
  324. } // namespace
  325. // Verify that there is no crash when an observer is removed while it is being
  326. // notified.
  327. TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) {
  328. auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
  329. RemoveWhileNotificationIsRunningObserver observer;
  330. WaitableEvent task_running(WaitableEvent::ResetPolicy::AUTOMATIC,
  331. WaitableEvent::InitialState::NOT_SIGNALED);
  332. WaitableEvent barrier(WaitableEvent::ResetPolicy::AUTOMATIC,
  333. WaitableEvent::InitialState::NOT_SIGNALED);
  334. // This must be after the declaration of |barrier| so that tasks posted to
  335. // ThreadPool can safely use |barrier|.
  336. test::TaskEnvironment task_environment;
  337. ThreadPool::CreateSequencedTaskRunner({MayBlock()})
  338. ->PostTask(FROM_HERE,
  339. base::BindOnce(base::IgnoreResult(
  340. &ObserverListThreadSafe<Foo>::AddObserver),
  341. observer_list, Unretained(&observer)));
  342. ThreadPoolInstance::Get()->FlushForTesting();
  343. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  344. observer.WaitForNotificationRunning();
  345. observer_list->RemoveObserver(&observer);
  346. observer.Unblock();
  347. }
  348. TEST(ObserverListThreadSafeTest, AddRemoveWithPendingNotifications) {
  349. test::TaskEnvironment task_environment;
  350. scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
  351. new ObserverListThreadSafe<Foo>);
  352. Adder a(1);
  353. Adder b(1);
  354. observer_list->AddObserver(&a);
  355. observer_list->AddObserver(&b);
  356. // Remove observer `a` while there is a pending notification for observer `a`.
  357. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  358. observer_list->RemoveObserver(&a);
  359. RunLoop().RunUntilIdle();
  360. observer_list->AddObserver(&a);
  361. EXPECT_EQ(0, a.total);
  362. EXPECT_EQ(10, b.total);
  363. // Remove and re-adding observer `a` while there is a pending notification for
  364. // observer `a`. The notification to `a` must not be executed since it was
  365. // sent before the removal of `a`.
  366. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  367. observer_list->RemoveObserver(&a);
  368. observer_list->AddObserver(&a);
  369. RunLoop().RunUntilIdle();
  370. EXPECT_EQ(0, a.total);
  371. EXPECT_EQ(20, b.total);
  372. // Observer `a` and `b` are present and should both receive a notification.
  373. observer_list->RemoveObserver(&a);
  374. observer_list->AddObserver(&a);
  375. observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
  376. RunLoop().RunUntilIdle();
  377. EXPECT_EQ(10, a.total);
  378. EXPECT_EQ(30, b.total);
  379. }
  380. // Same as ObserverListTest.Existing, but for ObserverListThreadSafe
  381. TEST(ObserverListThreadSafeTest, Existing) {
  382. test::TaskEnvironment task_environment;
  383. scoped_refptr<ObserverListThreadSafe<Foo>> observer_list(
  384. new ObserverListThreadSafe<Foo>(ObserverListPolicy::EXISTING_ONLY));
  385. Adder a(1);
  386. AddInObserve b(observer_list.get());
  387. Adder c(1);
  388. b.SetToAdd(&c);
  389. observer_list->AddObserver(&a);
  390. observer_list->AddObserver(&b);
  391. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  392. RunLoop().RunUntilIdle();
  393. EXPECT_FALSE(b.to_add_);
  394. // B's adder should not have been notified because it was added during
  395. // notification.
  396. EXPECT_EQ(0, c.total);
  397. // Notify again to make sure b's adder is notified.
  398. observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
  399. RunLoop().RunUntilIdle();
  400. EXPECT_EQ(1, c.total);
  401. }
  402. } // namespace base