OLD | NEW |
---|---|
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 Loading... | |
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_ |
OLD | NEW |