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" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 static void DisableLocking(); | 74 static void DisableLocking(); |
75 | 75 |
76 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock); | 76 DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock); |
77 }; | 77 }; |
78 | 78 |
79 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing | 79 // A simple RAII class for locking the PPAPI proxy lock on entry and releasing |
80 // on exit. This is for simple interfaces that don't use the 'thunk' system, | 80 // on exit. This is for simple interfaces that don't use the 'thunk' system, |
81 // such as PPB_Var and PPB_Core. | 81 // such as PPB_Var and PPB_Core. |
82 class ProxyAutoLock { | 82 class ProxyAutoLock { |
83 public: | 83 public: |
84 ProxyAutoLock() { | 84 ProxyAutoLock() { ProxyLock::Acquire(); } |
85 ProxyLock::Acquire(); | 85 ~ProxyAutoLock() { ProxyLock::Release(); } |
86 } | 86 |
87 ~ProxyAutoLock() { | |
88 ProxyLock::Release(); | |
89 } | |
90 private: | 87 private: |
91 DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock); | 88 DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock); |
92 }; | 89 }; |
93 | 90 |
94 // The inverse of the above; unlock on construction, lock on destruction. This | 91 // The inverse of the above; unlock on construction, lock on destruction. This |
95 // is useful for calling out to the plugin, when we need to unlock but ensure | 92 // is useful for calling out to the plugin, when we need to unlock but ensure |
96 // that we re-acquire the lock when the plugin is returns or raises an | 93 // that we re-acquire the lock when the plugin is returns or raises an |
97 // exception. | 94 // exception. |
98 class ProxyAutoUnlock { | 95 class ProxyAutoUnlock { |
99 public: | 96 public: |
100 ProxyAutoUnlock() { | 97 ProxyAutoUnlock() { ProxyLock::Release(); } |
101 ProxyLock::Release(); | 98 ~ProxyAutoUnlock() { ProxyLock::Acquire(); } |
102 } | 99 |
103 ~ProxyAutoUnlock() { | |
104 ProxyLock::Acquire(); | |
105 } | |
106 private: | 100 private: |
107 DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock); | 101 DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock); |
108 }; | 102 }; |
109 | 103 |
110 // A set of function template overloads for invoking a function pointer while | 104 // A set of function template overloads for invoking a function pointer while |
111 // the ProxyLock is unlocked. This assumes that the luck is held. | 105 // the ProxyLock is unlocked. This assumes that the luck is held. |
112 // CallWhileUnlocked unlocks the ProxyLock just before invoking the given | 106 // CallWhileUnlocked unlocks the ProxyLock just before invoking the given |
113 // function. The lock is immediately re-acquired when the invoked function | 107 // function. The lock is immediately re-acquired when the invoked function |
114 // function returns. CallWhileUnlocked returns whatever the given function | 108 // function returns. CallWhileUnlocked returns whatever the given function |
115 // returned. | 109 // returned. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 return function(p1, p2, p3, p4, p5); | 157 return function(p1, p2, p3, p4, p5); |
164 } | 158 } |
165 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); | 159 void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); |
166 | 160 |
167 namespace internal { | 161 namespace internal { |
168 | 162 |
169 template <typename RunType> | 163 template <typename RunType> |
170 class RunWhileLockedHelper; | 164 class RunWhileLockedHelper; |
171 | 165 |
172 template <> | 166 template <> |
173 class RunWhileLockedHelper<void ()> { | 167 class RunWhileLockedHelper<void()> { |
174 public: | 168 public: |
175 typedef base::Callback<void ()> CallbackType; | 169 typedef base::Callback<void()> CallbackType; |
176 explicit RunWhileLockedHelper(const CallbackType& callback) | 170 explicit RunWhileLockedHelper(const CallbackType& callback) |
177 : callback_(new CallbackType(callback)) { | 171 : callback_(new CallbackType(callback)) { |
178 // Copying |callback| may adjust reference counts for bound Vars or | 172 // Copying |callback| may adjust reference counts for bound Vars or |
179 // Resources; we should have the lock already. | 173 // Resources; we should have the lock already. |
180 ProxyLock::AssertAcquired(); | 174 ProxyLock::AssertAcquired(); |
181 // CallWhileLocked and destruction might happen on a different thread from | 175 // CallWhileLocked and destruction might happen on a different thread from |
182 // creation. | 176 // creation. |
183 thread_checker_.DetachFromThread(); | 177 thread_checker_.DetachFromThread(); |
184 } | 178 } |
185 void CallWhileLocked() { | 179 void CallWhileLocked() { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 // ensures that the Resource's destructor is invoked only with the lock | 211 // ensures that the Resource's destructor is invoked only with the lock |
218 // held. | 212 // held. |
219 // | 213 // |
220 // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted), | 214 // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted), |
221 // and these callbacks need to be usable on any thread. So we need to lock | 215 // 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. | 216 // when releasing the callback to avoid ref counting races. |
223 ProxyAutoLock lock; | 217 ProxyAutoLock lock; |
224 callback_.reset(); | 218 callback_.reset(); |
225 } | 219 } |
226 } | 220 } |
| 221 |
227 private: | 222 private: |
228 scoped_ptr<CallbackType> callback_; | 223 scoped_ptr<CallbackType> callback_; |
229 | 224 |
230 // Used to ensure that the Callback is run and deleted on the same thread. | 225 // Used to ensure that the Callback is run and deleted on the same thread. |
231 base::ThreadChecker thread_checker_; | 226 base::ThreadChecker thread_checker_; |
232 }; | 227 }; |
233 | 228 |
234 template <typename P1> | 229 template <typename P1> |
235 class RunWhileLockedHelper<void (P1)> { | 230 class RunWhileLockedHelper<void(P1)> { |
236 public: | 231 public: |
237 typedef base::Callback<void (P1)> CallbackType; | 232 typedef base::Callback<void(P1)> CallbackType; |
238 explicit RunWhileLockedHelper(const CallbackType& callback) | 233 explicit RunWhileLockedHelper(const CallbackType& callback) |
239 : callback_(new CallbackType(callback)) { | 234 : callback_(new CallbackType(callback)) { |
240 ProxyLock::AssertAcquired(); | 235 ProxyLock::AssertAcquired(); |
241 thread_checker_.DetachFromThread(); | 236 thread_checker_.DetachFromThread(); |
242 } | 237 } |
243 void CallWhileLocked(P1 p1) { | 238 void CallWhileLocked(P1 p1) { |
244 DCHECK(thread_checker_.CalledOnValidThread()); | 239 DCHECK(thread_checker_.CalledOnValidThread()); |
245 ProxyAutoLock lock; | 240 ProxyAutoLock lock; |
246 { | 241 { |
247 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); | 242 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); |
248 temp_callback->Run(p1); | 243 temp_callback->Run(p1); |
249 } | 244 } |
250 } | 245 } |
251 ~RunWhileLockedHelper() { | 246 ~RunWhileLockedHelper() { |
252 DCHECK(thread_checker_.CalledOnValidThread()); | 247 DCHECK(thread_checker_.CalledOnValidThread()); |
253 if (callback_) { | 248 if (callback_) { |
254 ProxyAutoLock lock; | 249 ProxyAutoLock lock; |
255 callback_.reset(); | 250 callback_.reset(); |
256 } | 251 } |
257 } | 252 } |
| 253 |
258 private: | 254 private: |
259 scoped_ptr<CallbackType> callback_; | 255 scoped_ptr<CallbackType> callback_; |
260 base::ThreadChecker thread_checker_; | 256 base::ThreadChecker thread_checker_; |
261 }; | 257 }; |
262 | 258 |
263 template <typename P1, typename P2> | 259 template <typename P1, typename P2> |
264 class RunWhileLockedHelper<void (P1, P2)> { | 260 class RunWhileLockedHelper<void(P1, P2)> { |
265 public: | 261 public: |
266 typedef base::Callback<void (P1, P2)> CallbackType; | 262 typedef base::Callback<void(P1, P2)> CallbackType; |
267 explicit RunWhileLockedHelper(const CallbackType& callback) | 263 explicit RunWhileLockedHelper(const CallbackType& callback) |
268 : callback_(new CallbackType(callback)) { | 264 : callback_(new CallbackType(callback)) { |
269 ProxyLock::AssertAcquired(); | 265 ProxyLock::AssertAcquired(); |
270 thread_checker_.DetachFromThread(); | 266 thread_checker_.DetachFromThread(); |
271 } | 267 } |
272 void CallWhileLocked(P1 p1, P2 p2) { | 268 void CallWhileLocked(P1 p1, P2 p2) { |
273 DCHECK(thread_checker_.CalledOnValidThread()); | 269 DCHECK(thread_checker_.CalledOnValidThread()); |
274 ProxyAutoLock lock; | 270 ProxyAutoLock lock; |
275 { | 271 { |
276 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); | 272 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); |
277 temp_callback->Run(p1, p2); | 273 temp_callback->Run(p1, p2); |
278 } | 274 } |
279 } | 275 } |
280 ~RunWhileLockedHelper() { | 276 ~RunWhileLockedHelper() { |
281 DCHECK(thread_checker_.CalledOnValidThread()); | 277 DCHECK(thread_checker_.CalledOnValidThread()); |
282 if (callback_) { | 278 if (callback_) { |
283 ProxyAutoLock lock; | 279 ProxyAutoLock lock; |
284 callback_.reset(); | 280 callback_.reset(); |
285 } | 281 } |
286 } | 282 } |
| 283 |
287 private: | 284 private: |
288 scoped_ptr<CallbackType> callback_; | 285 scoped_ptr<CallbackType> callback_; |
289 base::ThreadChecker thread_checker_; | 286 base::ThreadChecker thread_checker_; |
290 }; | 287 }; |
291 | 288 |
292 template <typename P1, typename P2, typename P3> | 289 template <typename P1, typename P2, typename P3> |
293 class RunWhileLockedHelper<void (P1, P2, P3)> { | 290 class RunWhileLockedHelper<void(P1, P2, P3)> { |
294 public: | 291 public: |
295 typedef base::Callback<void (P1, P2, P3)> CallbackType; | 292 typedef base::Callback<void(P1, P2, P3)> CallbackType; |
296 explicit RunWhileLockedHelper(const CallbackType& callback) | 293 explicit RunWhileLockedHelper(const CallbackType& callback) |
297 : callback_(new CallbackType(callback)) { | 294 : callback_(new CallbackType(callback)) { |
298 ProxyLock::AssertAcquired(); | 295 ProxyLock::AssertAcquired(); |
299 thread_checker_.DetachFromThread(); | 296 thread_checker_.DetachFromThread(); |
300 } | 297 } |
301 void CallWhileLocked(P1 p1, P2 p2, P3 p3) { | 298 void CallWhileLocked(P1 p1, P2 p2, P3 p3) { |
302 DCHECK(thread_checker_.CalledOnValidThread()); | 299 DCHECK(thread_checker_.CalledOnValidThread()); |
303 ProxyAutoLock lock; | 300 ProxyAutoLock lock; |
304 { | 301 { |
305 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); | 302 scoped_ptr<CallbackType> temp_callback(callback_.Pass()); |
306 temp_callback->Run(p1, p2, p3); | 303 temp_callback->Run(p1, p2, p3); |
307 } | 304 } |
308 } | 305 } |
309 ~RunWhileLockedHelper() { | 306 ~RunWhileLockedHelper() { |
310 DCHECK(thread_checker_.CalledOnValidThread()); | 307 DCHECK(thread_checker_.CalledOnValidThread()); |
311 if (callback_) { | 308 if (callback_) { |
312 ProxyAutoLock lock; | 309 ProxyAutoLock lock; |
313 callback_.reset(); | 310 callback_.reset(); |
314 } | 311 } |
315 } | 312 } |
| 313 |
316 private: | 314 private: |
317 scoped_ptr<CallbackType> callback_; | 315 scoped_ptr<CallbackType> callback_; |
318 base::ThreadChecker thread_checker_; | 316 base::ThreadChecker thread_checker_; |
319 }; | 317 }; |
320 | 318 |
321 } // namespace internal | 319 } // namespace internal |
322 | 320 |
323 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked: | 321 // RunWhileLocked wraps the given Callback in a new Callback that, when invoked: |
324 // 1) Locks the ProxyLock. | 322 // 1) Locks the ProxyLock. |
325 // 2) Runs the original Callback (forwarding arguments, if any). | 323 // 2) Runs the original Callback (forwarding arguments, if any). |
(...skipping 16 matching lines...) Expand all Loading... |
342 // do something unusual, you may get a runtime crash due to deadlock. Here are | 340 // do something unusual, you may get a runtime crash due to deadlock. Here are |
343 // the ways that the returned Callback must be used to avoid a deadlock: | 341 // the ways that the returned Callback must be used to avoid a deadlock: |
344 // (1) copied to another Callback. After that, the original callback can be | 342 // (1) copied to another Callback. After that, the original callback can be |
345 // destroyed with or without the proxy lock acquired, while the newly assigned | 343 // destroyed with or without the proxy lock acquired, while the newly assigned |
346 // callback has to conform to these same restrictions. Or | 344 // callback has to conform to these same restrictions. Or |
347 // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop | 345 // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop |
348 // and run there). The callback must be destroyed on the same thread where it | 346 // and run there). The callback must be destroyed on the same thread where it |
349 // was run (but can be destroyed with or without the proxy lock acquired). Or | 347 // was run (but can be destroyed with or without the proxy lock acquired). Or |
350 // (3) destroyed without the proxy lock acquired. | 348 // (3) destroyed without the proxy lock acquired. |
351 template <class FunctionType> | 349 template <class FunctionType> |
352 inline base::Callback<FunctionType> | 350 inline base::Callback<FunctionType> RunWhileLocked( |
353 RunWhileLocked(const base::Callback<FunctionType>& callback) { | 351 const base::Callback<FunctionType>& callback) { |
354 internal::RunWhileLockedHelper<FunctionType>* helper = | 352 internal::RunWhileLockedHelper<FunctionType>* helper = |
355 new internal::RunWhileLockedHelper<FunctionType>(callback); | 353 new internal::RunWhileLockedHelper<FunctionType>(callback); |
356 return base::Bind( | 354 return base::Bind( |
357 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked, | 355 &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked, |
358 base::Owned(helper)); | 356 base::Owned(helper)); |
359 } | 357 } |
360 | 358 |
361 } // namespace ppapi | 359 } // namespace ppapi |
362 | 360 |
363 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ | 361 #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ |
OLD | NEW |