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() {
38 ++called_num;
39 }
40 private:
41 friend class base::RefCounted<CheckLockStateInDestructor>;
~CheckLockStateInDestructor()42 ~CheckLockStateInDestructor() {
43 CheckLockState();
44 }
45 DISALLOW_COPY_AND_ASSIGN(CheckLockStateInDestructor);
46 };
47
TestCallback_0()48 void TestCallback_0() {
49 CheckLockState();
50 ++called_num;
51 }
52
TestCallback_1(int p1)53 void TestCallback_1(int p1) {
54 CheckLockState();
55 ++called_num;
56 }
57
TestCallback_2(int p1,const std::string & p2)58 void TestCallback_2(int p1, const std::string& p2) {
59 CheckLockState();
60 ++called_num;
61 }
62
63 struct Param {};
TestCallback_3(int p1,const std::string & p2,Param p3)64 void TestCallback_3(int p1, const std::string& p2, Param p3) {
65 CheckLockState();
66 ++called_num;
67 }
68
69 } // namespace
70
TEST(PpapiProxyLockTest,Locking)71 TEST(PpapiProxyLockTest, Locking) {
72 TestGlobals globals;
73 expect_to_be_locked = true;
74
75 base::Callback<void()> cb0;
76 {
77 ProxyAutoLock lock;
78 cb0 = RunWhileLocked(base::Bind(TestCallback_0));
79 }
80 cb0.Run();
81 ASSERT_EQ(1, called_num);
82 called_num = 0;
83
84 {
85 ProxyAutoLock lock;
86 cb0 = RunWhileLocked(base::Bind(TestCallback_1, 123));
87 }
88 cb0.Run();
89 ASSERT_EQ(1, called_num);
90 called_num = 0;
91
92 {
93 ProxyAutoLock lock;
94 scoped_refptr<CheckLockStateInDestructor> object =
95 new CheckLockStateInDestructor();
96 cb0 = RunWhileLocked(
97 base::Bind(&CheckLockStateInDestructor::Method,
98 object));
99 // Note after this scope, the Callback owns the only reference.
100 }
101 cb0.Run();
102 ASSERT_EQ(1, called_num);
103 called_num = 0;
104
105 base::Callback<void(int)> cb1;
106 {
107 ProxyAutoLock lock;
108 cb1 = RunWhileLocked(base::Bind(TestCallback_1));
109 }
110 cb1.Run(123);
111 ASSERT_EQ(1, called_num);
112 called_num = 0;
113
114 base::Callback<void(int, const std::string&)> cb2;
115 {
116 ProxyAutoLock lock;
117 cb2 = RunWhileLocked(base::Bind(TestCallback_2));
118 }
119 cb2.Run(123, std::string("yo"));
120 ASSERT_EQ(1, called_num);
121 called_num = 0;
122
123 base::Callback<void(int, const std::string&, Param)> cb3;
124 {
125 ProxyAutoLock lock;
126 cb3 = RunWhileLocked(base::Bind(TestCallback_3));
127 }
128 cb3.Run(123, std::string("yo"), Param());
129 ASSERT_EQ(1, called_num);
130 called_num = 0;
131
132 base::Callback<void(const std::string&)> cb1_string;
133 {
134 ProxyAutoLock lock;
135 cb1_string = RunWhileLocked(base::Bind(TestCallback_2, 123));
136 }
137 cb1_string.Run(std::string("yo"));
138 ASSERT_EQ(1, called_num);
139 called_num = 0;
140
141 {
142 ProxyAutoLock lock;
143 cb0 = RunWhileLocked(base::Bind(TestCallback_2, 123, std::string("yo")));
144 }
145 cb0.Run();
146 ASSERT_EQ(1, called_num);
147 called_num = 0;
148 }
149
TEST(PpapiProxyLockTest,Unlocking)150 TEST(PpapiProxyLockTest, Unlocking) {
151 TestGlobals globals;
152 expect_to_be_locked = false;
153 // These calls should all try to _unlock_, so we must be locked before
154 // entering them.
155 ProxyAutoLock auto_lock;
156
157 {
158 CallWhileUnlocked(TestCallback_0);
159 ASSERT_EQ(1, called_num);
160 called_num = 0;
161 } {
162 CallWhileUnlocked(TestCallback_1, 123);
163 ASSERT_EQ(1, called_num);
164 called_num = 0;
165 } {
166 // TODO(dmichael): Make const-ref arguments work properly with type
167 // deduction.
168 CallWhileUnlocked<void, int, const std::string&>(
169 TestCallback_2, 123, std::string("yo"));
170 ASSERT_EQ(1, called_num);
171 called_num = 0;
172 } {
173 base::Callback<void()> callback(base::Bind(TestCallback_0));
174 CallWhileUnlocked(callback);
175 ASSERT_EQ(1, called_num);
176 called_num = 0;
177 }
178 }
179
180 } // namespace ppapi
181