1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file. 4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "sync/internal_api/public/base/cancelation_signal.h" 6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 7d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/bind.h" 8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/message_loop/message_loop.h" 9d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/synchronization/waitable_event.h" 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/platform_thread.h" 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "base/threading/thread.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/time/time.h" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "sync/internal_api/public/base/cancelation_observer.h" 14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 15d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace syncer { 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class BlockingTask : public CancelationObserver { 19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public: 20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) BlockingTask(CancelationSignal* cancel_signal); 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual ~BlockingTask(); 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Starts the |exec_thread_| and uses it to execute DoRun(). 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void RunAsync(base::WaitableEvent* task_start_signal, 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent* task_done_signal); 26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Blocks until canceled. Signals |task_done_signal| when finished (either 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // via early cancel or cancel after start). Signals |task_start_signal| if 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // and when the task starts successfully (which will not happen if the task 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // was cancelled early). 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void Run(base::WaitableEvent* task_start_signal, 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent* task_done_signal); 33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Implementation of CancelationObserver. 35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Wakes up the thread blocked in Run(). 36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void OnSignalReceived() OVERRIDE; 37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Checks if we ever did successfully start waiting for |event_|. Be careful 39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // with this. The flag itself is thread-unsafe, and the event that flips it 40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // is racy. 41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) bool WasStarted(); 42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private: 44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::WaitableEvent event_; 45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Thread exec_thread_; 46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelationSignal* cancel_signal_; 47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) bool was_started_; 48d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}; 49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)BlockingTask::BlockingTask(CancelationSignal* cancel_signal) 51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : event_(true, false), 52d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) exec_thread_("BlockingTaskBackgroundThread"), 53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) cancel_signal_(cancel_signal), 54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) was_started_(false) { } 55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)BlockingTask::~BlockingTask() { 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (was_started_) { 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) cancel_signal_->UnregisterHandler(this); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BlockingTask::RunAsync(base::WaitableEvent* task_start_signal, 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent* task_done_signal) { 64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) exec_thread_.Start(); 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) exec_thread_.message_loop()->PostTask( 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FROM_HERE, 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Bind(&BlockingTask::Run, 68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(this), 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(task_start_signal), 70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(task_done_signal))); 71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void BlockingTask::Run( 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent* task_start_signal, 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent* task_done_signal) { 76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (cancel_signal_->TryRegisterHandler(this)) { 77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(!event_.IsSignaled()); 78d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) was_started_ = true; 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) task_start_signal->Signal(); 80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) event_.Wait(); 81d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 82d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) task_done_signal->Signal(); 83d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 84d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 85d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BlockingTask::OnSignalReceived() { 86d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) event_.Signal(); 87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool BlockingTask::WasStarted() { 90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return was_started_; 91d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class CancelationSignalTest : public ::testing::Test { 94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) public: 95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelationSignalTest(); 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual ~CancelationSignalTest(); 97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Starts the blocking task on a background thread. Does not wait for the 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // task to start. 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void StartBlockingTaskAsync(); 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Starts the blocking task on a background thread. Does not return until 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the task has been started. 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void StartBlockingTaskAndWaitForItToStart(); 105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Cancels the blocking task. 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) void CancelBlocking(); 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Verifies that the background task was canceled early. 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 111d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // This method may block for a brief period of time while waiting for the 112d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // background thread to make progress. 113d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) bool VerifyTaskNotStarted(); 114d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 115d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) private: 116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::MessageLoop main_loop_; 117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 118d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelationSignal signal_; 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WaitableEvent task_start_event_; 120d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::WaitableEvent task_done_event_; 121d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) BlockingTask blocking_task_; 122d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}; 123d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)CancelationSignalTest::CancelationSignalTest() 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : task_start_event_(false, false), 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) task_done_event_(false, false), 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blocking_task_(&signal_) {} 128d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 129d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)CancelationSignalTest::~CancelationSignalTest() {} 130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CancelationSignalTest::StartBlockingTaskAsync() { 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blocking_task_.RunAsync(&task_start_event_, &task_done_event_); 133d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 134d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CancelationSignalTest::StartBlockingTaskAndWaitForItToStart() { 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) blocking_task_.RunAsync(&task_start_event_, &task_done_event_); 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) task_start_event_.Wait(); 138d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 139d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CancelationSignalTest::CancelBlocking() { 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) signal_.Signal(); 142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 143d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 144d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool CancelationSignalTest::VerifyTaskNotStarted() { 145d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Wait until BlockingTask::Run() has finished. 146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) task_done_event_.Wait(); 147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 148d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Verify the background thread never started blocking. 149d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return !blocking_task_.WasStarted(); 150d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 151d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 152d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class FakeCancelationObserver : public CancelationObserver { 153d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) virtual void OnSignalReceived() OVERRIDE { } 154d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}; 155d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 156d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST(CancelationSignalTest_SingleThread, CheckFlags) { 157d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FakeCancelationObserver observer; 158d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelationSignal signal; 159d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 160d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_FALSE(signal.IsSignalled()); 161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) signal.Signal(); 162d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_TRUE(signal.IsSignalled()); 163d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_FALSE(signal.TryRegisterHandler(&observer)); 164d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 165d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 166d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Send the cancelation signal before the task is started. This will ensure 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// that the task will never be "started" (ie. TryRegisterHandler() will fail, 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// so it will never start blocking on its main WaitableEvent). 169d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(CancelationSignalTest, CancelEarly) { 170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelBlocking(); 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StartBlockingTaskAsync(); 172d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) EXPECT_TRUE(VerifyTaskNotStarted()); 173d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 174d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Send the cancelation signal after the task has started running. This tests 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// the non-early exit code path, where the task is stopped while it is in 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// progress. 178d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)TEST_F(CancelationSignalTest, Cancel) { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) StartBlockingTaskAndWaitForItToStart(); 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Wait for the task to finish and let verify it has been started. 182d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) CancelBlocking(); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(VerifyTaskNotStarted()); 184d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 185d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 186d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} // namespace syncer 187