Chromium Code Reviews| 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 |