| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "sync/internal_api/public/engine/model_safe_worker.h" | 5 #include "sync/internal_api/public/engine/model_safe_worker.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/json/json_writer.h" | 10 #include "base/json/json_writer.h" |
| 11 #include "base/threading/thread_task_runner_handle.h" |
| 11 #include "base/values.h" | 12 #include "base/values.h" |
| 12 | 13 |
| 13 namespace syncer { | 14 namespace syncer { |
| 14 | 15 |
| 15 std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue( | 16 std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue( |
| 16 const ModelSafeRoutingInfo& routing_info) { | 17 const ModelSafeRoutingInfo& routing_info) { |
| 17 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 18 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| 18 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); | 19 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); |
| 19 it != routing_info.end(); ++it) { | 20 it != routing_info.end(); ++it) { |
| 20 dict->SetString(ModelTypeToString(it->first), | 21 dict->SetString(ModelTypeToString(it->first), |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 default: | 70 default: |
| 70 NOTREACHED(); | 71 NOTREACHED(); |
| 71 return "INVALID"; | 72 return "INVALID"; |
| 72 } | 73 } |
| 73 } | 74 } |
| 74 | 75 |
| 75 ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer) | 76 ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer) |
| 76 : stopped_(false), | 77 : stopped_(false), |
| 77 work_done_or_stopped_(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 78 work_done_or_stopped_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 78 base::WaitableEvent::InitialState::NOT_SIGNALED), | 79 base::WaitableEvent::InitialState::NOT_SIGNALED), |
| 79 observer_(observer), | 80 observer_(observer) {} |
| 80 working_loop_(NULL) {} | |
| 81 | 81 |
| 82 ModelSafeWorker::~ModelSafeWorker() {} | 82 ModelSafeWorker::~ModelSafeWorker() {} |
| 83 | 83 |
| 84 void ModelSafeWorker::RequestStop() { | 84 void ModelSafeWorker::RequestStop() { |
| 85 base::AutoLock al(stopped_lock_); | 85 base::AutoLock al(stopped_lock_); |
| 86 | 86 |
| 87 // Set stop flag but don't signal work_done_or_stopped_ to unblock sync loop | 87 // Set stop flag but don't signal work_done_or_stopped_ to unblock sync loop |
| 88 // because the worker may be working and depending on sync command object | 88 // because the worker may be working and depending on sync command object |
| 89 // living on sync thread. This prevents any *further* tasks from being posted | 89 // living on sync thread. This prevents any *further* tasks from being posted |
| 90 // to worker threads (see DoWorkAndWaitUntilDone below), but note that one | 90 // to worker threads (see DoWorkAndWaitUntilDone below), but note that one |
| (...skipping 27 matching lines...) Expand all Loading... |
| 118 // finish. At this point, all pending tasks posted to the loop have been | 118 // finish. At this point, all pending tasks posted to the loop have been |
| 119 // destroyed (see MessageLoop::~MessageLoop). So syncer will be blocked | 119 // destroyed (see MessageLoop::~MessageLoop). So syncer will be blocked |
| 120 // indefinitely without signaling here. | 120 // indefinitely without signaling here. |
| 121 work_done_or_stopped_.Signal(); | 121 work_done_or_stopped_.Signal(); |
| 122 | 122 |
| 123 DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup()) | 123 DVLOG(1) << ModelSafeGroupToString(GetModelSafeGroup()) |
| 124 << " worker stops on destruction of its working thread."; | 124 << " worker stops on destruction of its working thread."; |
| 125 } | 125 } |
| 126 | 126 |
| 127 { | 127 { |
| 128 base::AutoLock l(working_loop_lock_); | 128 base::AutoLock l(working_task_runner_lock_); |
| 129 working_loop_ = NULL; | 129 working_task_runner_ = NULL; |
| 130 } | 130 } |
| 131 | 131 |
| 132 if (observer_) | 132 if (observer_) |
| 133 observer_->OnWorkerLoopDestroyed(GetModelSafeGroup()); | 133 observer_->OnWorkerLoopDestroyed(GetModelSafeGroup()); |
| 134 } | 134 } |
| 135 | 135 |
| 136 void ModelSafeWorker::SetWorkingLoopToCurrent() { | 136 void ModelSafeWorker::SetWorkingLoopToCurrent() { |
| 137 base::Callback<void(ModelSafeGroup)> unregister_done_callback; | 137 base::Callback<void(ModelSafeGroup)> unregister_done_callback; |
| 138 | 138 |
| 139 { | 139 { |
| 140 base::AutoLock l(working_loop_lock_); | 140 base::AutoLock l(working_task_runner_lock_); |
| 141 DCHECK(!working_loop_); | 141 DCHECK(!working_task_runner_); |
| 142 | 142 |
| 143 if (unregister_done_callback_.is_null()) { | 143 if (unregister_done_callback_.is_null()) { |
| 144 // Expected case - UnregisterForLoopDestruction hasn't been called yet. | 144 // Expected case - UnregisterForLoopDestruction hasn't been called yet. |
| 145 base::MessageLoop::current()->AddDestructionObserver(this); | 145 base::MessageLoop::current()->AddDestructionObserver(this); |
| 146 working_loop_ = base::MessageLoop::current(); | 146 working_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
| 147 } else { | 147 } else { |
| 148 // Rare case which is possible when the model type thread remains | 148 // Rare case which is possible when the model type thread remains |
| 149 // blocked for the entire session and UnregisterForLoopDestruction ends | 149 // blocked for the entire session and UnregisterForLoopDestruction ends |
| 150 // up being called before this method. This method is posted unlike | 150 // up being called before this method. This method is posted unlike |
| 151 // UnregisterForLoopDestruction - that's why they can end up being called | 151 // UnregisterForLoopDestruction - that's why they can end up being called |
| 152 // out of order. | 152 // out of order. |
| 153 // In this case we skip the destruction observer registration | 153 // In this case we skip the destruction observer registration |
| 154 // and just invoke the callback stored at UnregisterForLoopDestruction. | 154 // and just invoke the callback stored at UnregisterForLoopDestruction. |
| 155 DCHECK(stopped_); | 155 DCHECK(stopped_); |
| 156 unregister_done_callback = unregister_done_callback_; | 156 unregister_done_callback = unregister_done_callback_; |
| 157 unregister_done_callback_.Reset(); | 157 unregister_done_callback_.Reset(); |
| 158 } | 158 } |
| 159 } | 159 } |
| 160 | 160 |
| 161 if (!unregister_done_callback.is_null()) { | 161 if (!unregister_done_callback.is_null()) { |
| 162 unregister_done_callback.Run(GetModelSafeGroup()); | 162 unregister_done_callback.Run(GetModelSafeGroup()); |
| 163 } | 163 } |
| 164 } | 164 } |
| 165 | 165 |
| 166 void ModelSafeWorker::UnregisterForLoopDestruction( | 166 void ModelSafeWorker::UnregisterForLoopDestruction( |
| 167 base::Callback<void(ModelSafeGroup)> unregister_done_callback) { | 167 base::Callback<void(ModelSafeGroup)> unregister_done_callback) { |
| 168 base::AutoLock l(working_loop_lock_); | 168 base::AutoLock l(working_task_runner_lock_); |
| 169 if (working_loop_ != NULL) { | 169 if (working_task_runner_) { |
| 170 // Normal case - observer registration has been already done. | 170 // Normal case - observer registration has been already done. |
| 171 // Delegate to the sync thread to do the actual unregistration in | 171 // Delegate to the sync thread to do the actual unregistration in |
| 172 // UnregisterForLoopDestructionAsync. | 172 // UnregisterForLoopDestructionAsync. |
| 173 DCHECK_NE(base::MessageLoop::current(), working_loop_); | 173 DCHECK(!working_task_runner_->BelongsToCurrentThread()); |
| 174 working_loop_->PostTask( | 174 working_task_runner_->PostTask( |
| 175 FROM_HERE, | 175 FROM_HERE, |
| 176 base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync, | 176 base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync, this, |
| 177 this, | |
| 178 unregister_done_callback)); | 177 unregister_done_callback)); |
| 179 } else { | 178 } else { |
| 180 // The working loop is still unknown, probably because the model type | 179 // The working loop is still unknown, probably because the model type |
| 181 // thread is blocked. Store the callback to be called from | 180 // thread is blocked. Store the callback to be called from |
| 182 // SetWorkingLoopToCurrent. | 181 // SetWorkingLoopToCurrent. |
| 183 unregister_done_callback_ = unregister_done_callback; | 182 unregister_done_callback_ = unregister_done_callback; |
| 184 } | 183 } |
| 185 } | 184 } |
| 186 | 185 |
| 187 void ModelSafeWorker::UnregisterForLoopDestructionAsync( | 186 void ModelSafeWorker::UnregisterForLoopDestructionAsync( |
| 188 base::Callback<void(ModelSafeGroup)> unregister_done_callback) { | 187 base::Callback<void(ModelSafeGroup)> unregister_done_callback) { |
| 189 { | 188 { |
| 190 base::AutoLock l(working_loop_lock_); | 189 base::AutoLock l(working_task_runner_lock_); |
| 191 if (!working_loop_) | 190 if (!working_task_runner_) |
| 192 return; | 191 return; |
| 193 DCHECK_EQ(base::MessageLoop::current(), working_loop_); | 192 DCHECK(working_task_runner_->BelongsToCurrentThread()); |
| 194 } | 193 } |
| 195 | 194 |
| 196 DCHECK(stopped_); | 195 DCHECK(stopped_); |
| 197 base::MessageLoop::current()->RemoveDestructionObserver(this); | 196 base::MessageLoop::current()->RemoveDestructionObserver(this); |
| 198 unregister_done_callback.Run(GetModelSafeGroup()); | 197 unregister_done_callback.Run(GetModelSafeGroup()); |
| 199 } | 198 } |
| 200 | 199 |
| 201 } // namespace syncer | 200 } // namespace syncer |
| OLD | NEW |