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

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

Issue 2782573002: [Sync] Refactor ModelSafeWorker::DoWorkAndWaitUntilDone() to avoid code duplication. (Closed)
Patch Set: self-review 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 ModelSafeWorker::ModelSafeWorker()
76 : work_done_or_abandoned_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
77 base::WaitableEvent::InitialState::NOT_SIGNALED) {
78 }
73 ModelSafeWorker::~ModelSafeWorker() {} 79 ModelSafeWorker::~ModelSafeWorker() {}
74 80
75 void ModelSafeWorker::RequestStop() { 81 void ModelSafeWorker::RequestStop() {
76 // Set stop flag. This prevents any *further* tasks from being posted to 82 base::AutoLock auto_lock(lock_);
77 // worker threads (see DoWorkAndWaitUntilDone below), but note that one may 83
78 // already be posted. 84 // Set stop flag to prevent any *further* WorkCallback from starting to run
79 stopped_.Set(); 85 // (note that one may alreay be running).
86 stopped_ = true;
87
88 // If no work is running, unblock DoWorkAndWaitUntilDone(). If work is
89 // running, it is unsafe to return from DoWorkAndWaitUntilDone().
90 // ScopedSignalWorkDoneOrAbandoned will take care of signaling the event when
91 // the work is done.
92 if (!is_work_running_)
93 work_done_or_abandoned_.Signal();
80 } 94 }
81 95
82 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(const WorkCallback& work) { 96 SyncerError ModelSafeWorker::DoWorkAndWaitUntilDone(WorkCallback work) {
83 if (stopped_.IsSet()) 97 {
84 return CANNOT_DO_WORK; 98 // It is important to check |stopped_| and reset |work_done_or_abandoned_|
85 return DoWorkAndWaitUntilDoneImpl(work); 99 // atomically to prevent this race:
100 //
101 // Thread Action
102 // Sync Sees that |stopped_| is false.
103 // UI Calls RequestStop(). Signals |work_done_or_abandoned_|.
104 // Sync Resets |work_done_or_abandoned_|.
105 // Waits on |work_done_or_abandoned_| forever since the task may not
106 // run after RequestStop() is called.
107 base::AutoLock auto_lock(lock_);
108 if (stopped_)
109 return CANNOT_DO_WORK;
110 DCHECK(!is_work_running_);
111 work_done_or_abandoned_.Reset();
112 }
113
114 SyncerError error = UNSET;
115 bool did_run = false;
116 ScheduleWork(base::BindOnce(
117 &ModelSafeWorker::DoWork, this, base::Passed(std::move(work)),
118 base::Passed(base::ScopedClosureRunner(base::Bind(
119 [](scoped_refptr<ModelSafeWorker> worker) {
120 worker->work_done_or_abandoned_.Signal();
121 },
122 make_scoped_refptr(this)))),
123 base::Unretained(&error), base::Unretained(&did_run)));
124
125 // Unblocked when the task runs or is deleted or when RequestStop() is called
126 // before the task starts running.
127 work_done_or_abandoned_.Wait();
128
129 return did_run ? error : CANNOT_DO_WORK;
86 } 130 }
87 131
88 bool ModelSafeWorker::IsStopped() { 132 void ModelSafeWorker::DoWork(WorkCallback work,
89 return stopped_.IsSet(); 133 base::ScopedClosureRunner scoped_closure_runner,
134 SyncerError* error,
135 bool* did_run) {
136 {
137 base::AutoLock auto_lock(lock_);
138 if (stopped_)
139 return;
140
141 // Set |is_work_running_| to make sure that DoWorkAndWaitUntilDone() doesn't
142 // return while |work| is running.
143 DCHECK(!is_work_running_);
144 is_work_running_ = true;
145 }
146
147 *error = std::move(work).Run();
148 *did_run = true;
149
150 {
151 base::AutoLock auto_lock(lock_);
152 DCHECK(is_work_running_);
153 is_work_running_ = false;
154 }
90 } 155 }
91 156
92 } // namespace syncer 157 } // namespace syncer
OLDNEW
« no previous file with comments | « components/sync/engine/model_safe_worker.h ('k') | components/sync/engine/model_safe_worker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698