Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / sync / internal_api / public / engine / model_safe_worker.cc
blobd43389d58fb08b326b667048bc20e71e5bec14c4
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.
5 #include "sync/internal_api/public/engine/model_safe_worker.h"
7 #include "base/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
12 namespace syncer {
14 scoped_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue(
15 const ModelSafeRoutingInfo& routing_info) {
16 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
17 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
18 it != routing_info.end(); ++it) {
19 dict->SetString(ModelTypeToString(it->first),
20 ModelSafeGroupToString(it->second));
22 return dict;
25 std::string ModelSafeRoutingInfoToString(
26 const ModelSafeRoutingInfo& routing_info) {
27 std::string json;
28 base::JSONWriter::Write(*ModelSafeRoutingInfoToValue(routing_info), &json);
29 return json;
32 ModelTypeSet GetRoutingInfoTypes(const ModelSafeRoutingInfo& routing_info) {
33 ModelTypeSet types;
34 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
35 it != routing_info.end(); ++it) {
36 types.Put(it->first);
38 return types;
41 ModelSafeGroup GetGroupForModelType(const ModelType type,
42 const ModelSafeRoutingInfo& routes) {
43 ModelSafeRoutingInfo::const_iterator it = routes.find(type);
44 if (it == routes.end()) {
45 if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER)
46 DVLOG(1) << "Entry does not belong to active ModelSafeGroup!";
47 return GROUP_PASSIVE;
49 return it->second;
52 std::string ModelSafeGroupToString(ModelSafeGroup group) {
53 switch (group) {
54 case GROUP_UI:
55 return "GROUP_UI";
56 case GROUP_DB:
57 return "GROUP_DB";
58 case GROUP_FILE:
59 return "GROUP_FILE";
60 case GROUP_HISTORY:
61 return "GROUP_HISTORY";
62 case GROUP_PASSIVE:
63 return "GROUP_PASSIVE";
64 case GROUP_PASSWORD:
65 return "GROUP_PASSWORD";
66 default:
67 NOTREACHED();
68 return "INVALID";
72 ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer)
73 : stopped_(false),
74 work_done_or_stopped_(false, false),
75 observer_(observer),
76 working_loop_(NULL) {
79 ModelSafeWorker::~ModelSafeWorker() {}
81 void ModelSafeWorker::RequestStop() {
82 base::AutoLock al(stopped_lock_);
84 // Set stop flag but don't signal work_done_or_stopped_ to unblock sync loop
85 // because the worker may be working and depending on sync command object
86 // living on sync thread. This prevents any *further* tasks from being posted
87 // to worker threads (see DoWorkAndWaitUntilDone below), but note that one
88 // may already be posted.
89 stopped_ = true;
92 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) {
94 base::AutoLock al(stopped_lock_);
95 if (stopped_)
96 return CANNOT_DO_WORK;
98 CHECK(!work_done_or_stopped_.IsSignaled());
101 return DoWorkAndWaitUntilDoneImpl(work);
104 bool ModelSafeWorker::IsStopped() {
105 base::AutoLock al(stopped_lock_);
106 return stopped_;
109 void ModelSafeWorker::WillDestroyCurrentMessageLoop() {
111 base::AutoLock al(stopped_lock_);
112 stopped_ = true;
114 // Must signal to unblock syncer if it's waiting for a posted task to
115 // finish. At this point, all pending tasks posted to the loop have been
116 // destroyed (see MessageLoop::~MessageLoop). So syncer will be blocked
117 // indefinitely without signaling here.
118 work_done_or_stopped_.Signal();
120 DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup())
121 << " worker stops on destruction of its working thread.";
125 base::AutoLock l(working_loop_lock_);
126 working_loop_ = NULL;
129 if (observer_)
130 observer_->OnWorkerLoopDestroyed(GetModelSafeGroup());
133 void ModelSafeWorker::SetWorkingLoopToCurrent() {
134 base::Callback<void(ModelSafeGroup)> unregister_done_callback;
137 base::AutoLock l(working_loop_lock_);
138 DCHECK(!working_loop_);
140 if (unregister_done_callback_.is_null()) {
141 // Expected case - UnregisterForLoopDestruction hasn't been called yet.
142 base::MessageLoop::current()->AddDestructionObserver(this);
143 working_loop_ = base::MessageLoop::current();
144 } else {
145 // Rare case which is possible when the model type thread remains
146 // blocked for the entire session and UnregisterForLoopDestruction ends
147 // up being called before this method. This method is posted unlike
148 // UnregisterForLoopDestruction - that's why they can end up being called
149 // out of order.
150 // In this case we skip the destruction observer registration
151 // and just invoke the callback stored at UnregisterForLoopDestruction.
152 DCHECK(stopped_);
153 unregister_done_callback = unregister_done_callback_;
154 unregister_done_callback_.Reset();
158 if (!unregister_done_callback.is_null()) {
159 unregister_done_callback.Run(GetModelSafeGroup());
163 void ModelSafeWorker::UnregisterForLoopDestruction(
164 base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
165 base::AutoLock l(working_loop_lock_);
166 if (working_loop_ != NULL) {
167 // Normal case - observer registration has been already done.
168 // Delegate to the sync thread to do the actual unregistration in
169 // UnregisterForLoopDestructionAsync.
170 DCHECK_NE(base::MessageLoop::current(), working_loop_);
171 working_loop_->PostTask(
172 FROM_HERE,
173 base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync,
174 this,
175 unregister_done_callback));
176 } else {
177 // The working loop is still unknown, probably because the model type
178 // thread is blocked. Store the callback to be called from
179 // SetWorkingLoopToCurrent.
180 unregister_done_callback_ = unregister_done_callback;
184 void ModelSafeWorker::UnregisterForLoopDestructionAsync(
185 base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
187 base::AutoLock l(working_loop_lock_);
188 if (!working_loop_)
189 return;
190 DCHECK_EQ(base::MessageLoop::current(), working_loop_);
193 DCHECK(stopped_);
194 base::MessageLoop::current()->RemoveDestructionObserver(this);
195 unregister_done_callback.Run(GetModelSafeGroup());
198 } // namespace syncer