Remove redundant deinitialization code from HttpCache::Transaction.
[chromium-blink-merge.git] / ppapi / shared_impl / proxy_lock.h
blob935247189813b18552749c852770140fb080d512
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 ppapi {
21 // This is the one lock to rule them all for the ppapi proxy. All PPB interface
22 // functions that need to be synchronized should lock this lock on entry. This
23 // is normally accomplished by using an appropriate Enter RAII object at the
24 // beginning of each thunk function.
26 // TODO(dmichael): If this turns out to be too slow and contentious, we'll want
27 // to use multiple locks. E.g., one for the var tracker, one for the resource
28 // tracker, etc.
29 class PPAPI_SHARED_EXPORT ProxyLock {
30 public:
31 // Acquire the proxy lock. If it is currently held by another thread, block
32 // until it is available. If the lock has not been set using the 'Set' method,
33 // this operation does nothing. That is the normal case for the host side;
34 // see PluginResourceTracker for where the lock gets set for the out-of-
35 // process plugin case.
36 static void Acquire();
37 // Relinquish the proxy lock. If the lock has not been set, this does nothing.
38 static void Release();
40 // Assert that the lock is owned by the current thread (in the plugin
41 // process). Does nothing when running in-process (or in the host process).
42 static void AssertAcquired();
44 private:
45 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock);
48 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing
49 // on exit. This is for simple interfaces that don't use the 'thunk' system,
50 // such as PPB_Var and PPB_Core.
51 class ProxyAutoLock {
52 public:
53 ProxyAutoLock() {
54 ProxyLock::Acquire();
56 ~ProxyAutoLock() {
57 ProxyLock::Release();
59 private:
60 DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock);
63 // The inverse of the above; unlock on construction, lock on destruction. This
64 // is useful for calling out to the plugin, when we need to unlock but ensure
65 // that we re-acquire the lock when the plugin is returns or raises an
66 // exception.
67 class ProxyAutoUnlock {
68 public:
69 ProxyAutoUnlock() {
70 ProxyLock::Release();
72 ~ProxyAutoUnlock() {
73 ProxyLock::Acquire();
75 private:
76 DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock);
79 // A set of function template overloads for invoking a function pointer while
80 // the ProxyLock is unlocked. This assumes that the luck is held.
81 // CallWhileUnlocked unlocks the ProxyLock just before invoking the given
82 // function. The lock is immediately re-acquired when the invoked function
83 // function returns. CallWhileUnlocked returns whatever the given function
84 // returned.
86 // Example usage:
87 // *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent,
88 // instance,
89 // resource->pp_resource());
90 template <class ReturnType>
91 ReturnType CallWhileUnlocked(ReturnType (*function)()) {
92 ProxyAutoUnlock unlock;
93 return function();
95 template <class ReturnType, class P1>
96 ReturnType CallWhileUnlocked(ReturnType (*function)(P1), const P1& p1) {
97 ProxyAutoUnlock unlock;
98 return function(p1);
100 template <class ReturnType, class P1, class P2>
101 ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2),
102 const P1& p1,
103 const P2& p2) {
104 ProxyAutoUnlock unlock;
105 return function(p1, p2);
107 template <class ReturnType, class P1, class P2, class P3>
108 ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3),
109 const P1& p1,
110 const P2& p2,
111 const P3& p3) {
112 ProxyAutoUnlock unlock;
113 return function(p1, p2, p3);
115 template <class ReturnType, class P1, class P2, class P3, class P4>
116 ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4),
117 const P1& p1,
118 const P2& p2,
119 const P3& p3,
120 const P4& p4) {
121 ProxyAutoUnlock unlock;
122 return function(p1, p2, p3, p4);
124 template <class ReturnType, class P1, class P2, class P3, class P4, class P5>
125 ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4, P5),
126 const P1& p1,
127 const P2& p2,
128 const P3& p3,
129 const P4& p4,
130 const P5& p5) {
131 ProxyAutoUnlock unlock;
132 return function(p1, p2, p3, p4, p5);
134 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure);
136 namespace internal {
138 template <typename RunType>
139 class RunWhileLockedHelper;
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();
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;
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();
167 private:
168 scoped_ptr<CallbackType> callback_;
170 // Used to ensure that the Callback is run and deleted on the same thread.
171 base::ThreadChecker thread_checker_;
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();
183 void CallWhileLocked(P1 p1) {
184 DCHECK(thread_checker_.CalledOnValidThread());
185 ProxyAutoLock lock;
187 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
188 temp_callback->Run(p1);
192 private:
193 scoped_ptr<CallbackType> callback_;
194 base::ThreadChecker thread_checker_;
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();
206 void CallWhileLocked(P1 p1, P2 p2) {
207 DCHECK(thread_checker_.CalledOnValidThread());
208 ProxyAutoLock lock;
210 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
211 temp_callback->Run(p1, p2);
215 private:
216 scoped_ptr<CallbackType> callback_;
217 base::ThreadChecker thread_checker_;
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();
229 void CallWhileLocked(P1 p1, P2 p2, P3 p3) {
230 DCHECK(thread_checker_.CalledOnValidThread());
231 ProxyAutoLock lock;
233 scoped_ptr<CallbackType> temp_callback(callback_.Pass());
234 temp_callback->Run(p1, p2, p3);
238 private:
239 scoped_ptr<CallbackType> callback_;
240 base::ThreadChecker thread_checker_;
243 } // namespace internal
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.
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:
258 // GetMainThreadMessageLoop()->PostDelayedTask(
259 // FROM_HERE,
260 // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)),
261 // delay_in_ms);
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));
285 } // namespace ppapi
287 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_