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 "components/sync/driver/glue/ui_model_worker.h" | 5 #include "components/sync/driver/glue/ui_model_worker.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/location.h" | 9 #include "base/location.h" |
10 #include "base/memory/ref_counted.h" | 10 #include "base/memory/ref_counted.h" |
(...skipping 14 matching lines...) Expand all Loading... | |
25 work.Run(); | 25 work.Run(); |
26 return SYNCER_OK; | 26 return SYNCER_OK; |
27 } | 27 } |
28 | 28 |
29 // Converts |work| to a WorkCallback that will verify that it's run on the | 29 // Converts |work| to a WorkCallback that will verify that it's run on the |
30 // thread it was constructed on. | 30 // thread it was constructed on. |
31 WorkCallback ClosureToWorkCallback(base::Closure work) { | 31 WorkCallback ClosureToWorkCallback(base::Closure work) { |
32 return base::Bind(&DoWork, base::ThreadTaskRunnerHandle::Get(), work); | 32 return base::Bind(&DoWork, base::ThreadTaskRunnerHandle::Get(), work); |
33 } | 33 } |
34 | 34 |
35 // This function runs on the sync thread. | |
36 void SignalAndDoWork(scoped_refptr<UIModelWorker> worker, | |
37 WorkCallback work, | |
38 base::WaitableEvent* event) { | |
39 if (event) | |
fdoray
2016/11/14 14:24:34
EXPECT_TRUE(event) since we don't expect |event| t
maxbogue
2016/11/14 20:53:21
n/a, event is no longer needed.
| |
40 event->Signal(); | |
41 worker->DoWorkAndWaitUntilDone(work); | |
42 } | |
43 | |
35 class SyncUIModelWorkerTest : public testing::Test { | 44 class SyncUIModelWorkerTest : public testing::Test { |
36 public: | 45 public: |
37 SyncUIModelWorkerTest() : sync_thread_("SyncThreadForTest") { | 46 SyncUIModelWorkerTest() : sync_thread_("SyncThreadForTest") { |
38 sync_thread_.Start(); | 47 sync_thread_.Start(); |
39 worker_ = new UIModelWorker(base::ThreadTaskRunnerHandle::Get()); | 48 worker_ = new UIModelWorker(base::ThreadTaskRunnerHandle::Get()); |
40 } | 49 } |
41 | 50 |
42 void PostWorkToSyncThread(WorkCallback work) { | 51 void PostWorkToSyncThread(base::Closure work, |
52 base::WaitableEvent* task_on_sync_thread_event) { | |
43 sync_thread_.task_runner()->PostTask( | 53 sync_thread_.task_runner()->PostTask( |
44 FROM_HERE, | 54 FROM_HERE, |
45 base::Bind(base::IgnoreResult(&UIModelWorker::DoWorkAndWaitUntilDone), | 55 base::Bind(&SignalAndDoWork, worker_, ClosureToWorkCallback(work), |
46 worker_, work)); | 56 task_on_sync_thread_event)); |
47 } | 57 } |
48 | 58 |
59 void StopSyncThread() { sync_thread_.Stop(); } | |
60 | |
61 UIModelWorker* worker() { return worker_.get(); } | |
62 | |
49 private: | 63 private: |
64 // Worker must outlive message loop. | |
65 scoped_refptr<UIModelWorker> worker_; | |
50 base::MessageLoop ui_loop_; | 66 base::MessageLoop ui_loop_; |
51 base::Thread sync_thread_; | 67 base::Thread sync_thread_; |
52 scoped_refptr<UIModelWorker> worker_; | |
53 }; | 68 }; |
54 | 69 |
55 TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) { | 70 TEST_F(SyncUIModelWorkerTest, ScheduledWorkRunsOnUILoop) { |
56 base::RunLoop run_loop; | 71 base::RunLoop run_loop; |
57 PostWorkToSyncThread(ClosureToWorkCallback(run_loop.QuitClosure())); | 72 PostWorkToSyncThread(run_loop.QuitClosure(), nullptr); |
58 // This won't quit until the QuitClosure is run. | 73 // This won't quit until the QuitClosure is run. |
59 run_loop.Run(); | 74 run_loop.Run(); |
60 } | 75 } |
61 | 76 |
77 TEST_F(SyncUIModelWorkerTest, ShutdownNoDeadlock) { | |
78 // We need some way to wait until the sync thread has our task. | |
79 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, | |
80 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
81 | |
82 PostWorkToSyncThread(base::Bind(&SyncUIModelWorkerTest::StopSyncThread, | |
83 base::Unretained(this)), | |
84 &event); | |
85 | |
86 // Wait until the sync thread has started our task. | |
87 event.Wait(); | |
88 | |
89 // This is a little racy. We're banking on this stop signal to occur after the | |
90 // sync thread has progressed past the stopped check. However, if it doesn't, | |
91 // we just get a false positive (no flakes). | |
fdoray
2016/11/14 14:24:34
I think the test below avoids false positives (the
maxbogue
2016/11/14 20:53:21
Of course, just do everything inside the work clos
| |
92 worker()->RequestStop(); | |
93 | |
94 // Now we yield control of the UI thread. The stop signal has unblocked the | |
95 // sync thread, so the UI thread task can join the sync thread without | |
96 // deadlocking. | |
97 base::RunLoop().RunUntilIdle(); | |
98 } | |
99 | |
62 } // namespace | 100 } // namespace |
63 } // namespace syncer | 101 } // namespace syncer |
OLD | NEW |