1 // Copyright (c) 2013 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 <string>
6
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/compiler_specific.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "ppapi/shared_impl/proxy_lock.h"
13 #include "ppapi/shared_impl/test_globals.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace ppapi {
17
18 namespace {
19
20 bool expect_to_be_locked = false;
CheckLockState()21 void CheckLockState() {
22 if (expect_to_be_locked) {
23 ProxyLock::AssertAcquired();
24 } else {
25 // If we expect to be unlocked, try to lock. We rely on the checking inside
26 // base::Lock that prevents recursive locking.
27 ProxyAutoLock lock;
28 }
29 }
30
31 int called_num = 0;
32
33 class CheckLockStateInDestructor
34 : public base::RefCounted<CheckLockStateInDestructor> {
35 public:
CheckLockStateInDestructor()36 CheckLockStateInDestructor() {}
Method()37 void Method() { ++called_num; }
38
39 private:
40 friend class base::RefCounted<CheckLockStateInDestructor>;
~CheckLockStateInDestructor()41 ~CheckLockStateInDestructor() { CheckLockState(); }
42 DISALLOW_COPY_AND_ASSIGN(CheckLockStateInDestructor);
43 };
44
TestCallback_0()45 void TestCallback_0() {
46 CheckLockState();
47 ++called_num;
48 }
49
TestCallback_1(int p1)50 void TestCallback_1(int p1) {
51 CheckLockState();
52 ++called_num;
53 }
54
TestCallback_2(int p1,const std::string & p2)55 void TestCallback_2(int p1, const std::string& p2) {
56 CheckLockState();
57 ++called_num;
58 }
59
60 struct Param {};
TestCallback_3(int p1,const std::string & p2,Param p3)61 void TestCallback_3(int p1, const std::string& p2, Param p3) {
62 CheckLockState();
63 ++called_num;
64 }
65
66 } // namespace
67
TEST(PpapiProxyLockTest,Locking)68 TEST(PpapiProxyLockTest, Locking) {
69 TestGlobals globals;
70 expect_to_be_locked = true;
71
72 base::Callback<void()> cb0;
73 {
74 ProxyAutoLock lock;
75 cb0 = RunWhileLocked(base::Bind(TestCallback_0));
76 }
77 cb0.Run();
78 ASSERT_EQ(1, called_num);
79 called_num = 0;
80
81 {
82 ProxyAutoLock lock;
83 cb0 = RunWhileLocked(base::Bind(TestCallback_1, 123));
84 }
85 cb0.Run();
86 ASSERT_EQ(1, called_num);
87 called_num = 0;
88
89 {
90 ProxyAutoLock lock;
91 scoped_refptr<CheckLockStateInDestructor> object =
92 new CheckLockStateInDestructor();
93 cb0 =
94 RunWhileLocked(base::Bind(&CheckLockStateInDestructor::Method, object));
95 // Note after this scope, the Callback owns the only reference.
96 }
97 cb0.Run();
98 ASSERT_EQ(1, called_num);
99 called_num = 0;
100
101 base::Callback<void(int)> cb1;
102 {
103 ProxyAutoLock lock;
104 cb1 = RunWhileLocked(base::Bind(TestCallback_1));
105 }
106 cb1.Run(123);
107 ASSERT_EQ(1, called_num);
108 called_num = 0;
109
110 base::Callback<void(int, const std::string&)> cb2;
111 {
112 ProxyAutoLock lock;
113 cb2 = RunWhileLocked(base::Bind(TestCallback_2));
114 }
115 cb2.Run(123, std::string("yo"));
116 ASSERT_EQ(1, called_num);
117 called_num = 0;
118
119 base::Callback<void(int, const std::string&, Param)> cb3;
120 {
121 ProxyAutoLock lock;
122 cb3 = RunWhileLocked(base::Bind(TestCallback_3));
123 }
124 cb3.Run(123, std::string("yo"), Param());
125 ASSERT_EQ(1, called_num);
126 called_num = 0;
127
128 base::Callback<void(const std::string&)> cb1_string;
129 {
130 ProxyAutoLock lock;
131 cb1_string = RunWhileLocked(base::Bind(TestCallback_2, 123));
132 }
133 cb1_string.Run(std::string("yo"));
134 ASSERT_EQ(1, called_num);
135 called_num = 0;
136
137 {
138 ProxyAutoLock lock;
139 cb0 = RunWhileLocked(base::Bind(TestCallback_2, 123, std::string("yo")));
140 }
141 cb0.Run();
142 ASSERT_EQ(1, called_num);
143 called_num = 0;
144 }
145
TEST(PpapiProxyLockTest,Unlocking)146 TEST(PpapiProxyLockTest, Unlocking) {
147 TestGlobals globals;
148 expect_to_be_locked = false;
149 // These calls should all try to _unlock_, so we must be locked before
150 // entering them.
151 ProxyAutoLock auto_lock;
152
153 {
154 CallWhileUnlocked(TestCallback_0);
155 ASSERT_EQ(1, called_num);
156 called_num = 0;
157 }
158 {
159 CallWhileUnlocked(TestCallback_1, 123);
160 ASSERT_EQ(1, called_num);
161 called_num = 0;
162 }
163 {
164 // TODO(dmichael): Make const-ref arguments work properly with type
165 // deduction.
166 CallWhileUnlocked<void, int, const std::string&>(
167 TestCallback_2, 123, std::string("yo"));
168 ASSERT_EQ(1, called_num);
169 called_num = 0;
170 }
171 {
172 base::Callback<void()> callback(base::Bind(TestCallback_0));
173 CallWhileUnlocked(callback);
174 ASSERT_EQ(1, called_num);
175 called_num = 0;
176 }
177 }
178
179 } // namespace ppapi
180