Make castv2 performance test work.
[chromium-blink-merge.git] / ppapi / shared_impl / proxy_lock.h
blob32728bd8e9ab19f52041e2f6d94a9db621b957ff
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"
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/threading/thread_checker.h"
13 #include "ppapi/shared_impl/ppapi_shared_export.h"
15 namespace base {
16 class Lock;
19 namespace content {
20 class HostGlobals;
23 namespace ppapi {
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
32 // tracker, etc.
33 class PPAPI_SHARED_EXPORT ProxyLock {
34 public:
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
38 // variable.
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() {
54 #ifndef NDEBUG
55 AssertAcquired();
56 #endif
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 {
63 public:
64 LockingDisablerForTest();
65 ~LockingDisablerForTest();
68 private:
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
72 // chance to run.
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.
81 class ProxyAutoLock {
82 public:
83 ProxyAutoLock() { ProxyLock::Acquire(); }
84 ~ProxyAutoLock() { ProxyLock::Release(); }
86 private:
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
93 // exception.
94 class ProxyAutoUnlock {
95 public:
96 ProxyAutoUnlock() { ProxyLock::Release(); }
97 ~ProxyAutoUnlock() { ProxyLock::Acquire(); }
99 private:
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
108 // returned.
110 // Example usage:
111 // *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent,
112 // instance,
113 // resource->pp_resource());
114 template <class ReturnType>
115 ReturnType CallWhileUnlocked(ReturnType (*function)()) {
116 ProxyAutoUnlock unlock;
117 return function();
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;
126 return function(p1);
128 template <class ReturnType, class A1, class A2, class P1, class P2>
129 ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2),
130 const P1& p1,
131 const P2& p2) {
132 ProxyAutoUnlock unlock;
133 return function(p1, p2);
135 template <class ReturnType, class A1, class A2, class A3, class P1, class P2,
136 class P3>
137 ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3),
138 const P1& p1,
139 const P2& p2,
140 const P3& p3) {
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),
147 const P1& p1,
148 const P2& p2,
149 const P3& p3,
150 const P4& p4) {
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),
157 const P1& p1,
158 const P2& p2,
159 const P3& p3,
160 const P4& p4,
161 const P5& p5) {
162 ProxyAutoUnlock unlock;
163 return function(p1, p2, p3, p4, p5);
165 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure);
167 namespace internal {
169 template <typename RunType>
170 class RunWhileLockedHelper;
172 template <>
173 class RunWhileLockedHelper<void()> {
174 public:
175 typedef base::Callback<void()> CallbackType;
176 explicit RunWhileLockedHelper(const CallbackType& callback)
177 : callback_(new CallbackType(callback)) {
178 // CallWhileLocked and destruction might happen on a different thread from
179 // creation.
180 thread_checker_.DetachFromThread();
182 void CallWhileLocked() {
183 // Bind thread_checker_ to this thread so we can check in the destructor.
184 DCHECK(thread_checker_.CalledOnValidThread());
185 ProxyAutoLock lock;
187 // Use a scope and local Callback to ensure that the callback is cleared
188 // before the lock is released, even in the unlikely event that Run()
189 // throws an exception.
190 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
191 temp_callback->Run();
195 ~RunWhileLockedHelper() {
196 // Check that the Callback is destroyed on the same thread as where
197 // CallWhileLocked happened (if CallWhileLocked happened).
198 DCHECK(thread_checker_.CalledOnValidThread());
199 // Here we read callback_ without the lock. This is why the callback must be
200 // destroyed on the same thread where it runs. There are 2 cases where
201 // callback_ will be NULL:
202 // 1) This is the original RunWhileLockedHelper that RunWhileLocked
203 // created. When it was copied somewhere else (e.g., to a MessageLoop
204 // queue), callback_ was passed to the new copy, and the original
205 // RunWhileLockedHelper's callback_ was set to NULL (since scoped_ptrs
206 // only ever have 1 owner). In this case, we don't want to acquire the
207 // lock, because we already have it.
208 // 2) callback_ has already been run via CallWhileLocked. In this case,
209 // there's no need to acquire the lock, because we don't touch any
210 // shared data.
211 if (callback_) {
212 // If the callback was not run, we still need to have the lock when we
213 // destroy the callback in case it had a Resource bound to it. This
214 // ensures that the Resource's destructor is invoked only with the lock
215 // held.
217 // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted),
218 // and these callbacks need to be usable on any thread. So we need to lock
219 // when releasing the callback to avoid ref counting races.
220 ProxyAutoLock lock;
221 callback_.reset();
225 private:
226 scoped_ptr<CallbackType> callback_;
228 // Used to ensure that the Callback is run and deleted on the same thread.
229 base::ThreadChecker thread_checker_;
232 template <typename P1>
233 class RunWhileLockedHelper<void(P1)> {
234 public:
235 typedef base::Callback<void(P1)> CallbackType;
236 explicit RunWhileLockedHelper(const CallbackType& callback)
237 : callback_(new CallbackType(callback)) {
238 thread_checker_.DetachFromThread();
240 void CallWhileLocked(P1 p1) {
241 DCHECK(thread_checker_.CalledOnValidThread());
242 ProxyAutoLock lock;
244 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
245 temp_callback->Run(p1);
248 ~RunWhileLockedHelper() {
249 DCHECK(thread_checker_.CalledOnValidThread());
250 if (callback_) {
251 ProxyAutoLock lock;
252 callback_.reset();
256 private:
257 scoped_ptr<CallbackType> callback_;
258 base::ThreadChecker thread_checker_;
261 template <typename P1, typename P2>
262 class RunWhileLockedHelper<void(P1, P2)> {
263 public:
264 typedef base::Callback<void(P1, P2)> CallbackType;
265 explicit RunWhileLockedHelper(const CallbackType& callback)
266 : callback_(new CallbackType(callback)) {
267 thread_checker_.DetachFromThread();
269 void CallWhileLocked(P1 p1, P2 p2) {
270 DCHECK(thread_checker_.CalledOnValidThread());
271 ProxyAutoLock lock;
273 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
274 temp_callback->Run(p1, p2);
277 ~RunWhileLockedHelper() {
278 DCHECK(thread_checker_.CalledOnValidThread());
279 if (callback_) {
280 ProxyAutoLock lock;
281 callback_.reset();
285 private:
286 scoped_ptr<CallbackType> callback_;
287 base::ThreadChecker thread_checker_;
290 template <typename P1, typename P2, typename P3>
291 class RunWhileLockedHelper<void(P1, P2, P3)> {
292 public:
293 typedef base::Callback<void(P1, P2, P3)> CallbackType;
294 explicit RunWhileLockedHelper(const CallbackType& callback)
295 : callback_(new CallbackType(callback)) {
296 thread_checker_.DetachFromThread();
298 void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
299 DCHECK(thread_checker_.CalledOnValidThread());
300 ProxyAutoLock lock;
302 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
303 temp_callback->Run(p1, p2, p3);
306 ~RunWhileLockedHelper() {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 if (callback_) {
309 ProxyAutoLock lock;
310 callback_.reset();
314 private:
315 scoped_ptr<CallbackType> callback_;
316 base::ThreadChecker thread_checker_;
319 } // namespace internal
321 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked:
322 // 1) Locks the ProxyLock.
323 // 2) Runs the original Callback (forwarding arguments, if any).
324 // 3) Clears the original Callback (while the lock is held).
325 // 4) Unlocks the ProxyLock.
326 // Note that it's important that the callback is cleared in step (3), in case
327 // clearing the Callback causes a destructor (e.g., for a Resource) to run,
328 // which should hold the ProxyLock to avoid data races.
330 // This is for cases where you want to run a task or store a Callback, but you
331 // want to ensure that the ProxyLock is acquired for the duration of the task
332 // that the Callback runs.
333 // EXAMPLE USAGE:
334 // GetMainThreadMessageLoop()->PostDelayedTask(
335 // FROM_HERE,
336 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
337 // delay_in_ms);
339 // In normal usage like the above, this all should "just work". However, if you
340 // do something unusual, you may get a runtime crash due to deadlock. Here are
341 // the ways that the returned Callback must be used to avoid a deadlock:
342 // (1) copied to another Callback. After that, the original callback can be
343 // destroyed with or without the proxy lock acquired, while the newly assigned
344 // callback has to conform to these same restrictions. Or
345 // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop
346 // and run there). The callback must be destroyed on the same thread where it
347 // was run (but can be destroyed with or without the proxy lock acquired). Or
348 // (3) destroyed without the proxy lock acquired.
349 template <class FunctionType>
350 inline base::Callback<FunctionType> RunWhileLocked(
351 const base::Callback<FunctionType>& callback) {
352 internal::RunWhileLockedHelper<FunctionType>* helper =
353 new internal::RunWhileLockedHelper<FunctionType>(callback);
354 return base::Bind(
355 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked,
356 base::Owned(helper));
359 } // namespace ppapi
361 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_