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

Side by Side Diff: ppapi/shared_impl/proxy_lock.h

Issue 19492014: PPAPI: Purposely leak ProxyLock, fix shutdown race (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Make the destructor lock [sometimes] Created 7 years, 5 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 | Annotate | Revision Log
« no previous file with comments | « ppapi/proxy/ppb_core_proxy.cc ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 #ifndef PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 5 #ifndef PPAPI_SHARED_IMPL_PROXY_LOCK_H_
6 #define PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 6 #define PPAPI_SHARED_IMPL_PROXY_LOCK_H_
7 7
8 #include "base/basictypes.h" 8 #include "base/basictypes.h"
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback.h" 10 #include "base/callback.h"
11 #include "base/threading/thread_checker.h"
11 12
12 #include "ppapi/shared_impl/ppapi_shared_export.h" 13 #include "ppapi/shared_impl/ppapi_shared_export.h"
13 14
14 namespace base { 15 namespace base {
15 class Lock; 16 class Lock;
16 } 17 }
17 18
18 namespace ppapi { 19 namespace ppapi {
19 20
20 // This is the one lock to rule them all for the ppapi proxy. All PPB interface 21 // This is the one lock to rule them all for the ppapi proxy. All PPB interface
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 const P1& p1, 126 const P1& p1,
126 const P2& p2, 127 const P2& p2,
127 const P3& p3, 128 const P3& p3,
128 const P4& p4, 129 const P4& p4,
129 const P5& p5) { 130 const P5& p5) {
130 ProxyAutoUnlock unlock; 131 ProxyAutoUnlock unlock;
131 return function(p1, p2, p3, p4, p5); 132 return function(p1, p2, p3, p4, p5);
132 } 133 }
133 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); 134 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure);
134 135
135 // CallWhileLocked locks the ProxyLock and runs the given closure immediately. 136 namespace internal {
136 // The lock is released when CallWhileLocked returns. This function assumes the
137 // lock is not held. This is mostly for use in RunWhileLocked; see below.
138 void PPAPI_SHARED_EXPORT CallWhileLocked(const base::Closure& closure);
139 137
140 // RunWhileLocked binds the given closure with CallWhileLocked and returns the 138 template <typename RunType>
141 // new Closure. This is for cases where you want to run a task, but you want to 139 class RunWhileLockedHelper;
142 // ensure that the ProxyLock is acquired for the duration of the task. 140
141 template <>
142 class RunWhileLockedHelper<void ()> {
143 public:
144 typedef base::Callback<void ()> CallbackType;
145 explicit RunWhileLockedHelper(const CallbackType& callback)
146 : callback_(new CallbackType(callback)) {
147 // Copying |callback| may adjust reference counts for bound Vars or
148 // Resources; we should have the lock already.
149 ProxyLock::AssertAcquired();
150 // CallWhileLocked and destruction might happen on a different thread from
151 // creation.
152 thread_checker_.DetachFromThread();
153 }
154 void CallWhileLocked() {
155 // Bind thread_checker_ to this thread so we can check in the destructor.
156 DCHECK(thread_checker_.CalledOnValidThread());
157 ProxyAutoLock lock;
158 {
159 // Use a scope and local Callback to ensure that the callback is cleared
160 // before the lock is released, even in the unlikely event that Run()
161 // throws an exception.
162 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
163 temp_callback->Run();
164 }
165 }
166
167 ~RunWhileLockedHelper() {
168 // Check that the Callback is destroyed on the same thread as where
169 // CallWhileLocked happened (if CallWhileLocked happened).
170 DCHECK(thread_checker_.CalledOnValidThread());
171 // Here we read callback_ without the lock. This is why the callback must be
172 // destroyed on the same thread where it runs. There are 2 cases where
173 // callback_ will be NULL:
174 // 1) This is the original RunWhileLockedHelper that RunWhileLocked
175 // created. When it was copied somewhere else (e.g., to a MessageLoop
176 // queue), callback_ was passed to the new copy, and the original
177 // RunWhileLockedHelper's callback_ was set to NULL (since scoped_ptrs
178 // only ever have 1 owner).
teravest 2013/07/22 20:36:00 You should mention here that the proxy lock is sti
179 // 2) callback_ has already been run via CallWhileLocked.
180 if (callback_) {
181 // If the callback was not run, we still need to have the lock when we
182 // destroy the callback in case it had a Resource bound to it. This
183 // ensures that the Resource's destructor is invoked only with the lock
184 // held.
185 //
186 // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted),
187 // and these callbacks need to be usable on any thread. So we need to lock
188 // when releasing the callback to avoid ref counting races.
189 ProxyAutoLock lock;
190 callback_.reset();
191 }
192 }
193 private:
194 scoped_ptr<CallbackType> callback_;
195
196 // Used to ensure that the Callback is run and deleted on the same thread.
197 base::ThreadCheckerImpl thread_checker_;
198 };
199
200 template <typename P1>
201 class RunWhileLockedHelper<void (P1)> {
202 public:
203 typedef base::Callback<void (P1)> CallbackType;
204 explicit RunWhileLockedHelper(const CallbackType& callback)
205 : callback_(new CallbackType(callback)) {
206 ProxyLock::AssertAcquired();
207 thread_checker_.DetachFromThread();
208 }
209 void CallWhileLocked(P1 p1) {
210 DCHECK(thread_checker_.CalledOnValidThread());
211 ProxyAutoLock lock;
212 {
213 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
214 temp_callback->Run(p1);
215 }
216 }
217
218 ~RunWhileLockedHelper() {
219 DCHECK(thread_checker_.CalledOnValidThread());
220 if (callback_) {
221 ProxyAutoLock lock;
222 callback_.reset();
223 }
224 }
225 private:
226 scoped_ptr<CallbackType> callback_;
227 base::ThreadCheckerImpl thread_checker_;
228 };
229
230 template <typename P1, typename P2>
231 class RunWhileLockedHelper<void (P1, P2)> {
232 public:
233 typedef base::Callback<void (P1, P2)> CallbackType;
234 explicit RunWhileLockedHelper(const CallbackType& callback)
235 : callback_(new CallbackType(callback)) {
236 ProxyLock::AssertAcquired();
237 thread_checker_.DetachFromThread();
238 }
239 void CallWhileLocked(P1 p1, P2 p2) {
240 DCHECK(thread_checker_.CalledOnValidThread());
241 ProxyAutoLock lock;
242 {
243 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
244 temp_callback->Run(p1, p2);
245 }
246 }
247
248 ~RunWhileLockedHelper() {
249 DCHECK(thread_checker_.CalledOnValidThread());
250 if (callback_) {
251 ProxyAutoLock lock;
252 callback_.reset();
253 }
254 }
255 private:
256 scoped_ptr<CallbackType> callback_;
257 base::ThreadCheckerImpl thread_checker_;
258 };
259
260 template <typename P1, typename P2, typename P3>
261 class RunWhileLockedHelper<void (P1, P2, P3)> {
262 public:
263 typedef base::Callback<void (P1, P2, P3)> CallbackType;
264 explicit RunWhileLockedHelper(const CallbackType& callback)
265 : callback_(new CallbackType(callback)) {
266 ProxyLock::AssertAcquired();
267 thread_checker_.DetachFromThread();
268 }
269 void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
270 DCHECK(thread_checker_.CalledOnValidThread());
271 ProxyAutoLock lock;
272 {
273 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
274 temp_callback->Run(p1, p2, p3);
275 }
276 }
277
278 ~RunWhileLockedHelper() {
279 DCHECK(thread_checker_.CalledOnValidThread());
280 if (callback_) {
281 ProxyAutoLock lock;
282 callback_.reset();
283 }
284 }
285 private:
286 scoped_ptr<CallbackType> callback_;
287 base::ThreadCheckerImpl thread_checker_;
288 };
289
290 } // namespace internal
291
292 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
293 // 1) Locks the ProxyLock.
294 // 2) Runs the original Callback (forwarding arguments, if any).
295 // 3) Clears the original Callback (while the lock is held).
296 // 4) Unlocks the ProxyLock.
297 // Note that it's important that the callback is cleared in step (3), in case
298 // clearing the Callback causes a destructor (e.g., for a Resource) to run,
299 // which should hold the ProxyLock to avoid data races.
300 //
301 // This is for cases where you want to run a task or store a Callback, but you
302 // want to ensure that the ProxyLock is acquired for the duration of the task.
143 // Example usage: 303 // Example usage:
144 // GetMainThreadMessageLoop()->PostDelayedTask( 304 // GetMainThreadMessageLoop()->PostDelayedTask(
145 // FROM_HERE, 305 // FROM_HERE,
146 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), 306 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
147 // delay_in_ms); 307 // delay_in_ms);
148 inline base::Closure RunWhileLocked(const base::Closure& closure) { 308 template <class FunctionType>
149 return base::Bind(CallWhileLocked, closure); 309 inline base::Callback<FunctionType>
310 RunWhileLocked(const base::Callback<FunctionType>& callback) {
311 internal::RunWhileLockedHelper<FunctionType>* helper =
312 new internal::RunWhileLockedHelper<FunctionType>(callback);
313 return base::Bind(
314 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked,
315 base::Owned(helper));
150 } 316 }
151 317
152 } // namespace ppapi 318 } // namespace ppapi
153 319
154 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 320 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_
OLDNEW
« no previous file with comments | « ppapi/proxy/ppb_core_proxy.cc ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698