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
|
// 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 "components/sync/engine/ui_model_worker.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "components/sync/base/scoped_event_signal.h"
namespace syncer {
namespace {
class ScopedEventSignalWithWorker {
public:
ScopedEventSignalWithWorker(scoped_refptr<UIModelWorker> ui_model_worker,
base::WaitableEvent* event)
: ui_model_worker_(std::move(ui_model_worker)),
scoped_event_signal_(event) {}
ScopedEventSignalWithWorker(ScopedEventSignalWithWorker&&) = default;
ScopedEventSignalWithWorker& operator=(ScopedEventSignalWithWorker&&) =
default;
bool IsStopped() const { return ui_model_worker_->IsStopped(); }
private:
// This reference prevents the event in |scoped_event_signal_| from being
// signaled after being deleted.
scoped_refptr<UIModelWorker> ui_model_worker_;
ScopedEventSignal scoped_event_signal_;
DISALLOW_COPY_AND_ASSIGN(ScopedEventSignalWithWorker);
};
void CallDoWorkAndSignalEvent(
const WorkCallback& work,
ScopedEventSignalWithWorker scoped_event_signal_with_worker,
SyncerError* error_info) {
if (!scoped_event_signal_with_worker.IsStopped())
*error_info = work.Run();
// The event in |scoped_event_signal_with_worker| is signaled at the end of
// this scope.
}
} // namespace
UIModelWorker::UIModelWorker(
scoped_refptr<base::SingleThreadTaskRunner> ui_thread)
: ui_thread_(std::move(ui_thread)),
work_done_or_abandoned_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
stop_requested_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
sequence_checker_.DetachFromSequence();
}
SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl(
const WorkCallback& work) {
DCHECK(sequence_checker_.CalledOnValidSequence());
DCHECK(!ui_thread_->BelongsToCurrentThread());
SyncerError error_info;
work_done_or_abandoned_.Reset();
if (!ui_thread_->PostTask(
FROM_HERE,
base::Bind(&CallDoWorkAndSignalEvent, work,
base::Passed(syncer::ScopedEventSignalWithWorker(
this, &work_done_or_abandoned_)),
&error_info))) {
DLOG(WARNING) << "Could not post work to UI loop.";
error_info = CANNOT_DO_WORK;
return error_info;
}
base::WaitableEvent* events[] = {&work_done_or_abandoned_, &stop_requested_};
base::WaitableEvent::WaitMany(events, arraysize(events));
return error_info;
}
void UIModelWorker::RequestStop() {
DCHECK(ui_thread_->BelongsToCurrentThread());
ModelSafeWorker::RequestStop();
stop_requested_.Signal();
}
ModelSafeGroup UIModelWorker::GetModelSafeGroup() {
return GROUP_UI;
}
bool UIModelWorker::IsOnModelThread() {
return ui_thread_->BelongsToCurrentThread();
}
UIModelWorker::~UIModelWorker() {}
} // namespace syncer
|