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.
5 #include "ppapi/shared_impl/thread_aware_callback.h"
7 #include "base/bind_helpers.h"
8 #include "base/compiler_specific.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/single_thread_task_runner.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/proxy/ppapi_proxy_test.h"
15 #include "testing/gtest/include/gtest/gtest.h"
23 TestParameter() : value_(0) {}
30 void TestCallback_0() { ++called_num
; }
32 void TestCallback_1(int p1
) { ++called_num
; }
34 void TestCallback_2(int p1
, const double* p2
) { ++called_num
; }
36 void TestCallback_3(int p1
, const double* p2
, bool* p3
) { ++called_num
; }
38 void TestCallback_4(int p1
, const double* p2
, bool* p3
, TestParameter p4
) {
42 void TestCallback_5(int p1
,
46 const TestParameter
& p5
) {
50 typedef proxy::PluginProxyTest ThreadAwareCallbackTest
;
52 // Test that a callback created on the main thread will run on the main thread,
53 // even when requested from a different thread.
54 class ThreadAwareCallbackMultiThreadTest
55 : public proxy::PluginProxyMultiThreadTest
{
57 ThreadAwareCallbackMultiThreadTest() : main_thread_callback_called_(false) {}
58 ~ThreadAwareCallbackMultiThreadTest() override
{
59 CHECK(main_thread_callback_called_
);
62 // proxy::PluginProxyMultiThreadTest implementation.
63 void SetUpTestOnMainThread() override
{
64 ProxyAutoLock auto_lock
;
66 main_thread_callback_
.reset(
67 ThreadAwareCallback
<CallbackFunc
>::Create(&MainThreadCallbackBody
));
70 void SetUpTestOnSecondaryThread() override
{
72 ProxyAutoLock auto_lock
;
73 main_thread_callback_
->RunOnTargetThread(this);
76 PostQuitForSecondaryThread();
77 PostQuitForMainThread();
81 typedef void (*CallbackFunc
)(ThreadAwareCallbackMultiThreadTest
*);
83 static void MainThreadCallbackBody(ThreadAwareCallbackMultiThreadTest
* thiz
) {
84 thiz
->CheckOnThread(MAIN_THREAD
);
85 thiz
->main_thread_callback_called_
= true;
88 ProxyAutoLock auto_lock
;
89 // We have to destroy it prior to the PluginGlobals instance held by the
90 // base class. Otherwise it has a ref to Pepper message loop for the main
91 // thread and the PluginGlobals destructor will complain.
92 thiz
->main_thread_callback_
.reset(NULL
);
96 scoped_ptr
<ThreadAwareCallback
<CallbackFunc
> > main_thread_callback_
;
97 bool main_thread_callback_called_
;
100 // Test that when a ThreadAwareCallback instance is destroyed, pending tasks to
101 // run the callback will be ignored.
102 class ThreadAwareCallbackAbortTest
: public proxy::PluginProxyMultiThreadTest
{
104 ThreadAwareCallbackAbortTest() {}
105 ~ThreadAwareCallbackAbortTest() override
{}
107 // proxy::PluginProxyMultiThreadTest implementation.
108 void SetUpTestOnMainThread() override
{
109 ProxyAutoLock auto_lock
;
111 main_thread_callback_
.reset(
112 ThreadAwareCallback
<CallbackFunc
>::Create(&MainThreadCallbackBody
));
115 void SetUpTestOnSecondaryThread() override
{
117 ProxyAutoLock auto_lock
;
118 main_thread_task_runner_
->PostTask(
119 FROM_HERE
, base::Bind(&ThreadAwareCallbackAbortTest::DeleteCallback
,
120 base::Unretained(this)));
121 // |main_thread_callback_| is still valid, even if DeleteCallback() can be
122 // called before this following statement. That is because |auto_lock| is
123 // still held by this method, which prevents DeleteCallback() from
124 // deleting the callback.
125 main_thread_callback_
->RunOnTargetThread(this);
128 PostQuitForSecondaryThread();
129 PostQuitForMainThread();
133 typedef void (*CallbackFunc
)(ThreadAwareCallbackAbortTest
*);
135 static void MainThreadCallbackBody(ThreadAwareCallbackAbortTest
* thiz
) {
136 // The callback should not be called.
140 void DeleteCallback() {
141 ProxyAutoLock auto_lock
;
142 main_thread_callback_
.reset(NULL
);
145 scoped_ptr
<ThreadAwareCallback
<CallbackFunc
> > main_thread_callback_
;
150 TEST_F(ThreadAwareCallbackTest
, Basics
) {
151 // ThreadAwareCallback should only be used when the proxy lock has been
153 ProxyAutoLock auto_lock
;
155 double double_arg
= 0.0;
156 bool bool_arg
= false;
157 TestParameter object_arg
;
159 // Exercise all the template code.
161 typedef void (*FuncType_0
)();
162 scoped_ptr
<ThreadAwareCallback
<FuncType_0
> > callback_0(
163 ThreadAwareCallback
<FuncType_0
>::Create(TestCallback_0
));
164 callback_0
->RunOnTargetThread();
166 typedef void (*FuncType_1
)(int);
167 scoped_ptr
<ThreadAwareCallback
<FuncType_1
> > callback_1(
168 ThreadAwareCallback
<FuncType_1
>::Create(TestCallback_1
));
169 callback_1
->RunOnTargetThread(1);
171 typedef void (*FuncType_2
)(int, const double*);
172 scoped_ptr
<ThreadAwareCallback
<FuncType_2
> > callback_2(
173 ThreadAwareCallback
<FuncType_2
>::Create(TestCallback_2
));
174 callback_2
->RunOnTargetThread(1, &double_arg
);
176 typedef void (*FuncType_3
)(int, const double*, bool*);
177 scoped_ptr
<ThreadAwareCallback
<FuncType_3
> > callback_3(
178 ThreadAwareCallback
<FuncType_3
>::Create(TestCallback_3
));
179 callback_3
->RunOnTargetThread(1, &double_arg
, &bool_arg
);
181 typedef void (*FuncType_4
)(int, const double*, bool*, TestParameter
);
182 scoped_ptr
<ThreadAwareCallback
<FuncType_4
> > callback_4(
183 ThreadAwareCallback
<FuncType_4
>::Create(TestCallback_4
));
184 callback_4
->RunOnTargetThread(1, &double_arg
, &bool_arg
, object_arg
);
186 typedef void (*FuncType_5
)(
187 int, const double*, bool*, TestParameter
, const TestParameter
&);
188 scoped_ptr
<ThreadAwareCallback
<FuncType_5
> > callback_5(
189 ThreadAwareCallback
<FuncType_5
>::Create(TestCallback_5
));
190 callback_5
->RunOnTargetThread(
191 1, &double_arg
, &bool_arg
, object_arg
, object_arg
);
193 EXPECT_EQ(6, called_num
);
196 TEST_F(ThreadAwareCallbackMultiThreadTest
, RunOnTargetThread
) { RunTest(); }
198 TEST_F(ThreadAwareCallbackAbortTest
, NotRunIfAborted
) { RunTest(); }