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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync/glue/ui_model_worker.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/synchronization/waitable_event.h" 11 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 12 #include "base/threading/thread_restrictions.h" 13 #include "content/public/browser/browser_thread.h" 14 15 using content::BrowserThread; 16 17 namespace browser_sync { 18 19 namespace { 20 21 // A simple callback to signal a waitable event after running a closure. 22 void CallDoWorkAndSignalCallback(const syncer::WorkCallback& work, 23 base::WaitableEvent* work_done, 24 syncer::SyncerError* error_info) { 25 if (work.is_null()) { 26 // This can happen during tests or cases where there are more than just the 27 // default UIModelWorker in existence and it gets destroyed before 28 // the main UI loop has terminated. There is no easy way to assert the 29 // loop is running / not running at the moment, so we just provide cancel 30 // semantics here and short-circuit. 31 // TODO(timsteele): Maybe we should have the message loop destruction 32 // observer fire when the loop has ended, just a bit before it 33 // actually gets destroyed. 34 return; 35 } 36 37 *error_info = work.Run(); 38 39 work_done->Signal(); // Unblock the syncer thread that scheduled us. 40 } 41 42 } // namespace 43 44 UIModelWorker::UIModelWorker(syncer::WorkerLoopDestructionObserver* observer) 45 : syncer::ModelSafeWorker(observer) { 46 } 47 48 void UIModelWorker::RegisterForLoopDestruction() { 49 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 50 base::MessageLoop::current()->AddDestructionObserver(this); 51 SetWorkingLoopToCurrent(); 52 } 53 54 syncer::SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl( 55 const syncer::WorkCallback& work) { 56 syncer::SyncerError error_info; 57 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 58 DLOG(WARNING) << "DoWorkAndWaitUntilDone called from " 59 << "ui_loop_. Probably a nested invocation?"; 60 return work.Run(); 61 } 62 63 if (!BrowserThread::PostTask( 64 BrowserThread::UI, FROM_HERE, 65 base::Bind(&CallDoWorkAndSignalCallback, 66 work, work_done_or_stopped(), &error_info))) { 67 DLOG(WARNING) << "Could not post work to UI loop."; 68 error_info = syncer::CANNOT_DO_WORK; 69 return error_info; 70 } 71 work_done_or_stopped()->Wait(); 72 73 return error_info; 74 } 75 76 syncer::ModelSafeGroup UIModelWorker::GetModelSafeGroup() { 77 return syncer::GROUP_UI; 78 } 79 80 UIModelWorker::~UIModelWorker() { 81 } 82 83 } // namespace browser_sync 84