Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1069)

Side by Side Diff: components/sync/engine/model_safe_worker.cc

Issue 2782573002: [Sync] Refactor ModelSafeWorker::DoWorkAndWaitUntilDone() to avoid code duplication. (Closed)
Patch Set: fix-test-error Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "components/sync/engine/model_safe_worker.h" 5 #include "components/sync/engine/model_safe_worker.h"
6 6
7 #include <utility>
8
9 #include "base/bind.h"
7 #include "base/json/json_writer.h" 10 #include "base/json/json_writer.h"
8 #include "base/values.h" 11 #include "base/values.h"
9 12
10 namespace syncer { 13 namespace syncer {
11 14
12 std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue( 15 std::unique_ptr<base::DictionaryValue> ModelSafeRoutingInfoToValue(
13 const ModelSafeRoutingInfo& routing_info) { 16 const ModelSafeRoutingInfo& routing_info) {
14 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); 17 std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
15 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin(); 18 for (ModelSafeRoutingInfo::const_iterator it = routing_info.begin();
16 it != routing_info.end(); ++it) { 19 it != routing_info.end(); ++it) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 case GROUP_PASSWORD: 65 case GROUP_PASSWORD:
63 return "GROUP_PASSWORD"; 66 return "GROUP_PASSWORD";
64 case GROUP_NON_BLOCKING: 67 case GROUP_NON_BLOCKING:
65 return "GROUP_NON_BLOCKING"; 68 return "GROUP_NON_BLOCKING";
66 default: 69 default:
67 NOTREACHED(); 70 NOTREACHED();
68 return "INVALID"; 71 return "INVALID";
69 } 72 }
70 } 73 }
71 74
72 ModelSafeWorker::ModelSafeWorker() {} 75 // An object which signals the |work_done_or_abandoned_| event of a
76 // ModelSafeWorker when it is deleted.
77 class ModelSafeWorker::ScopedSignalWorkDoneOrAbandoned {
skym 2017/04/06 00:34:54 This feels like a generic problem that is being so
fdoray 2017/04/06 18:10:55 Done.
78 public:
79 explicit ScopedSignalWorkDoneOrAbandoned(scoped_refptr<ModelSafeWorker> outer)
80 : outer_(std::move(outer)) {}
81
82 ScopedSignalWorkDoneOrAbandoned(ScopedSignalWorkDoneOrAbandoned&& other) =
83 default;
84 ScopedSignalWorkDoneOrAbandoned& operator=(
85 ScopedSignalWorkDoneOrAbandoned&& other) = default;
86
87 ~ScopedSignalWorkDoneOrAbandoned() {
88 if (outer_)
skym 2017/04/06 00:34:54 Why's this if check needed?
fdoray 2017/04/06 18:10:55 n/a
89 outer_->work_done_or_abandoned_.Signal();
90 }
91
92 private:
93 scoped_refptr<ModelSafeWorker> outer_;
94
95 DISALLOW_COPY_AND_ASSIGN(ScopedSignalWorkDoneOrAbandoned);
96 };
97
98 ModelSafeWorker::ModelSafeWorker()
99 : work_done_or_abandoned_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
100 base::WaitableEvent::InitialState::NOT_SIGNALED) {
101 }
73 ModelSafeWorker::~ModelSafeWorker() {} 102 ModelSafeWorker::~ModelSafeWorker() {}
74 103
75 void ModelSafeWorker::RequestStop() { 104 void ModelSafeWorker::RequestStop() {
76 // Set stop flag. This prevents any *further* tasks from being posted to 105 base::AutoLock auto_lock(lock_);
77 // worker threads (see DoWorkAndWaitUntilDone below), but note that one may 106
78 // already be posted. 107 // Set stop flag to prevent any *further* WorkCallback from starting to run
79 stopped_.Set(); 108 // (note that one may alreay be running).
109 stopped_ = true;
110
111 // If no work is running, unblock DoWorkAndWaitUntilDone(). If work is
112 // running, it is unsafe to return from DoWorkAndWaitUntilDone().
113 // ScopedSignalWorkDoneOrAbandoned will take care of signaling the event when
114 // the work is done.
115 if (!is_work_running_)
116 work_done_or_abandoned_.Signal();
80 } 117 }
81 118
82 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) { 119 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) {
83 if (stopped_.IsSet()) 120 {
84 return CANNOT_DO_WORK; 121 // It is important to check |stopped_| and reset |work_done_or_abandoned_|
85 return DoWorkAndWaitUntilDoneImpl(work); 122 // atomically to prevent this race:
123 //
124 // Thread Action
125 // Sync Sees that |stopped_| is false.
126 // UI Calls RequestStop(). Signals |work_done_or_abandoned_|.
127 // Sync Resets |work_done_or_abandoned_|.
128 // Waits on |work_done_or_abandoned_| forever since the task may not
129 // run after RequestStop() is called.
130 base::AutoLock auto_lock(lock_);
131 if (stopped_)
132 return CANNOT_DO_WORK;
133 DCHECK(!is_work_running_);
134 work_done_or_abandoned_.Reset();
135 }
136
137 SyncerError error = UNSET;
138 bool did_run = false;
139 ScheduleWork(base::Bind(&ModelSafeWorker::DoWork, this, work,
140 base::Passed(ScopedSignalWorkDoneOrAbandoned(this)),
141 base::Unretained(&error),
142 base::Unretained(&did_run)));
143
144 // Unblocked when the task runs or is deleted or when RequestStop() is called
145 // before the task starts running.
146 work_done_or_abandoned_.Wait();
147
148 return did_run ? error : CANNOT_DO_WORK;
86 } 149 }
87 150
88 bool ModelSafeWorker::IsStopped() { 151 void ModelSafeWorker::DoWork(
89 return stopped_.IsSet(); 152 const WorkCallback& work,
153 ScopedSignalWorkDoneOrAbandoned scoped_signal_work_done_or_abandoned,
154 SyncerError* error,
155 bool* did_run) {
156 {
157 base::AutoLock auto_lock(lock_);
158 if (stopped_)
159 return;
160
161 // Set |is_work_running_| to make sure that DoWorkAndWaitUntilDone() doesn't
162 // return while the work is running.
163 DCHECK(!is_work_running_);
164 is_work_running_ = true;
165 }
166
167 *error = work.Run();
168 *did_run = true;
169
170 {
171 base::AutoLock auto_lock(lock_);
172 DCHECK(is_work_running_);
173 is_work_running_ = false;
174 }
90 } 175 }
91 176
92 } // namespace syncer 177 } // namespace syncer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698