- add sources.
[platform/framework/web/crosswalk.git] / src / sync / internal_api / public / engine / model_safe_worker.cc
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 "sync/internal_api/public/engine/model_safe_worker.h"
6
7 #include "base/bind.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/values.h"
11
12 namespace syncer {
13
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));
21   }
22   return dict;
23 }
24
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;
32 }
33
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);
39   }
40   return types;
41 }
42
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;
50   }
51   return it->second;
52 }
53
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";
71   }
72 }
73
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) {}
80
81 ModelSafeWorker::~ModelSafeWorker() {}
82
83 void ModelSafeWorker::RequestStop() {
84   base::AutoLock al(stopped_lock_);
85
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;
92 }
93
94 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) {
95   {
96     base::AutoLock al(stopped_lock_);
97     if (stopped_)
98       return CANNOT_DO_WORK;
99
100     CHECK(!work_done_or_stopped_.IsSignaled());
101   }
102
103   return DoWorkAndWaitUntilDoneImpl(work);
104 }
105
106 bool ModelSafeWorker::IsStopped() {
107   base::AutoLock al(stopped_lock_);
108   return stopped_;
109 }
110
111 void ModelSafeWorker::WillDestroyCurrentMessageLoop() {
112   {
113     base::AutoLock al(stopped_lock_);
114     stopped_ = true;
115
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();
121
122     DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup())
123         << " worker stops on destruction of its working thread.";
124   }
125
126   {
127     base::AutoLock l(working_loop_lock_);
128     working_loop_ = NULL;
129   }
130
131   if (observer_)
132     observer_->OnWorkerLoopDestroyed(GetModelSafeGroup());
133 }
134
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();
140 }
141
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();
147
148   {
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));
157     }
158   }
159 }
160
161 void ModelSafeWorker::UnregisterForLoopDestructionAsync(
162     base::Callback<void(ModelSafeGroup)> unregister_done_callback) {
163   {
164     base::AutoLock l(working_loop_lock_);
165     if (!working_loop_)
166       return;
167     DCHECK_EQ(base::MessageLoop::current(), working_loop_);
168   }
169
170   DCHECK(stopped_);
171   base::MessageLoop::current()->RemoveDestructionObserver(this);
172   unregister_done_callback.Run(GetModelSafeGroup());
173 }
174
175 }  // namespace syncer