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
3 // found in the LICENSE file.
5 #ifndef PPAPI_SHARED_IMPL_PROXY_LOCK_H_
6 #define PPAPI_SHARED_IMPL_PROXY_LOCK_H_
8 #include "base/basictypes.h"
10 #include "base/callback.h"
11 #include "base/threading/thread_checker.h"
13 #include "ppapi/shared_impl/ppapi_shared_export.h"
25 // This is the one lock to rule them all for the ppapi proxy. All PPB interface
26 // functions that need to be synchronized should lock this lock on entry. This
27 // is normally accomplished by using an appropriate Enter RAII object at the
28 // beginning of each thunk function.
30 // TODO(dmichael): If this turns out to be too slow and contentious, we'll want
31 // to use multiple locks. E.g., one for the var tracker, one for the resource
33 class PPAPI_SHARED_EXPORT ProxyLock
{
35 // Return the global ProxyLock. Normally, you should not access this
36 // directly but instead use ProxyAutoLock or ProxyAutoUnlock. But sometimes
37 // you need access to the ProxyLock, for example to create a condition
39 static base::Lock
* Get();
41 // Acquire the proxy lock. If it is currently held by another thread, block
42 // until it is available. If the lock has not been set using the 'Set' method,
43 // this operation does nothing. That is the normal case for the host side;
44 // see PluginResourceTracker for where the lock gets set for the out-of-
45 // process plugin case.
46 static void Acquire();
47 // Relinquish the proxy lock. If the lock has not been set, this does nothing.
48 static void Release();
50 // Assert that the lock is owned by the current thread (in the plugin
51 // process). Does nothing when running in-process (or in the host process).
52 static void AssertAcquired();
53 static void AssertAcquiredDebugOnly() {
59 // We have some unit tests where one thread pretends to be the host and one
60 // pretends to be the plugin. This allows the lock to do nothing on only one
61 // thread to support these tests. See TwoWayTest for more information.
62 class PPAPI_SHARED_EXPORT LockingDisablerForTest
{
64 LockingDisablerForTest();
65 ~LockingDisablerForTest();
69 friend class content::HostGlobals
;
70 // On the host side, we do not lock. This must be called at most once at
71 // startup, before other threads that may access the ProxyLock have had a
73 static void DisableLocking();
75 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock
);
78 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing
79 // on exit. This is for simple interfaces that don't use the 'thunk' system,
80 // such as PPB_Var and PPB_Core.
83 ProxyAutoLock() { ProxyLock::Acquire(); }
84 ~ProxyAutoLock() { ProxyLock::Release(); }
87 DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock
);
90 // The inverse of the above; unlock on construction, lock on destruction. This
91 // is useful for calling out to the plugin, when we need to unlock but ensure
92 // that we re-acquire the lock when the plugin is returns or raises an
94 class ProxyAutoUnlock
{
96 ProxyAutoUnlock() { ProxyLock::Release(); }
97 ~ProxyAutoUnlock() { ProxyLock::Acquire(); }
100 DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock
);
103 // A set of function template overloads for invoking a function pointer while
104 // the ProxyLock is unlocked. This assumes that the luck is held.
105 // CallWhileUnlocked unlocks the ProxyLock just before invoking the given
106 // function. The lock is immediately re-acquired when the invoked function
107 // function returns. CallWhileUnlocked returns whatever the given function
111 // *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent,
113 // resource->pp_resource());
114 template <class ReturnType
>
115 ReturnType
CallWhileUnlocked(ReturnType (*function
)()) {
116 ProxyAutoUnlock unlock
;
119 // Note we use 2 types for the params, even though for the most part we expect
120 // A1 to match P1. We let the compiler determine if P1 can convert safely to
121 // A1. This allows callers to avoid having to do things like
122 // const_cast to add const.
123 template <class ReturnType
, class A1
, class P1
>
124 ReturnType
CallWhileUnlocked(ReturnType (*function
)(A1
), const P1
& p1
) {
125 ProxyAutoUnlock unlock
;
128 template <class ReturnType
, class A1
, class A2
, class P1
, class P2
>
129 ReturnType
CallWhileUnlocked(ReturnType (*function
)(A1
, A2
),
132 ProxyAutoUnlock unlock
;
133 return function(p1
, p2
);
135 template <class ReturnType
, class A1
, class A2
, class A3
, class P1
, class P2
,
137 ReturnType
CallWhileUnlocked(ReturnType (*function
)(A1
, A2
, A3
),
141 ProxyAutoUnlock unlock
;
142 return function(p1
, p2
, p3
);
144 template <class ReturnType
, class A1
, class A2
, class A3
, class A4
, class P1
,
145 class P2
, class P3
, class P4
>
146 ReturnType
CallWhileUnlocked(ReturnType (*function
)(A1
, A2
, A3
, A4
),
151 ProxyAutoUnlock unlock
;
152 return function(p1
, p2
, p3
, p4
);
154 template <class ReturnType
, class A1
, class A2
, class A3
, class A4
, class A5
,
155 class P1
, class P2
, class P3
, class P4
, class P5
>
156 ReturnType
CallWhileUnlocked(ReturnType (*function
)(A1
, A2
, A3
, A4
, A5
),
162 ProxyAutoUnlock unlock
;
163 return function(p1
, p2
, p3
, p4
, p5
);
165 void PPAPI_SHARED_EXPORT
CallWhileUnlocked(const base::Closure
& closure
);
169 template <typename RunType
>
170 class RunWhileLockedHelper
;
173 class RunWhileLockedHelper
<void()> {
175 typedef base::Callback
<void()> CallbackType
;
176 explicit RunWhileLockedHelper(const CallbackType
& callback
)
177 : callback_(new CallbackType(callback
)) {
178 // Copying |callback| may adjust reference counts for bound Vars or
179 // Resources; we should have the lock already.
180 ProxyLock::AssertAcquired();
181 // CallWhileLocked and destruction might happen on a different thread from
183 thread_checker_
.DetachFromThread();
185 void CallWhileLocked() {
186 // Bind thread_checker_ to this thread so we can check in the destructor.
187 DCHECK(thread_checker_
.CalledOnValidThread());
190 // Use a scope and local Callback to ensure that the callback is cleared
191 // before the lock is released, even in the unlikely event that Run()
192 // throws an exception.
193 scoped_ptr
<CallbackType
> temp_callback(callback_
.Pass());
194 temp_callback
->Run();
198 ~RunWhileLockedHelper() {
199 // Check that the Callback is destroyed on the same thread as where
200 // CallWhileLocked happened (if CallWhileLocked happened).
201 DCHECK(thread_checker_
.CalledOnValidThread());
202 // Here we read callback_ without the lock. This is why the callback must be
203 // destroyed on the same thread where it runs. There are 2 cases where
204 // callback_ will be NULL:
205 // 1) This is the original RunWhileLockedHelper that RunWhileLocked
206 // created. When it was copied somewhere else (e.g., to a MessageLoop
207 // queue), callback_ was passed to the new copy, and the original
208 // RunWhileLockedHelper's callback_ was set to NULL (since scoped_ptrs
209 // only ever have 1 owner). In this case, we don't want to acquire the
210 // lock, because we already have it.
211 // 2) callback_ has already been run via CallWhileLocked. In this case,
212 // there's no need to acquire the lock, because we don't touch any
215 // If the callback was not run, we still need to have the lock when we
216 // destroy the callback in case it had a Resource bound to it. This
217 // ensures that the Resource's destructor is invoked only with the lock
220 // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted),
221 // and these callbacks need to be usable on any thread. So we need to lock
222 // when releasing the callback to avoid ref counting races.
229 scoped_ptr
<CallbackType
> callback_
;
231 // Used to ensure that the Callback is run and deleted on the same thread.
232 base::ThreadChecker thread_checker_
;
235 template <typename P1
>
236 class RunWhileLockedHelper
<void(P1
)> {
238 typedef base::Callback
<void(P1
)> CallbackType
;
239 explicit RunWhileLockedHelper(const CallbackType
& callback
)
240 : callback_(new CallbackType(callback
)) {
241 ProxyLock::AssertAcquired();
242 thread_checker_
.DetachFromThread();
244 void CallWhileLocked(P1 p1
) {
245 DCHECK(thread_checker_
.CalledOnValidThread());
248 scoped_ptr
<CallbackType
> temp_callback(callback_
.Pass());
249 temp_callback
->Run(p1
);
252 ~RunWhileLockedHelper() {
253 DCHECK(thread_checker_
.CalledOnValidThread());
261 scoped_ptr
<CallbackType
> callback_
;
262 base::ThreadChecker thread_checker_
;
265 template <typename P1
, typename P2
>
266 class RunWhileLockedHelper
<void(P1
, P2
)> {
268 typedef base::Callback
<void(P1
, P2
)> CallbackType
;
269 explicit RunWhileLockedHelper(const CallbackType
& callback
)
270 : callback_(new CallbackType(callback
)) {
271 ProxyLock::AssertAcquired();
272 thread_checker_
.DetachFromThread();
274 void CallWhileLocked(P1 p1
, P2 p2
) {
275 DCHECK(thread_checker_
.CalledOnValidThread());
278 scoped_ptr
<CallbackType
> temp_callback(callback_
.Pass());
279 temp_callback
->Run(p1
, p2
);
282 ~RunWhileLockedHelper() {
283 DCHECK(thread_checker_
.CalledOnValidThread());
291 scoped_ptr
<CallbackType
> callback_
;
292 base::ThreadChecker thread_checker_
;
295 template <typename P1
, typename P2
, typename P3
>
296 class RunWhileLockedHelper
<void(P1
, P2
, P3
)> {
298 typedef base::Callback
<void(P1
, P2
, P3
)> CallbackType
;
299 explicit RunWhileLockedHelper(const CallbackType
& callback
)
300 : callback_(new CallbackType(callback
)) {
301 ProxyLock::AssertAcquired();
302 thread_checker_
.DetachFromThread();
304 void CallWhileLocked(P1 p1
, P2 p2
, P3 p3
) {
305 DCHECK(thread_checker_
.CalledOnValidThread());
308 scoped_ptr
<CallbackType
> temp_callback(callback_
.Pass());
309 temp_callback
->Run(p1
, p2
, p3
);
312 ~RunWhileLockedHelper() {
313 DCHECK(thread_checker_
.CalledOnValidThread());
321 scoped_ptr
<CallbackType
> callback_
;
322 base::ThreadChecker thread_checker_
;
325 } // namespace internal
327 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
328 // 1) Locks the ProxyLock.
329 // 2) Runs the original Callback (forwarding arguments, if any).
330 // 3) Clears the original Callback (while the lock is held).
331 // 4) Unlocks the ProxyLock.
332 // Note that it's important that the callback is cleared in step (3), in case
333 // clearing the Callback causes a destructor (e.g., for a Resource) to run,
334 // which should hold the ProxyLock to avoid data races.
336 // This is for cases where you want to run a task or store a Callback, but you
337 // want to ensure that the ProxyLock is acquired for the duration of the task
338 // that the Callback runs.
340 // GetMainThreadMessageLoop()->PostDelayedTask(
342 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
345 // In normal usage like the above, this all should "just work". However, if you
346 // do something unusual, you may get a runtime crash due to deadlock. Here are
347 // the ways that the returned Callback must be used to avoid a deadlock:
348 // (1) copied to another Callback. After that, the original callback can be
349 // destroyed with or without the proxy lock acquired, while the newly assigned
350 // callback has to conform to these same restrictions. Or
351 // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop
352 // and run there). The callback must be destroyed on the same thread where it
353 // was run (but can be destroyed with or without the proxy lock acquired). Or
354 // (3) destroyed without the proxy lock acquired.
355 template <class FunctionType
>
356 inline base::Callback
<FunctionType
> RunWhileLocked(
357 const base::Callback
<FunctionType
>& callback
) {
358 internal::RunWhileLockedHelper
<FunctionType
>* helper
=
359 new internal::RunWhileLockedHelper
<FunctionType
>(callback
);
361 &internal::RunWhileLockedHelper
<FunctionType
>::CallWhileLocked
,
362 base::Owned(helper
));
367 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_