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
16namespace ppapi {
17
18namespace {
19
20bool expect_to_be_locked = false;
21void 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
31int called_num = 0;
32
33class CheckLockStateInDestructor
34    : public base::RefCounted<CheckLockStateInDestructor> {
35 public:
36  CheckLockStateInDestructor() {}
37  void Method() { ++called_num; }
38
39 private:
40  friend class base::RefCounted<CheckLockStateInDestructor>;
41  ~CheckLockStateInDestructor() { CheckLockState(); }
42  DISALLOW_COPY_AND_ASSIGN(CheckLockStateInDestructor);
43};
44
45void TestCallback_0() {
46  CheckLockState();
47  ++called_num;
48}
49
50void TestCallback_1(int p1) {
51  CheckLockState();
52  ++called_num;
53}
54
55void TestCallback_2(int p1, const std::string& p2) {
56  CheckLockState();
57  ++called_num;
58}
59
60struct Param {};
61void TestCallback_3(int p1, const std::string& p2, Param p3) {
62  CheckLockState();
63  ++called_num;
64}
65
66}  // namespace
67
68TEST(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
146TEST(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