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 15using content::BrowserThread; 16 17namespace browser_sync { 18 19namespace { 20 21// A simple callback to signal a waitable event after running a closure. 22void 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 44UIModelWorker::UIModelWorker(syncer::WorkerLoopDestructionObserver* observer) 45 : syncer::ModelSafeWorker(observer) { 46} 47 48void UIModelWorker::RegisterForLoopDestruction() { 49 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 50 SetWorkingLoopToCurrent(); 51} 52 53syncer::SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl( 54 const syncer::WorkCallback& work) { 55 syncer::SyncerError error_info; 56 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 57 DLOG(WARNING) << "DoWorkAndWaitUntilDone called from " 58 << "ui_loop_. Probably a nested invocation?"; 59 return work.Run(); 60 } 61 62 if (!BrowserThread::PostTask( 63 BrowserThread::UI, FROM_HERE, 64 base::Bind(&CallDoWorkAndSignalCallback, 65 work, work_done_or_stopped(), &error_info))) { 66 DLOG(WARNING) << "Could not post work to UI loop."; 67 error_info = syncer::CANNOT_DO_WORK; 68 return error_info; 69 } 70 work_done_or_stopped()->Wait(); 71 72 return error_info; 73} 74 75syncer::ModelSafeGroup UIModelWorker::GetModelSafeGroup() { 76 return syncer::GROUP_UI; 77} 78 79UIModelWorker::~UIModelWorker() { 80} 81 82} // namespace browser_sync 83