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