Chromium Code Reviews| 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 |