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/thread_aware_callback.h"
6
7#include "base/bind_helpers.h"
8#include "base/compiler_specific.h"
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "ppapi/c/pp_errors.h"
12#include "ppapi/proxy/ppapi_proxy_test.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15namespace ppapi {
16
17namespace {
18
19class TestParameter {
20 public:
21  TestParameter() : value_(0) {}
22
23  int value_;
24};
25
26int called_num = 0;
27
28void TestCallback_0() { ++called_num; }
29
30void TestCallback_1(int p1) { ++called_num; }
31
32void TestCallback_2(int p1, const double* p2) { ++called_num; }
33
34void TestCallback_3(int p1, const double* p2, bool* p3) { ++called_num; }
35
36void TestCallback_4(int p1, const double* p2, bool* p3, TestParameter p4) {
37  ++called_num;
38}
39
40void TestCallback_5(int p1,
41                    const double* p2,
42                    bool* p3,
43                    TestParameter p4,
44                    const TestParameter& p5) {
45  ++called_num;
46}
47
48typedef proxy::PluginProxyTest ThreadAwareCallbackTest;
49
50// Test that a callback created on the main thread will run on the main thread,
51// even when requested from a different thread.
52class ThreadAwareCallbackMultiThreadTest
53    : public proxy::PluginProxyMultiThreadTest {
54 public:
55  ThreadAwareCallbackMultiThreadTest() : main_thread_callback_called_(false) {}
56  virtual ~ThreadAwareCallbackMultiThreadTest() {
57    CHECK(main_thread_callback_called_);
58  }
59
60  // proxy::PluginProxyMultiThreadTest implementation.
61  virtual void SetUpTestOnMainThread() OVERRIDE {
62    ProxyAutoLock auto_lock;
63
64    main_thread_callback_.reset(
65        ThreadAwareCallback<CallbackFunc>::Create(&MainThreadCallbackBody));
66  }
67
68  virtual void SetUpTestOnSecondaryThread() OVERRIDE {
69    {
70      ProxyAutoLock auto_lock;
71      main_thread_callback_->RunOnTargetThread(this);
72    }
73
74    PostQuitForSecondaryThread();
75    PostQuitForMainThread();
76  }
77
78 private:
79  typedef void (*CallbackFunc)(ThreadAwareCallbackMultiThreadTest*);
80
81  static void MainThreadCallbackBody(ThreadAwareCallbackMultiThreadTest* thiz) {
82    thiz->CheckOnThread(MAIN_THREAD);
83    thiz->main_thread_callback_called_ = true;
84
85    {
86      ProxyAutoLock auto_lock;
87      // We have to destroy it prior to the PluginGlobals instance held by the
88      // base class. Otherwise it has a ref to Pepper message loop for the main
89      // thread and the PluginGlobals destructor will complain.
90      thiz->main_thread_callback_.reset(NULL);
91    }
92  }
93
94  scoped_ptr<ThreadAwareCallback<CallbackFunc> > main_thread_callback_;
95  bool main_thread_callback_called_;
96};
97
98// Test that when a ThreadAwareCallback instance is destroyed, pending tasks to
99// run the callback will be ignored.
100class ThreadAwareCallbackAbortTest : public proxy::PluginProxyMultiThreadTest {
101 public:
102  ThreadAwareCallbackAbortTest() {}
103  virtual ~ThreadAwareCallbackAbortTest() {}
104
105  // proxy::PluginProxyMultiThreadTest implementation.
106  virtual void SetUpTestOnMainThread() OVERRIDE {
107    ProxyAutoLock auto_lock;
108
109    main_thread_callback_.reset(
110        ThreadAwareCallback<CallbackFunc>::Create(&MainThreadCallbackBody));
111  }
112
113  virtual void SetUpTestOnSecondaryThread() OVERRIDE {
114    {
115      ProxyAutoLock auto_lock;
116      main_thread_message_loop_proxy_->PostTask(
117          FROM_HERE,
118          base::Bind(&ThreadAwareCallbackAbortTest::DeleteCallback,
119                     base::Unretained(this)));
120      // |main_thread_callback_| is still valid, even if DeleteCallback() can be
121      // called before this following statement. That is because |auto_lock| is
122      // still held by this method, which prevents DeleteCallback() from
123      // deleting the callback.
124      main_thread_callback_->RunOnTargetThread(this);
125    }
126
127    PostQuitForSecondaryThread();
128    PostQuitForMainThread();
129  }
130
131 private:
132  typedef void (*CallbackFunc)(ThreadAwareCallbackAbortTest*);
133
134  static void MainThreadCallbackBody(ThreadAwareCallbackAbortTest* thiz) {
135    // The callback should not be called.
136    ASSERT_TRUE(false);
137  }
138
139  void DeleteCallback() {
140    ProxyAutoLock auto_lock;
141    main_thread_callback_.reset(NULL);
142  }
143
144  scoped_ptr<ThreadAwareCallback<CallbackFunc> > main_thread_callback_;
145};
146
147}  // namespace
148
149TEST_F(ThreadAwareCallbackTest, Basics) {
150  // ThreadAwareCallback should only be used when the proxy lock has been
151  // acquired.
152  ProxyAutoLock auto_lock;
153
154  double double_arg = 0.0;
155  bool bool_arg = false;
156  TestParameter object_arg;
157
158  // Exercise all the template code.
159  called_num = 0;
160  typedef void (*FuncType_0)();
161  scoped_ptr<ThreadAwareCallback<FuncType_0> > callback_0(
162      ThreadAwareCallback<FuncType_0>::Create(TestCallback_0));
163  callback_0->RunOnTargetThread();
164
165  typedef void (*FuncType_1)(int);
166  scoped_ptr<ThreadAwareCallback<FuncType_1> > callback_1(
167      ThreadAwareCallback<FuncType_1>::Create(TestCallback_1));
168  callback_1->RunOnTargetThread(1);
169
170  typedef void (*FuncType_2)(int, const double*);
171  scoped_ptr<ThreadAwareCallback<FuncType_2> > callback_2(
172      ThreadAwareCallback<FuncType_2>::Create(TestCallback_2));
173  callback_2->RunOnTargetThread(1, &double_arg);
174
175  typedef void (*FuncType_3)(int, const double*, bool*);
176  scoped_ptr<ThreadAwareCallback<FuncType_3> > callback_3(
177      ThreadAwareCallback<FuncType_3>::Create(TestCallback_3));
178  callback_3->RunOnTargetThread(1, &double_arg, &bool_arg);
179
180  typedef void (*FuncType_4)(int, const double*, bool*, TestParameter);
181  scoped_ptr<ThreadAwareCallback<FuncType_4> > callback_4(
182      ThreadAwareCallback<FuncType_4>::Create(TestCallback_4));
183  callback_4->RunOnTargetThread(1, &double_arg, &bool_arg, object_arg);
184
185  typedef void (*FuncType_5)(
186      int, const double*, bool*, TestParameter, const TestParameter&);
187  scoped_ptr<ThreadAwareCallback<FuncType_5> > callback_5(
188      ThreadAwareCallback<FuncType_5>::Create(TestCallback_5));
189  callback_5->RunOnTargetThread(
190      1, &double_arg, &bool_arg, object_arg, object_arg);
191
192  EXPECT_EQ(6, called_num);
193}
194
195TEST_F(ThreadAwareCallbackMultiThreadTest, RunOnTargetThread) { RunTest(); }
196
197TEST_F(ThreadAwareCallbackAbortTest, NotRunIfAborted) { RunTest(); }
198
199}  // namespace ppapi
200