Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / sync / internal_api / public / engine / model_safe_worker.cc
blobeb3fc1f1c3ec286c961e743b23b05e77a7eae358
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 base::DictionaryValue* ModelSafeRoutingInfoToValue(
15 const ModelSafeRoutingInfo& routing_info) {
16 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 scoped_ptr<base::DictionaryValue> dict(
28 ModelSafeRoutingInfoToValue(routing_info));
29 std::string json;
30 base::JSONWriter::Write(dict.get(), &json);
31 return json;
34 ModelTypeSet GetRoutingInfoTypes(const ModelSafeRoutingInfo& routing_info) {
35 ModelTypeSet types;
36 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
37 it != routing_info.end(); ++it) {
38 types.Put(it->first);
40 return types;
43 ModelSafeGroup GetGroupForModelType(const ModelType type,
44 const ModelSafeRoutingInfo& routes) {
45 ModelSafeRoutingInfo::const_iterator it = routes.find(type);
46 if (it == routes.end()) {
47 if (type != UNSPECIFIED && type != TOP_LEVEL_FOLDER)
48 DVLOG(1) << "Entry does not belong to active ModelSafeGroup!";
49 return GROUP_PASSIVE;
51 return it->second;
54 std::string ModelSafeGroupToString(ModelSafeGroup group) {
55 switch (group) {
56 case GROUP_UI:
57 return "GROUP_UI";
58 case GROUP_DB:
59 return "GROUP_DB";
60 case GROUP_FILE:
61 return "GROUP_FILE";
62 case GROUP_HISTORY:
63 return "GROUP_HISTORY";
64 case GROUP_PASSIVE:
65 return "GROUP_PASSIVE";
66 case GROUP_PASSWORD:
67 return "GROUP_PASSWORD";
68 default:
69 NOTREACHED();
70 return "INVALID";
74 ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer)
75 : stopped_(false),
76 work_done_or_stopped_(false, false),
77 observer_(observer),
78 working_loop_(NULL),
79 working_loop_set_wait_(true, false) {}
81 ModelSafeWorker::~ModelSafeWorker() {}
83 void ModelSafeWorker::RequestStop() {
84 base::AutoLock al(stopped_lock_);
86 // Set stop flag but don't signal work_done_or_stopped_ to unblock sync loop
87 // because the worker may be working and depending on sync command object
88 // living on sync thread. his prevents any *further* tasks from being posted
89 // to worker threads (see DoWorkAndWaitUntilDone below), but note that one
90 // may already be posted.
91 stopped_ = true;
94 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) {
96 base::AutoLock al(stopped_lock_);
97 if (stopped_)
98 return CANNOT_DO_WORK;
100 CHECK(!work_done_or_stopped_.IsSignaled());
103 return DoWorkAndWaitUntilDoneImpl(work);
106 bool ModelSafeWorker::IsStopped() {
107 base::AutoLock al(stopped_lock_);
108 return stopped_;
111 void ModelSafeWorker::WillDestroyCurrentMessageLoop() {
113 base::AutoLock al(stopped_lock_);
114 stopped_ = true;
116 // Must signal to unblock syncer if it's waiting for a posted task to
117 // finish. At this point, all pending tasks posted to the loop have been
118 // destroyed (see MessageLoop::~MessageLoop). So syncer will be blocked
119 // indefinitely without signaling here.
120 work_done_or_stopped_.Signal();
122 DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup())
123 << " worker stops on destruction of its working thread.";
127 base::AutoLock l(working_loop_lock_);
128 working_loop_ = NULL;
131 if (observer_)
132 observer_->OnWorkerLoopDestroyed(GetModelSafeGroup());
135 void ModelSafeWorker::SetWorkingLoopToCurrent() {
136 base::AutoLock l(working_loop_lock_);
137 DCHECK(!working_loop_);
138 working_loop_ = base::MessageLoop::current();
139 working_loop_set_wait_.Signal();
142 void ModelSafeWorker::UnregisterForLoopDestruction(
143 base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
144 // Ok to wait until |working_loop_| is set because this is called on sync
145 // loop.
146 working_loop_set_wait_.Wait();
149 base::AutoLock l(working_loop_lock_);
150 if (working_loop_ != NULL) {
151 // Should be called on sync loop.
152 DCHECK_NE(base::MessageLoop::current(), working_loop_);
153 working_loop_->PostTask(
154 FROM_HERE,
155 base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync,
156 this, unregister_done_callback));
161 void ModelSafeWorker::UnregisterForLoopDestructionAsync(
162 base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
164 base::AutoLock l(working_loop_lock_);
165 if (!working_loop_)
166 return;
167 DCHECK_EQ(base::MessageLoop::current(), working_loop_);
170 DCHECK(stopped_);
171 base::MessageLoop::current()->RemoveDestructionObserver(this);
172 unregister_done_callback.Run(GetModelSafeGroup());
175 } // namespace syncer