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

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

Issue 19678028: PAPI: Fix bug in RunWhileLocked, add support for params (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Unlock when joining the audio thread so that we don't deadlock if it makes pepper calls. 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/shared_impl/ppb_audio_shared.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
143 // Example usage: 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 private:
168 scoped_ptr<CallbackType> callback_;
169
170 // Used to ensure that the Callback is run and deleted on the same thread.
171 base::ThreadChecker thread_checker_;
172 };
173
174 template <typename P1>
175 class RunWhileLockedHelper<void (P1)> {
176 public:
177 typedef base::Callback<void (P1)> CallbackType;
178 explicit RunWhileLockedHelper(const CallbackType& callback)
179 : callback_(new CallbackType(callback)) {
180 ProxyLock::AssertAcquired();
181 thread_checker_.DetachFromThread();
182 }
183 void CallWhileLocked(P1 p1) {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 ProxyAutoLock lock;
186 {
187 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
188 temp_callback->Run(p1);
189 }
190 }
191
192 private:
193 scoped_ptr<CallbackType> callback_;
194 base::ThreadChecker thread_checker_;
195 };
196
197 template <typename P1, typename P2>
198 class RunWhileLockedHelper<void (P1, P2)> {
199 public:
200 typedef base::Callback<void (P1, P2)> CallbackType;
201 explicit RunWhileLockedHelper(const CallbackType& callback)
202 : callback_(new CallbackType(callback)) {
203 ProxyLock::AssertAcquired();
204 thread_checker_.DetachFromThread();
205 }
206 void CallWhileLocked(P1 p1, P2 p2) {
207 DCHECK(thread_checker_.CalledOnValidThread());
208 ProxyAutoLock lock;
209 {
210 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
211 temp_callback->Run(p1, p2);
212 }
213 }
214
215 private:
216 scoped_ptr<CallbackType> callback_;
217 base::ThreadChecker thread_checker_;
218 };
219
220 template <typename P1, typename P2, typename P3>
221 class RunWhileLockedHelper<void (P1, P2, P3)> {
222 public:
223 typedef base::Callback<void (P1, P2, P3)> CallbackType;
224 explicit RunWhileLockedHelper(const CallbackType& callback)
225 : callback_(new CallbackType(callback)) {
226 ProxyLock::AssertAcquired();
227 thread_checker_.DetachFromThread();
228 }
229 void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
230 DCHECK(thread_checker_.CalledOnValidThread());
231 ProxyAutoLock lock;
232 {
233 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
234 temp_callback->Run(p1, p2, p3);
235 }
236 }
237
238 private:
239 scoped_ptr<CallbackType> callback_;
240 base::ThreadChecker thread_checker_;
241 };
242
243 } // namespace internal
244
245 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
246 // 1) Locks the ProxyLock.
247 // 2) Runs the original Callback (forwarding arguments, if any).
248 // 3) Clears the original Callback (while the lock is held).
249 // 4) Unlocks the ProxyLock.
250 // Note that it's important that the callback is cleared in step (3), in case
251 // clearing the Callback causes a destructor (e.g., for a Resource) to run,
252 // which should hold the ProxyLock to avoid data races.
253 //
254 // This is for cases where you want to run a task or store a Callback, but you
255 // want to ensure that the ProxyLock is acquired for the duration of the task
256 // that the Callback runs.
257 // EXAMPLE USAGE:
144 // GetMainThreadMessageLoop()->PostDelayedTask( 258 // GetMainThreadMessageLoop()->PostDelayedTask(
145 // FROM_HERE, 259 // FROM_HERE,
146 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), 260 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
147 // delay_in_ms); 261 // delay_in_ms);
148 inline base::Closure RunWhileLocked(const base::Closure& closure) { 262 //
149 return base::Bind(CallWhileLocked, closure); 263 // In normal usage like the above, this all should "just work". However, if you
264 // do something unusual, you may get a runtime crash due to deadlock. Here are
265 // the ways that the returned Callback must be used to avoid a deadlock:
266 // (1) copied to another Callback. After that, the original callback can be
267 // destroyed with or without the proxy lock acquired, while the newly assigned
268 // callback has to conform to these same restrictions. Or
269 // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop
270 // and run there). The callback must be destroyed on the same thread where it
271 // was run (but can be destroyed with or without the proxy lock acquired). Or
272 // (3) destroyed without the proxy lock acquired.
273 // TODO(dmichael): This won't actually fail until
274 // https://codereview.chromium.org/19492014/ lands.
275 template <class FunctionType>
276 inline base::Callback<FunctionType>
277 RunWhileLocked(const base::Callback<FunctionType>& callback) {
278 internal::RunWhileLockedHelper<FunctionType>* helper =
279 new internal::RunWhileLockedHelper<FunctionType>(callback);
280 return base::Bind(
281 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked,
282 base::Owned(helper));
150 } 283 }
151 284
152 } // namespace ppapi 285 } // namespace ppapi
153 286
154 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 287 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_
OLDNEW
« no previous file with comments | « ppapi/shared_impl/ppb_audio_shared.cc ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698