Home | History | Annotate | Download | only in shared_impl
      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