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