1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sync/glue/history_model_worker.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h"
#include "content/public/browser/browser_thread.h"
using base::WaitableEvent;
using content::BrowserThread;
namespace browser_sync {
class WorkerTask : public history::HistoryDBTask {
public:
WorkerTask(
const syncer::WorkCallback& work,
WaitableEvent* done,
syncer::SyncerError* error)
: work_(work), done_(done), error_(error) {}
bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) override {
*error_ = work_.Run();
done_->Signal();
return true;
}
// Since the DoWorkAndWaitUntilDone() is synchronous, we don't need to run
// any code asynchronously on the main thread after completion.
void DoneRunOnMainThread() override {}
protected:
~WorkerTask() override {}
syncer::WorkCallback work_;
WaitableEvent* done_;
syncer::SyncerError* error_;
};
class AddDBThreadObserverTask : public history::HistoryDBTask {
public:
explicit AddDBThreadObserverTask(base::Closure register_callback)
: register_callback_(register_callback) {}
bool RunOnDBThread(history::HistoryBackend* backend,
history::HistoryDatabase* db) override {
register_callback_.Run();
return true;
}
void DoneRunOnMainThread() override {}
private:
~AddDBThreadObserverTask() override {}
base::Closure register_callback_;
};
namespace {
// Post the work task on |history_service|'s DB thread from the UI
// thread.
void PostWorkerTask(const base::WeakPtr<HistoryService>& history_service,
const syncer::WorkCallback& work,
base::CancelableTaskTracker* cancelable_tracker,
WaitableEvent* done,
syncer::SyncerError* error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (history_service.get()) {
scoped_ptr<history::HistoryDBTask> task(new WorkerTask(work, done, error));
history_service->ScheduleDBTask(task.Pass(), cancelable_tracker);
} else {
*error = syncer::CANNOT_DO_WORK;
done->Signal();
}
}
} // namespace
HistoryModelWorker::HistoryModelWorker(
const base::WeakPtr<HistoryService>& history_service,
syncer::WorkerLoopDestructionObserver* observer)
: syncer::ModelSafeWorker(observer),
history_service_(history_service) {
CHECK(history_service.get());
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
cancelable_tracker_.reset(new base::CancelableTaskTracker);
}
void HistoryModelWorker::RegisterForLoopDestruction() {
CHECK(history_service_.get());
history_service_->ScheduleDBTask(
scoped_ptr<history::HistoryDBTask>(new AddDBThreadObserverTask(
base::Bind(&HistoryModelWorker::RegisterOnDBThread, this))),
cancelable_tracker_.get());
}
void HistoryModelWorker::RegisterOnDBThread() {
SetWorkingLoopToCurrent();
}
syncer::SyncerError HistoryModelWorker::DoWorkAndWaitUntilDoneImpl(
const syncer::WorkCallback& work) {
syncer::SyncerError error = syncer::UNSET;
if (BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(&PostWorkerTask,
history_service_,
work,
cancelable_tracker_.get(),
work_done_or_stopped(),
&error))) {
work_done_or_stopped()->Wait();
} else {
error = syncer::CANNOT_DO_WORK;
}
return error;
}
syncer::ModelSafeGroup HistoryModelWorker::GetModelSafeGroup() {
return syncer::GROUP_HISTORY;
}
HistoryModelWorker::~HistoryModelWorker() {
// The base::CancelableTaskTracker class is not thread-safe and must only be
// used from a single thread but the current object may not be destroyed from
// the UI thread, so delete it from the UI thread.
BrowserThread::DeleteOnUIThread::Destruct(cancelable_tracker_.release());
}
} // namespace browser_sync
|