Home | History | Annotate | Download | only in glue
      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