|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef PPAPI_SHARED_IMPL_PROXY_LOCK_H_ | 
|  | #define PPAPI_SHARED_IMPL_PROXY_LOCK_H_ | 
|  |  | 
|  | #include "base/basictypes.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/memory/scoped_ptr.h" | 
|  | #include "base/threading/thread_checker.h" | 
|  |  | 
|  | #include "ppapi/shared_impl/ppapi_shared_export.h" | 
|  |  | 
|  | namespace base { | 
|  | class Lock; | 
|  | } | 
|  |  | 
|  | namespace content { | 
|  | class HostGlobals; | 
|  | } | 
|  |  | 
|  | namespace ppapi { | 
|  |  | 
|  | // This is the one lock to rule them all for the ppapi proxy. All PPB interface | 
|  | // functions that need to be synchronized should lock this lock on entry. This | 
|  | // is normally accomplished by using an appropriate Enter RAII object at the | 
|  | // beginning of each thunk function. | 
|  | // | 
|  | // TODO(dmichael): If this turns out to be too slow and contentious, we'll want | 
|  | // to use multiple locks. E.g., one for the var tracker, one for the resource | 
|  | // tracker, etc. | 
|  | class PPAPI_SHARED_EXPORT ProxyLock { | 
|  | public: | 
|  | // Return the global ProxyLock. Normally, you should not access this | 
|  | // directly but instead use ProxyAutoLock or ProxyAutoUnlock. But sometimes | 
|  | // you need access to the ProxyLock, for example to create a condition | 
|  | // variable. | 
|  | static base::Lock* Get(); | 
|  |  | 
|  | // Acquire the proxy lock. If it is currently held by another thread, block | 
|  | // until it is available. If the lock has not been set using the 'Set' method, | 
|  | // this operation does nothing. That is the normal case for the host side; | 
|  | // see PluginResourceTracker for where the lock gets set for the out-of- | 
|  | // process plugin case. | 
|  | static void Acquire(); | 
|  | // Relinquish the proxy lock. If the lock has not been set, this does nothing. | 
|  | static void Release(); | 
|  |  | 
|  | // Assert that the lock is owned by the current thread (in the plugin | 
|  | // process). Does nothing when running in-process (or in the host process). | 
|  | static void AssertAcquired(); | 
|  | static void AssertAcquiredDebugOnly() { | 
|  | #ifndef NDEBUG | 
|  | AssertAcquired(); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | // We have some unit tests where one thread pretends to be the host and one | 
|  | // pretends to be the plugin. This allows the lock to do nothing on only one | 
|  | // thread to support these tests. See TwoWayTest for more information. | 
|  | class PPAPI_SHARED_EXPORT LockingDisablerForTest { | 
|  | public: | 
|  | LockingDisablerForTest(); | 
|  | ~LockingDisablerForTest(); | 
|  | }; | 
|  |  | 
|  | private: | 
|  | friend class content::HostGlobals; | 
|  | // On the host side, we do not lock. This must be called at most once at | 
|  | // startup, before other threads that may access the ProxyLock have had a | 
|  | // chance to run. | 
|  | static void DisableLocking(); | 
|  |  | 
|  | DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock); | 
|  | }; | 
|  |  | 
|  | // A simple RAII class for locking the PPAPI proxy lock on entry and releasing | 
|  | // on exit. This is for simple interfaces that don't use the 'thunk' system, | 
|  | // such as PPB_Var and PPB_Core. | 
|  | class ProxyAutoLock { | 
|  | public: | 
|  | ProxyAutoLock() { ProxyLock::Acquire(); } | 
|  | ~ProxyAutoLock() { ProxyLock::Release(); } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock); | 
|  | }; | 
|  |  | 
|  | // The inverse of the above; unlock on construction, lock on destruction. This | 
|  | // is useful for calling out to the plugin, when we need to unlock but ensure | 
|  | // that we re-acquire the lock when the plugin is returns or raises an | 
|  | // exception. | 
|  | class ProxyAutoUnlock { | 
|  | public: | 
|  | ProxyAutoUnlock() { ProxyLock::Release(); } | 
|  | ~ProxyAutoUnlock() { ProxyLock::Acquire(); } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock); | 
|  | }; | 
|  |  | 
|  | // A set of function template overloads for invoking a function pointer while | 
|  | // the ProxyLock is unlocked. This assumes that the luck is held. | 
|  | // CallWhileUnlocked unlocks the ProxyLock just before invoking the given | 
|  | // function. The lock is immediately re-acquired when the invoked function | 
|  | // function returns. CallWhileUnlocked returns whatever the given function | 
|  | // returned. | 
|  | // | 
|  | // Example usage: | 
|  | //   *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent, | 
|  | //                               instance, | 
|  | //                               resource->pp_resource()); | 
|  | template <class ReturnType> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)()) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(); | 
|  | } | 
|  | // Note we use 2 types for the params, even though for the most part we expect | 
|  | // A1 to match P1. We let the compiler determine if P1 can convert safely to | 
|  | // A1. This allows callers to avoid having to do things like | 
|  | // const_cast to add const. | 
|  | template <class ReturnType, class A1, class P1> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)(A1), const P1& p1) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(p1); | 
|  | } | 
|  | template <class ReturnType, class A1, class A2, class P1, class P2> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2), | 
|  | const P1& p1, | 
|  | const P2& p2) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(p1, p2); | 
|  | } | 
|  | template <class ReturnType, class A1, class A2, class A3, class P1, class P2, | 
|  | class P3> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3), | 
|  | const P1& p1, | 
|  | const P2& p2, | 
|  | const P3& p3) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(p1, p2, p3); | 
|  | } | 
|  | template <class ReturnType, class A1, class A2, class A3, class A4, class P1, | 
|  | class P2, class P3, class P4> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3, A4), | 
|  | const P1& p1, | 
|  | const P2& p2, | 
|  | const P3& p3, | 
|  | const P4& p4) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(p1, p2, p3, p4); | 
|  | } | 
|  | template <class ReturnType, class A1, class A2, class A3, class A4, class A5, | 
|  | class P1, class P2, class P3, class P4, class P5> | 
|  | ReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3, A4, A5), | 
|  | const P1& p1, | 
|  | const P2& p2, | 
|  | const P3& p3, | 
|  | const P4& p4, | 
|  | const P5& p5) { | 
|  | ProxyAutoUnlock unlock; | 
|  | return function(p1, p2, p3, p4, p5); | 
|  | } | 
|  | void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | template <typename RunType> | 
|  | class RunWhileLockedHelper; | 
|  |  | 
|  | // A helper class to ensure that a callback is always run and destroyed while | 
|  | // the ProxyLock is held. A callback that is bound with ref-counted Var or | 
|  | // Resource parameters may invoke methods on the VarTracker or the | 
|  | // ResourceTracker in its destructor, and these require the ProxyLock. | 
|  | template <> | 
|  | class RunWhileLockedHelper<void()> { | 
|  | public: | 
|  | typedef base::Callback<void()> CallbackType; | 
|  | explicit RunWhileLockedHelper(const CallbackType& callback) | 
|  | : callback_(new CallbackType(callback)) { | 
|  | // CallWhileLocked and destruction might happen on a different thread from | 
|  | // creation. | 
|  | thread_checker_.DetachFromThread(); | 
|  | } | 
|  | static void CallWhileLocked(scoped_ptr<RunWhileLockedHelper> ptr) { | 
|  | // Bind thread_checker_ to this thread so we can check in the destructor. | 
|  | // *If* the callback gets invoked, it's important that RunWhileLockedHelper | 
|  | // is destroyed on the same thread (see the comments in the destructor). | 
|  | DCHECK(ptr->thread_checker_.CalledOnValidThread()); | 
|  | ProxyAutoLock lock; | 
|  | { | 
|  | // Use a scope and local Callback to ensure that the callback is cleared | 
|  | // before the lock is released, even in the unlikely event that Run() | 
|  | // throws an exception. | 
|  | scoped_ptr<CallbackType> temp_callback(ptr->callback_.Pass()); | 
|  | temp_callback->Run(); | 
|  | } | 
|  | } | 
|  |  | 
|  | ~RunWhileLockedHelper() { | 
|  | // Check that the Callback is destroyed on the same thread as where | 
|  | // CallWhileLocked happened if CallWhileLocked happened. If we weren't | 
|  | // invoked, thread_checked_ isn't bound to a thread. | 
|  | DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | // Here we read callback_ without the lock. This is why the callback must be | 
|  | // destroyed on the same thread where it runs. Note that callback_ will be | 
|  | // NULL if it has already been run via CallWhileLocked. In this case, | 
|  | // there's no need to acquire the lock, because we don't touch any shared | 
|  | // data. | 
|  | if (callback_) { | 
|  | // If the callback was *not* run, we're in a case where the task queue | 
|  | // we got pushed to has been destroyed (e.g., the thread is shut down and | 
|  | // its MessageLoop destroyed before all tasks have run.) | 
|  | // | 
|  | // We still need to have the lock when we destroy the callback: | 
|  | // - Because Resource and Var inherit RefCounted (not | 
|  | //   ThreadSafeRefCounted). | 
|  | // - Because if the callback owns the last ref to a Resource, it will | 
|  | //   call the ResourceTracker and also the Resource's destructor, which | 
|  | //   both require the ProxyLock. | 
|  | ProxyAutoLock lock; | 
|  | callback_.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(RunWhileLockedHelper); | 
|  | scoped_ptr<CallbackType> callback_; | 
|  |  | 
|  | // Used to ensure that the Callback is run and deleted on the same thread. | 
|  | base::ThreadChecker thread_checker_; | 
|  | }; | 
|  |  | 
|  | template <typename P1> | 
|  | class RunWhileLockedHelper<void(P1)> { | 
|  | public: | 
|  | typedef base::Callback<void(P1)> CallbackType; | 
|  | explicit RunWhileLockedHelper(const CallbackType& callback) | 
|  | : callback_(new CallbackType(callback)) { | 
|  | thread_checker_.DetachFromThread(); | 
|  | } | 
|  | static void CallWhileLocked(scoped_ptr<RunWhileLockedHelper> ptr, P1 p1) { | 
|  | DCHECK(ptr->thread_checker_.CalledOnValidThread()); | 
|  | ProxyAutoLock lock; | 
|  | { | 
|  | scoped_ptr<CallbackType> temp_callback(ptr->callback_.Pass()); | 
|  | temp_callback->Run(p1); | 
|  | } | 
|  | } | 
|  | ~RunWhileLockedHelper() { | 
|  | DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | if (callback_) { | 
|  | ProxyAutoLock lock; | 
|  | callback_.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(RunWhileLockedHelper); | 
|  | scoped_ptr<CallbackType> callback_; | 
|  | base::ThreadChecker thread_checker_; | 
|  | }; | 
|  |  | 
|  | template <typename P1, typename P2> | 
|  | class RunWhileLockedHelper<void(P1, P2)> { | 
|  | public: | 
|  | typedef base::Callback<void(P1, P2)> CallbackType; | 
|  | explicit RunWhileLockedHelper(const CallbackType& callback) | 
|  | : callback_(new CallbackType(callback)) { | 
|  | thread_checker_.DetachFromThread(); | 
|  | } | 
|  | static void CallWhileLocked( | 
|  | scoped_ptr<RunWhileLockedHelper> ptr, P1 p1, P2 p2) { | 
|  | DCHECK(ptr->thread_checker_.CalledOnValidThread()); | 
|  | ProxyAutoLock lock; | 
|  | { | 
|  | scoped_ptr<CallbackType> temp_callback(ptr->callback_.Pass()); | 
|  | temp_callback->Run(p1, p2); | 
|  | } | 
|  | } | 
|  | ~RunWhileLockedHelper() { | 
|  | DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | if (callback_) { | 
|  | ProxyAutoLock lock; | 
|  | callback_.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(RunWhileLockedHelper); | 
|  | scoped_ptr<CallbackType> callback_; | 
|  | base::ThreadChecker thread_checker_; | 
|  | }; | 
|  |  | 
|  | template <typename P1, typename P2, typename P3> | 
|  | class RunWhileLockedHelper<void(P1, P2, P3)> { | 
|  | public: | 
|  | typedef base::Callback<void(P1, P2, P3)> CallbackType; | 
|  | explicit RunWhileLockedHelper(const CallbackType& callback) | 
|  | : callback_(new CallbackType(callback)) { | 
|  | thread_checker_.DetachFromThread(); | 
|  | } | 
|  | static void CallWhileLocked( | 
|  | scoped_ptr<RunWhileLockedHelper> ptr, P1 p1, P2 p2, P3 p3) { | 
|  | DCHECK(ptr->thread_checker_.CalledOnValidThread()); | 
|  | ProxyAutoLock lock; | 
|  | { | 
|  | scoped_ptr<CallbackType> temp_callback(ptr->callback_.Pass()); | 
|  | temp_callback->Run(p1, p2, p3); | 
|  | } | 
|  | } | 
|  | ~RunWhileLockedHelper() { | 
|  | DCHECK(thread_checker_.CalledOnValidThread()); | 
|  | if (callback_) { | 
|  | ProxyAutoLock lock; | 
|  | callback_.reset(); | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(RunWhileLockedHelper); | 
|  | scoped_ptr<CallbackType> callback_; | 
|  | base::ThreadChecker thread_checker_; | 
|  | }; | 
|  |  | 
|  | }  // namespace internal | 
|  |  | 
|  | // RunWhileLocked wraps the given Callback in a new Callback that, when invoked: | 
|  | //  1) Locks the ProxyLock. | 
|  | //  2) Runs the original Callback (forwarding arguments, if any). | 
|  | //  3) Clears the original Callback (while the lock is held). | 
|  | //  4) Unlocks the ProxyLock. | 
|  | // Note that it's important that the callback is cleared in step (3), in case | 
|  | // clearing the Callback causes a destructor (e.g., for a Resource) to run, | 
|  | // which should hold the ProxyLock to avoid data races. | 
|  | // | 
|  | // This is for cases where you want to run a task or store a Callback, but you | 
|  | // want to ensure that the ProxyLock is acquired for the duration of the task | 
|  | // that the Callback runs. | 
|  | // EXAMPLE USAGE: | 
|  | //   GetMainThreadMessageLoop()->PostDelayedTask( | 
|  | //     FROM_HERE, | 
|  | //     RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), | 
|  | //     delay_in_ms); | 
|  | // | 
|  | // In normal usage like the above, this all should "just work". However, if you | 
|  | // do something unusual, you may get a runtime crash due to deadlock. Here are | 
|  | // the ways that the returned Callback must be used to avoid a deadlock: | 
|  | // (1) copied to another Callback. After that, the original callback can be | 
|  | // destroyed with or without the proxy lock acquired, while the newly assigned | 
|  | // callback has to conform to these same restrictions. Or | 
|  | // (2) run without proxy lock acquired (e.g., being posted to a MessageLoop | 
|  | // and run there). The callback must be destroyed on the same thread where it | 
|  | // was run (but can be destroyed with or without the proxy lock acquired). Or | 
|  | // (3) destroyed without the proxy lock acquired. | 
|  | template <class FunctionType> | 
|  | inline base::Callback<FunctionType> RunWhileLocked( | 
|  | const base::Callback<FunctionType>& callback) { | 
|  | // NOTE: the reason we use "scoped_ptr" here instead of letting the callback | 
|  | // own it via base::Owned is kind of subtle. Imagine for the moment that we | 
|  | // call RunWhileLocked without the ProxyLock: | 
|  | // { | 
|  | //   base::Callback<void ()> local_callback = base::Bind(&Foo); | 
|  | //   some_task_runner.PostTask(FROM_HERE, RunWhileLocked(local_callback)); | 
|  | // } | 
|  | // In this case, since we don't have a lock synchronizing us, it's possible | 
|  | // for the callback to run on the other thread before we return and destroy | 
|  | // |local_callback|. The important thing here is that even though the other | 
|  | // thread gets a copy of the callback, the internal "BindState" of the | 
|  | // callback is refcounted and shared between all copies of the callback. So | 
|  | // in that case, if we used base::Owned, we might delete RunWhileLockedHelper | 
|  | // on this thread, which will violate the RunWhileLockedHelper's assumption | 
|  | // that it is destroyed on the same thread where it is run. | 
|  | scoped_ptr<internal::RunWhileLockedHelper<FunctionType>> helper( | 
|  | new internal::RunWhileLockedHelper<FunctionType>(callback)); | 
|  | return base::Bind( | 
|  | &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked, | 
|  | base::Passed(helper.Pass())); | 
|  | } | 
|  |  | 
|  | }  // namespace ppapi | 
|  |  | 
|  | #endif  // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ |