• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()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
Acquire()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
Release()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
AssertAcquired()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
DisableLocking()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
DisableLockingOnThreadForTest()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
EnableLockingOnThreadForTest()90 void ProxyLock::EnableLockingOnThreadForTest() {
91   g_disable_locking_for_thread.Get().Set(false);
92 }
93 
CallWhileUnlocked(const base::Closure & closure)94 void CallWhileUnlocked(const base::Closure& closure) {
95   ProxyAutoUnlock lock;
96   closure.Run();
97 }
98 
99 }  // namespace ppapi
100