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 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
     26 base::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
     38 void 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
     51 void 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
     64 void 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
     76 void 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
     83 void 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
     90 void ProxyLock::EnableLockingOnThreadForTest() {
     91   g_disable_locking_for_thread.Get().Set(false);
     92 }
     93 
     94 void CallWhileUnlocked(const base::Closure& closure) {
     95   ProxyAutoUnlock lock;
     96   closure.Run();
     97 }
     98 
     99 }  // namespace ppapi
    100