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

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: add the unit test 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/ppapi_tests.gypi ('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
21 // functions that need to be synchronized should lock this lock on entry. This 22 // functions that need to be synchronized should lock this lock on entry. This
22 // is normally accomplished by using an appropriate Enter RAII object at the 23 // is normally accomplished by using an appropriate Enter RAII object at the
23 // beginning of each thunk function. 24 // beginning of each thunk function.
24 // 25 //
25 // TODO(dmichael): If this turns out to be too slow and contentious, we'll want 26 // TODO(dmichael): If this turns out to be too slow and contentious, we'll want
26 // to use multiple locks. E.g., one for the var tracker, one for the resource 27 // to use multiple locks. E.g., one for the var tracker, one for the resource
27 // tracker, etc. 28 // tracker, etc.
28 class PPAPI_SHARED_EXPORT ProxyLock { 29 class PPAPI_SHARED_EXPORT ProxyLock {
29 public: 30 public:
31 // Return the globally unique ProxyLock. Normally, you should not access this
32 // directly but instead use ProxyAutoLock or ProxyAutoUnlock. But sometimes
33 // you need access to the ProxyLock for e.g. a condition variable.
teravest 2013/07/24 16:38:44 /for e.g./for example/
dmichael (off chromium) 2013/07/24 22:30:11 Done.
34 static base::Lock* Get();
35
30 // Acquire the proxy lock. If it is currently held by another thread, block 36 // Acquire the proxy lock. If it is currently held by another thread, block
31 // until it is available. If the lock has not been set using the 'Set' method, 37 // until it is available. If the lock has not been set using the 'Set' method,
32 // this operation does nothing. That is the normal case for the host side; 38 // this operation does nothing. That is the normal case for the host side;
33 // see PluginResourceTracker for where the lock gets set for the out-of- 39 // see PluginResourceTracker for where the lock gets set for the out-of-
34 // process plugin case. 40 // process plugin case.
35 static void Acquire(); 41 static void Acquire();
36 // Relinquish the proxy lock. If the lock has not been set, this does nothing. 42 // Relinquish the proxy lock. If the lock has not been set, this does nothing.
37 static void Release(); 43 static void Release();
38 44
39 // Assert that the lock is owned by the current thread (in the plugin 45 // Assert that the lock is owned by the current thread (in the plugin
40 // process). Does nothing when running in-process (or in the host process). 46 // process). Does nothing when running in-process (or in the host process).
41 static void AssertAcquired(); 47 static void AssertAcquired();
42 48
43 private:
yzshen1 2013/07/24 18:45:19 Out of curiosity: Why removing "private:"?
dmichael (off chromium) 2013/07/24 22:30:11 Oops, that was an accident when I was deleting stu
44 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock); 49 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock);
45 }; 50 };
46 51
47 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing 52 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing
48 // on exit. This is for simple interfaces that don't use the 'thunk' system, 53 // on exit. This is for simple interfaces that don't use the 'thunk' system,
49 // such as PPB_Var and PPB_Core. 54 // such as PPB_Var and PPB_Core.
50 class ProxyAutoLock { 55 class ProxyAutoLock {
51 public: 56 public:
52 ProxyAutoLock() { 57 ProxyAutoLock() {
53 ProxyLock::Acquire(); 58 ProxyLock::Acquire();
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 const P1& p1, 130 const P1& p1,
126 const P2& p2, 131 const P2& p2,
127 const P3& p3, 132 const P3& p3,
128 const P4& p4, 133 const P4& p4,
129 const P5& p5) { 134 const P5& p5) {
130 ProxyAutoUnlock unlock; 135 ProxyAutoUnlock unlock;
131 return function(p1, p2, p3, p4, p5); 136 return function(p1, p2, p3, p4, p5);
132 } 137 }
133 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); 138 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure);
134 139
135 // CallWhileLocked locks the ProxyLock and runs the given closure immediately. 140 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 141
140 // RunWhileLocked binds the given closure with CallWhileLocked and returns the 142 template <typename RunType>
141 // new Closure. This is for cases where you want to run a task, but you want to 143 class RunWhileLockedHelper;
142 // ensure that the ProxyLock is acquired for the duration of the task. 144
143 // Example usage: 145 template <>
146 class RunWhileLockedHelper<void ()> {
147 public:
148 typedef base::Callback<void ()> CallbackType;
149 explicit RunWhileLockedHelper(const CallbackType& callback)
150 : callback_(new CallbackType(callback)) {
151 // Copying |callback| may adjust reference counts for bound Vars or
152 // Resources; we should have the lock already.
153 ProxyLock::AssertAcquired();
154 // CallWhileLocked and destruction might happen on a different thread from
155 // creation.
156 thread_checker_.DetachFromThread();
157 }
158 void CallWhileLocked() {
159 // Bind thread_checker_ to this thread so we can check in the destructor.
160 DCHECK(thread_checker_.CalledOnValidThread());
161 ProxyAutoLock lock;
162 {
163 // Use a scope and local Callback to ensure that the callback is cleared
164 // before the lock is released, even in the unlikely event that Run()
165 // throws an exception.
166 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
167 temp_callback->Run();
168 }
169 }
170
171 private:
172 scoped_ptr<CallbackType> callback_;
173
174 // Used to ensure that the Callback is run and deleted on the same thread.
175 base::ThreadChecker thread_checker_;
176 };
177
178 template <typename P1>
179 class RunWhileLockedHelper<void (P1)> {
180 public:
181 typedef base::Callback<void (P1)> CallbackType;
182 explicit RunWhileLockedHelper(const CallbackType& callback)
183 : callback_(new CallbackType(callback)) {
184 ProxyLock::AssertAcquired();
185 thread_checker_.DetachFromThread();
186 }
187 void CallWhileLocked(P1 p1) {
188 DCHECK(thread_checker_.CalledOnValidThread());
189 ProxyAutoLock lock;
190 {
191 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
192 temp_callback->Run(p1);
193 }
194 }
195
196 private:
197 scoped_ptr<CallbackType> callback_;
198 base::ThreadChecker thread_checker_;
199 };
200
201 template <typename P1, typename P2>
202 class RunWhileLockedHelper<void (P1, P2)> {
203 public:
204 typedef base::Callback<void (P1, P2)> CallbackType;
205 explicit RunWhileLockedHelper(const CallbackType& callback)
206 : callback_(new CallbackType(callback)) {
207 ProxyLock::AssertAcquired();
208 thread_checker_.DetachFromThread();
209 }
210 void CallWhileLocked(P1 p1, P2 p2) {
211 DCHECK(thread_checker_.CalledOnValidThread());
212 ProxyAutoLock lock;
213 {
214 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
215 temp_callback->Run(p1, p2);
216 }
217 }
218
219 private:
220 scoped_ptr<CallbackType> callback_;
221 base::ThreadChecker thread_checker_;
222 };
223
224 template <typename P1, typename P2, typename P3>
225 class RunWhileLockedHelper<void (P1, P2, P3)> {
226 public:
227 typedef base::Callback<void (P1, P2, P3)> CallbackType;
228 explicit RunWhileLockedHelper(const CallbackType& callback)
229 : callback_(new CallbackType(callback)) {
230 ProxyLock::AssertAcquired();
231 thread_checker_.DetachFromThread();
232 }
233 void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
234 DCHECK(thread_checker_.CalledOnValidThread());
235 ProxyAutoLock lock;
236 {
237 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
238 temp_callback->Run(p1, p2, p3);
239 }
240 }
241
242 private:
243 scoped_ptr<CallbackType> callback_;
244 base::ThreadChecker thread_checker_;
245 };
246
247 } // namespace internal
248
249 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
250 // 1) Locks the ProxyLock.
251 // 2) Runs the original Callback (forwarding arguments, if any).
252 // 3) Clears the original Callback (while the lock is held).
253 // 4) Unlocks the ProxyLock.
254 // Note that it's important that the callback is cleared in step (3), in case
255 // clearing the Callback causes a destructor (e.g., for a Resource) to run,
256 // which should hold the ProxyLock to avoid data races.
257 //
258 // This is for cases where you want to run a task or store a Callback, but you
259 // want to ensure that the ProxyLock is acquired for the duration of the task.
260 // EXAMPLE USAGE:
144 // GetMainThreadMessageLoop()->PostDelayedTask( 261 // GetMainThreadMessageLoop()->PostDelayedTask(
145 // FROM_HERE, 262 // FROM_HERE,
146 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), 263 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
147 // delay_in_ms); 264 // delay_in_ms);
148 inline base::Closure RunWhileLocked(const base::Closure& closure) { 265 //
149 return base::Bind(CallWhileLocked, closure); 266 // Note that the returned Callback must be:
yzshen1 2013/07/24 18:45:19 I think the comment is still pretty hard to unders
267 // - Posted to a MessageLoop.
268 // - Copied to another Callback (e.g. a member variable).
269 // or
270 // - Run().
271 // E.g., code like the following:
272 // {
273 // base::Callback<...> callback_a = RunWhileLocked(callback_b);
274 // // Do nothing about callback_a and let it go out of scope.
275 // }
276 // Will fail when the callback is destroyed, because the constructor expects the
teravest 2013/07/24 16:38:44 What do you mean by fail here? It'd be good if you
277 // proxy lock to already be acquired, while the destructor expects to need to
278 // acquire the lock (if the callback has not been run, like in the above case).
279 template <class FunctionType>
280 inline base::Callback<FunctionType>
281 RunWhileLocked(const base::Callback<FunctionType>& callback) {
282 internal::RunWhileLockedHelper<FunctionType>* helper =
283 new internal::RunWhileLockedHelper<FunctionType>(callback);
284 return base::Bind(
285 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked,
286 base::Owned(helper));
150 } 287 }
151 288
152 } // namespace ppapi 289 } // namespace ppapi
153 290
154 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 291 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_
OLDNEW
« no previous file with comments | « ppapi/ppapi_tests.gypi ('k') | ppapi/shared_impl/proxy_lock.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698