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 3 // found in the LICENSE file. 4 5 #include "ppapi/shared_impl/proxy_lock.h" 6 7 #include "base/lazy_instance.h" 8 #include "base/synchronization/lock.h" 9 #include "base/threading/thread_local.h" 10 #include "ppapi/shared_impl/ppapi_globals.h" 11 12 namespace ppapi { 13 14 base::LazyInstance<base::Lock>::Leaky g_proxy_lock = LAZY_INSTANCE_INITIALIZER; 15 16 bool g_disable_locking = false; 17 base::LazyInstance<base::ThreadLocalBoolean>::Leaky 18 g_disable_locking_for_thread = LAZY_INSTANCE_INITIALIZER; 19 20 // Simple single-thread deadlock detector for the proxy lock. 21 // |true| when the current thread has the lock. 22 base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_proxy_locked_on_thread = 23 LAZY_INSTANCE_INITIALIZER; 24 25 // static Get()26base::Lock* ProxyLock::Get() { 27 if (g_disable_locking || g_disable_locking_for_thread.Get().Get()) 28 return NULL; 29 return &g_proxy_lock.Get(); 30 } 31 32 // Functions below should only access the lock via Get to ensure that they don't 33 // try to use the lock on the host side of the proxy, where locking is 34 // unnecessary and wrong (because we haven't coded the host side to account for 35 // locking). 36 37 // static Acquire()38void ProxyLock::Acquire() { 39 base::Lock* lock = Get(); 40 if (lock) { 41 // This thread does not already hold the lock. 42 const bool deadlock = g_proxy_locked_on_thread.Get().Get(); 43 CHECK(!deadlock); 44 45 lock->Acquire(); 46 g_proxy_locked_on_thread.Get().Set(true); 47 } 48 } 49 50 // static Release()51void ProxyLock::Release() { 52 base::Lock* lock = Get(); 53 if (lock) { 54 // This thread currently holds the lock. 55 const bool locked = g_proxy_locked_on_thread.Get().Get(); 56 CHECK(locked); 57 58 g_proxy_locked_on_thread.Get().Set(false); 59 lock->Release(); 60 } 61 } 62 63 // static AssertAcquired()64void ProxyLock::AssertAcquired() { 65 base::Lock* lock = Get(); 66 if (lock) { 67 // This thread currently holds the lock. 68 const bool locked = g_proxy_locked_on_thread.Get().Get(); 69 CHECK(locked); 70 71 lock->AssertAcquired(); 72 } 73 } 74 75 // static DisableLocking()76void ProxyLock::DisableLocking() { 77 // Note, we don't DCHECK that this flag isn't already set, because multiple 78 // unit tests may run in succession and all set it. 79 g_disable_locking = true; 80 } 81 82 // static DisableLockingOnThreadForTest()83void ProxyLock::DisableLockingOnThreadForTest() { 84 // Note, we don't DCHECK that this flag isn't already set, because multiple 85 // unit tests may run in succession and all set it. 86 g_disable_locking_for_thread.Get().Set(true); 87 } 88 89 // static EnableLockingOnThreadForTest()90void ProxyLock::EnableLockingOnThreadForTest() { 91 g_disable_locking_for_thread.Get().Set(false); 92 } 93 CallWhileUnlocked(const base::Closure & closure)94void CallWhileUnlocked(const base::Closure& closure) { 95 ProxyAutoUnlock lock; 96 closure.Run(); 97 } 98 99 } // namespace ppapi 100