| // 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. |
| |
| #include "ppapi/shared_impl/proxy_lock.h" |
| |
| #include "base/lazy_instance.h" |
| #include "base/synchronization/lock.h" |
| #include "base/threading/thread_local.h" |
| #include "ppapi/shared_impl/ppapi_globals.h" |
| |
| namespace ppapi { |
| |
| base::LazyInstance<base::Lock>::Leaky g_proxy_lock = LAZY_INSTANCE_INITIALIZER; |
| |
| bool g_disable_locking = false; |
| base::LazyInstance<base::ThreadLocalBoolean>::Leaky |
| g_disable_locking_for_thread = LAZY_INSTANCE_INITIALIZER; |
| |
| // Simple single-thread deadlock detector for the proxy lock. |
| // |true| when the current thread has the lock. |
| base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_proxy_locked_on_thread = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| // static |
| base::Lock* ProxyLock::Get() { |
| if (g_disable_locking || g_disable_locking_for_thread.Get().Get()) |
| return NULL; |
| return &g_proxy_lock.Get(); |
| } |
| |
| // Functions below should only access the lock via Get to ensure that they don't |
| // try to use the lock on the host side of the proxy, where locking is |
| // unnecessary and wrong (because we haven't coded the host side to account for |
| // locking). |
| |
| // static |
| void ProxyLock::Acquire() { |
| base::Lock* lock = Get(); |
| if (lock) { |
| // This thread does not already hold the lock. |
| const bool deadlock = g_proxy_locked_on_thread.Get().Get(); |
| CHECK(!deadlock); |
| |
| lock->Acquire(); |
| g_proxy_locked_on_thread.Get().Set(true); |
| } |
| } |
| |
| // static |
| void ProxyLock::Release() { |
| base::Lock* lock = Get(); |
| if (lock) { |
| // This thread currently holds the lock. |
| const bool locked = g_proxy_locked_on_thread.Get().Get(); |
| CHECK(locked); |
| |
| g_proxy_locked_on_thread.Get().Set(false); |
| lock->Release(); |
| } |
| } |
| |
| // static |
| void ProxyLock::AssertAcquired() { |
| base::Lock* lock = Get(); |
| if (lock) { |
| // This thread currently holds the lock. |
| const bool locked = g_proxy_locked_on_thread.Get().Get(); |
| CHECK(locked); |
| |
| lock->AssertAcquired(); |
| } |
| } |
| |
| // static |
| void ProxyLock::DisableLocking() { |
| // Note, we don't DCHECK that this flag isn't already set, because multiple |
| // unit tests may run in succession and all set it. |
| g_disable_locking = true; |
| } |
| |
| // static |
| void ProxyLock::DisableLockingOnThreadForTest() { |
| // Note, we don't DCHECK that this flag isn't already set, because multiple |
| // unit tests may run in succession and all set it. |
| g_disable_locking_for_thread.Get().Set(true); |
| } |
| |
| // static |
| void ProxyLock::EnableLockingOnThreadForTest() { |
| g_disable_locking_for_thread.Get().Set(false); |
| } |
| |
| void CallWhileUnlocked(const base::Closure& closure) { |
| ProxyAutoUnlock lock; |
| closure.Run(); |
| } |
| |
| } // namespace ppapi |