// 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 "ppapi/shared_impl/ppapi_shared_export.h" namespace base { class Lock; } 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: // 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(); private: 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 ReturnType CallWhileUnlocked(ReturnType (*function)()) { ProxyAutoUnlock unlock; return function(); } template ReturnType CallWhileUnlocked(ReturnType (*function)(P1), const P1& p1) { ProxyAutoUnlock unlock; return function(p1); } template ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2), const P1& p1, const P2& p2) { ProxyAutoUnlock unlock; return function(p1, p2); } template ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3), const P1& p1, const P2& p2, const P3& p3) { ProxyAutoUnlock unlock; return function(p1, p2, p3); } template ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4), const P1& p1, const P2& p2, const P3& p3, const P4& p4) { ProxyAutoUnlock unlock; return function(p1, p2, p3, p4); } template ReturnType CallWhileUnlocked(ReturnType (*function)(P1, P2, P3, P4, P5), 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); // CallWhileLocked locks the ProxyLock and runs the given closure immediately. // The lock is released when CallWhileLocked returns. This function assumes the // lock is not held. This is mostly for use in RunWhileLocked; see below. void PPAPI_SHARED_EXPORT CallWhileLocked(const base::Closure& closure); // RunWhileLocked binds the given closure with CallWhileLocked and returns the // new Closure. This is for cases where you want to run a task, but you want to // ensure that the ProxyLock is acquired for the duration of the task. // Example usage: // GetMainThreadMessageLoop()->PostDelayedTask( // FROM_HERE, // RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), // delay_in_ms); inline base::Closure RunWhileLocked(const base::Closure& closure) { return base::Bind(CallWhileLocked, closure); } } // namespace ppapi #endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_