15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 1158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/threading/thread_checker.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/shared_impl/ppapi_shared_export.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Lock; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace content { 20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class HostGlobals; 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ppapi { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the one lock to rule them all for the ppapi proxy. All PPB interface 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functions that need to be synchronized should lock this lock on entry. This 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is normally accomplished by using an appropriate Enter RAII object at the 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// beginning of each thunk function. 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(dmichael): If this turns out to be too slow and contentious, we'll want 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to use multiple locks. E.g., one for the var tracker, one for the resource 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tracker, etc. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class PPAPI_SHARED_EXPORT ProxyLock { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Return the global ProxyLock. Normally, you should not access this 36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // directly but instead use ProxyAutoLock or ProxyAutoUnlock. But sometimes 37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // you need access to the ProxyLock, for example to create a condition 38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // variable. 39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) static base::Lock* Get(); 40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Acquire the proxy lock. If it is currently held by another thread, block 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // until it is available. If the lock has not been set using the 'Set' method, 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this operation does nothing. That is the normal case for the host side; 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // see PluginResourceTracker for where the lock gets set for the out-of- 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // process plugin case. 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Acquire(); 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Relinquish the proxy lock. If the lock has not been set, this does nothing. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void Release(); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assert that the lock is owned by the current thread (in the plugin 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // process). Does nothing when running in-process (or in the host process). 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void AssertAcquired(); 534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) static void AssertAcquiredDebugOnly() { 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifndef NDEBUG 554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) AssertAcquired(); 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // We have some unit tests where one thread pretends to be the host and one 60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // pretends to be the plugin. This allows the lock to do nothing on only one 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // thread to support these tests. See TwoWayTest for more information. 62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) static void DisableLockingOnThreadForTest(); 63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Enables locking on the current thread. Although locking is enabled by 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // default, unit tests that rely on the lock being enabled should *still* 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // call this, since a previous test may have disabled locking. 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) static void EnableLockingOnThreadForTest(); 68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) friend class content::HostGlobals; 71d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // On the host side, we do not lock. This must be called at most once at 72d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // startup, before other threads that may access the ProxyLock have had a 73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // chance to run. 74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) static void DisableLocking(); 75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_IMPLICIT_CONSTRUCTORS(ProxyLock); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A simple RAII class for locking the PPAPI proxy lock on entry and releasing 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// on exit. This is for simple interfaces that don't use the 'thunk' system, 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// such as PPB_Var and PPB_Core. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProxyAutoLock { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ProxyAutoLock() { ProxyLock::Acquire(); } 85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ~ProxyAutoLock() { ProxyLock::Release(); } 86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ProxyAutoLock); 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The inverse of the above; unlock on construction, lock on destruction. This 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is useful for calling out to the plugin, when we need to unlock but ensure 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that we re-acquire the lock when the plugin is returns or raises an 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// exception. 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ProxyAutoUnlock { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ProxyAutoUnlock() { ProxyLock::Release(); } 98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ~ProxyAutoUnlock() { ProxyLock::Acquire(); } 99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ProxyAutoUnlock); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A set of function template overloads for invoking a function pointer while 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the ProxyLock is unlocked. This assumes that the luck is held. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// CallWhileUnlocked unlocks the ProxyLock just before invoking the given 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function. The lock is immediately re-acquired when the invoked function 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// function returns. CallWhileUnlocked returns whatever the given function 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// returned. 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Example usage: 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// *result = CallWhileUnlocked(ppp_input_event_impl_->HandleInputEvent, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// instance, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// resource->pp_resource()); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class ReturnType> 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ReturnType CallWhileUnlocked(ReturnType (*function)()) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Note we use 2 types for the params, even though for the most part we expect 1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// A1 to match P1. We let the compiler determine if P1 can convert safely to 1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// A1. This allows callers to avoid having to do things like 1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// const_cast to add const. 1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitemplate <class ReturnType, class A1, class P1> 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciReturnType CallWhileUnlocked(ReturnType (*function)(A1), const P1& p1) { 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(p1); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitemplate <class ReturnType, class A1, class A2, class P1, class P2> 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2), 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P1& p1, 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P2& p2) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(p1, p2); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitemplate <class ReturnType, class A1, class A2, class A3, class P1, class P2, 1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class P3> 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3), 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P1& p1, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P2& p2, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P3& p3) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(p1, p2, p3); 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitemplate <class ReturnType, class A1, class A2, class A3, class A4, class P1, 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class P2, class P3, class P4> 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3, A4), 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P1& p1, 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P2& p2, 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P3& p3, 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P4& p4) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(p1, p2, p3, p4); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitemplate <class ReturnType, class A1, class A2, class A3, class A4, class A5, 1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class P1, class P2, class P3, class P4, class P5> 1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciReturnType CallWhileUnlocked(ReturnType (*function)(A1, A2, A3, A4, A5), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P1& p1, 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P2& p2, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P3& p3, 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P4& p4, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const P5& p5) { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProxyAutoUnlock unlock; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return function(p1, p2, p3, p4, p5); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PPAPI_SHARED_EXPORT CallWhileUnlocked(const base::Closure& closure); 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochnamespace internal { 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 17058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <typename RunType> 17158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochclass RunWhileLockedHelper; 17258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 17358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <> 174a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class RunWhileLockedHelper<void()> { 17558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch public: 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef base::Callback<void()> CallbackType; 17758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch explicit RunWhileLockedHelper(const CallbackType& callback) 17858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch : callback_(new CallbackType(callback)) { 17958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // Copying |callback| may adjust reference counts for bound Vars or 18058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // Resources; we should have the lock already. 18158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyLock::AssertAcquired(); 18258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // CallWhileLocked and destruction might happen on a different thread from 18358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // creation. 18458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch thread_checker_.DetachFromThread(); 18558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 18658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch void CallWhileLocked() { 18758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // Bind thread_checker_ to this thread so we can check in the destructor. 18858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 18958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyAutoLock lock; 19058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch { 19158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // Use a scope and local Callback to ensure that the callback is cleared 19258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // before the lock is released, even in the unlikely event that Run() 19358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // throws an exception. 19458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> temp_callback(callback_.Pass()); 19558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch temp_callback->Run(); 19658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 19758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 19858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ~RunWhileLockedHelper() { 200d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Check that the Callback is destroyed on the same thread as where 201d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // CallWhileLocked happened (if CallWhileLocked happened). 202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 203d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Here we read callback_ without the lock. This is why the callback must be 204d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // destroyed on the same thread where it runs. There are 2 cases where 205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // callback_ will be NULL: 206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 1) This is the original RunWhileLockedHelper that RunWhileLocked 207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // created. When it was copied somewhere else (e.g., to a MessageLoop 208d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // queue), callback_ was passed to the new copy, and the original 209d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // RunWhileLockedHelper's callback_ was set to NULL (since scoped_ptrs 210d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // only ever have 1 owner). In this case, we don't want to acquire the 211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // lock, because we already have it. 212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 2) callback_ has already been run via CallWhileLocked. In this case, 213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // there's no need to acquire the lock, because we don't touch any 214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // shared data. 215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (callback_) { 216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // If the callback was not run, we still need to have the lock when we 217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // destroy the callback in case it had a Resource bound to it. This 218d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // ensures that the Resource's destructor is invoked only with the lock 219d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // held. 220d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // 221d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Also: Resource and Var inherit RefCounted (not ThreadSafeRefCounted), 222d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // and these callbacks need to be usable on any thread. So we need to lock 223d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // when releasing the callback to avoid ref counting races. 224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ProxyAutoLock lock; 225d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) callback_.reset(); 226d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 227d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 22958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch private: 23058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> callback_; 23158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 23258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch // Used to ensure that the Callback is run and deleted on the same thread. 23358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch base::ThreadChecker thread_checker_; 23458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}; 23558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 23658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <typename P1> 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class RunWhileLockedHelper<void(P1)> { 23858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch public: 239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef base::Callback<void(P1)> CallbackType; 24058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch explicit RunWhileLockedHelper(const CallbackType& callback) 24158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch : callback_(new CallbackType(callback)) { 24258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyLock::AssertAcquired(); 24358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch thread_checker_.DetachFromThread(); 24458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 24558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch void CallWhileLocked(P1 p1) { 24658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 24758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyAutoLock lock; 24858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch { 24958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> temp_callback(callback_.Pass()); 25058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch temp_callback->Run(p1); 25158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 25258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ~RunWhileLockedHelper() { 254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 255d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (callback_) { 256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ProxyAutoLock lock; 257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) callback_.reset(); 258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 26158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch private: 26258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> callback_; 26358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch base::ThreadChecker thread_checker_; 26458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}; 26558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 26658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <typename P1, typename P2> 267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class RunWhileLockedHelper<void(P1, P2)> { 26858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch public: 269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef base::Callback<void(P1, P2)> CallbackType; 27058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch explicit RunWhileLockedHelper(const CallbackType& callback) 27158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch : callback_(new CallbackType(callback)) { 27258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyLock::AssertAcquired(); 27358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch thread_checker_.DetachFromThread(); 27458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 27558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch void CallWhileLocked(P1 p1, P2 p2) { 27658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 27758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyAutoLock lock; 27858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch { 27958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> temp_callback(callback_.Pass()); 28058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch temp_callback->Run(p1, p2); 28158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 28258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 283d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ~RunWhileLockedHelper() { 284d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 285d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (callback_) { 286d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ProxyAutoLock lock; 287d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) callback_.reset(); 288d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 289d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 29158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch private: 29258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> callback_; 29358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch base::ThreadChecker thread_checker_; 29458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}; 29558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 29658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <typename P1, typename P2, typename P3> 297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class RunWhileLockedHelper<void(P1, P2, P3)> { 29858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch public: 299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) typedef base::Callback<void(P1, P2, P3)> CallbackType; 30058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch explicit RunWhileLockedHelper(const CallbackType& callback) 30158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch : callback_(new CallbackType(callback)) { 30258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyLock::AssertAcquired(); 30358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch thread_checker_.DetachFromThread(); 30458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 30558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch void CallWhileLocked(P1 p1, P2 p2, P3 p3) { 30658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch DCHECK(thread_checker_.CalledOnValidThread()); 30758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch ProxyAutoLock lock; 30858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch { 30958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> temp_callback(callback_.Pass()); 31058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch temp_callback->Run(p1, p2, p3); 31158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 31258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch } 313d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ~RunWhileLockedHelper() { 314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 315d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (callback_) { 316d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ProxyAutoLock lock; 317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) callback_.reset(); 318d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 319d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 32158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch private: 32258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch scoped_ptr<CallbackType> callback_; 32358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch base::ThreadChecker thread_checker_; 32458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}; 32558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 32658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch} // namespace internal 32758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch 32858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// RunWhileLocked wraps the given Callback in a new Callback that, when invoked: 32958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 1) Locks the ProxyLock. 33058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 2) Runs the original Callback (forwarding arguments, if any). 33158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 3) Clears the original Callback (while the lock is held). 33258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 4) Unlocks the ProxyLock. 33358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// Note that it's important that the callback is cleared in step (3), in case 33458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// clearing the Callback causes a destructor (e.g., for a Resource) to run, 33558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// which should hold the ProxyLock to avoid data races. 33658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 33758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// This is for cases where you want to run a task or store a Callback, but you 33858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// want to ensure that the ProxyLock is acquired for the duration of the task 33958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// that the Callback runs. 34058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// EXAMPLE USAGE: 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetMainThreadMessageLoop()->PostDelayedTask( 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FROM_HERE, 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RunWhileLocked(base::Bind(&CallbackWrapper, callback, result)), 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// delay_in_ms); 34558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// 34658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// In normal usage like the above, this all should "just work". However, if you 34758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// do something unusual, you may get a runtime crash due to deadlock. Here are 34858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// the ways that the returned Callback must be used to avoid a deadlock: 34958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// (1) copied to another Callback. After that, the original callback can be 35058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// destroyed with or without the proxy lock acquired, while the newly assigned 35158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// callback has to conform to these same restrictions. Or 35258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// (2) run without proxy lock acquired (e.g., being posted to a MessageLoop 35358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// and run there). The callback must be destroyed on the same thread where it 35458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// was run (but can be destroyed with or without the proxy lock acquired). Or 35558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch// (3) destroyed without the proxy lock acquired. 35658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochtemplate <class FunctionType> 357a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)inline base::Callback<FunctionType> RunWhileLocked( 358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const base::Callback<FunctionType>& callback) { 35958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch internal::RunWhileLockedHelper<FunctionType>* helper = 36058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch new internal::RunWhileLockedHelper<FunctionType>(callback); 36158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch return base::Bind( 36258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch &internal::RunWhileLockedHelper<FunctionType>::CallWhileLocked, 36358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch base::Owned(helper)); 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ppapi 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // PPAPI_SHARED_IMPL_PROXY_LOCK_H_ 369