|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "ppapi/shared_impl/thread_aware_callback.h" | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/bind_helpers.h" | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/location.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/single_thread_task_runner.h" | 
|  | #include "ppapi/c/pp_errors.h" | 
|  | #include "ppapi/proxy/ppapi_proxy_test.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | namespace ppapi { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class TestParameter { | 
|  | public: | 
|  | TestParameter() : value_(0) {} | 
|  |  | 
|  | int value_; | 
|  | }; | 
|  |  | 
|  | int called_num = 0; | 
|  |  | 
|  | void TestCallback_0() { ++called_num; } | 
|  |  | 
|  | void TestCallback_1(int p1) { ++called_num; } | 
|  |  | 
|  | void TestCallback_2(int p1, const double* p2) { ++called_num; } | 
|  |  | 
|  | void TestCallback_3(int p1, const double* p2, bool* p3) { ++called_num; } | 
|  |  | 
|  | void TestCallback_4(int p1, const double* p2, bool* p3, TestParameter p4) { | 
|  | ++called_num; | 
|  | } | 
|  |  | 
|  | void TestCallback_5(int p1, | 
|  | const double* p2, | 
|  | bool* p3, | 
|  | TestParameter p4, | 
|  | const TestParameter& p5) { | 
|  | ++called_num; | 
|  | } | 
|  |  | 
|  | typedef proxy::PluginProxyTest ThreadAwareCallbackTest; | 
|  |  | 
|  | // Test that a callback created on the main thread will run on the main thread, | 
|  | // even when requested from a different thread. | 
|  | class ThreadAwareCallbackMultiThreadTest | 
|  | : public proxy::PluginProxyMultiThreadTest { | 
|  | public: | 
|  | ThreadAwareCallbackMultiThreadTest() : main_thread_callback_called_(false) {} | 
|  | ~ThreadAwareCallbackMultiThreadTest() override { | 
|  | CHECK(main_thread_callback_called_); | 
|  | } | 
|  |  | 
|  | // proxy::PluginProxyMultiThreadTest implementation. | 
|  | void SetUpTestOnMainThread() override { | 
|  | ProxyAutoLock auto_lock; | 
|  |  | 
|  | main_thread_callback_.reset( | 
|  | ThreadAwareCallback<CallbackFunc>::Create(&MainThreadCallbackBody)); | 
|  | } | 
|  |  | 
|  | void SetUpTestOnSecondaryThread() override { | 
|  | { | 
|  | ProxyAutoLock auto_lock; | 
|  | main_thread_callback_->RunOnTargetThread(this); | 
|  | } | 
|  |  | 
|  | PostQuitForSecondaryThread(); | 
|  | PostQuitForMainThread(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | typedef void (*CallbackFunc)(ThreadAwareCallbackMultiThreadTest*); | 
|  |  | 
|  | static void MainThreadCallbackBody(ThreadAwareCallbackMultiThreadTest* thiz) { | 
|  | thiz->CheckOnThread(MAIN_THREAD); | 
|  | thiz->main_thread_callback_called_ = true; | 
|  |  | 
|  | { | 
|  | ProxyAutoLock auto_lock; | 
|  | // We have to destroy it prior to the PluginGlobals instance held by the | 
|  | // base class. Otherwise it has a ref to Pepper message loop for the main | 
|  | // thread and the PluginGlobals destructor will complain. | 
|  | thiz->main_thread_callback_.reset(NULL); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<ThreadAwareCallback<CallbackFunc>> main_thread_callback_; | 
|  | bool main_thread_callback_called_; | 
|  | }; | 
|  |  | 
|  | // Test that when a ThreadAwareCallback instance is destroyed, pending tasks to | 
|  | // run the callback will be ignored. | 
|  | class ThreadAwareCallbackAbortTest : public proxy::PluginProxyMultiThreadTest { | 
|  | public: | 
|  | ThreadAwareCallbackAbortTest() {} | 
|  | ~ThreadAwareCallbackAbortTest() override {} | 
|  |  | 
|  | // proxy::PluginProxyMultiThreadTest implementation. | 
|  | void SetUpTestOnMainThread() override { | 
|  | ProxyAutoLock auto_lock; | 
|  |  | 
|  | main_thread_callback_.reset( | 
|  | ThreadAwareCallback<CallbackFunc>::Create(&MainThreadCallbackBody)); | 
|  | } | 
|  |  | 
|  | void SetUpTestOnSecondaryThread() override { | 
|  | { | 
|  | ProxyAutoLock auto_lock; | 
|  | main_thread_task_runner_->PostTask( | 
|  | FROM_HERE, | 
|  | base::BindOnce(&ThreadAwareCallbackAbortTest::DeleteCallback, | 
|  | base::Unretained(this))); | 
|  | // |main_thread_callback_| is still valid, even if DeleteCallback() can be | 
|  | // called before this following statement. That is because |auto_lock| is | 
|  | // still held by this method, which prevents DeleteCallback() from | 
|  | // deleting the callback. | 
|  | main_thread_callback_->RunOnTargetThread(this); | 
|  | } | 
|  |  | 
|  | PostQuitForSecondaryThread(); | 
|  | PostQuitForMainThread(); | 
|  | } | 
|  |  | 
|  | private: | 
|  | typedef void (*CallbackFunc)(ThreadAwareCallbackAbortTest*); | 
|  |  | 
|  | static void MainThreadCallbackBody(ThreadAwareCallbackAbortTest* thiz) { | 
|  | // The callback should not be called. | 
|  | ASSERT_TRUE(false); | 
|  | } | 
|  |  | 
|  | void DeleteCallback() { | 
|  | ProxyAutoLock auto_lock; | 
|  | main_thread_callback_.reset(NULL); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<ThreadAwareCallback<CallbackFunc>> main_thread_callback_; | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST_F(ThreadAwareCallbackTest, Basics) { | 
|  | // ThreadAwareCallback should only be used when the proxy lock has been | 
|  | // acquired. | 
|  | ProxyAutoLock auto_lock; | 
|  |  | 
|  | double double_arg = 0.0; | 
|  | bool bool_arg = false; | 
|  | TestParameter object_arg; | 
|  |  | 
|  | // Exercise all the template code. | 
|  | called_num = 0; | 
|  | typedef void (*FuncType_0)(); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_0>> callback_0( | 
|  | ThreadAwareCallback<FuncType_0>::Create(TestCallback_0)); | 
|  | callback_0->RunOnTargetThread(); | 
|  |  | 
|  | typedef void (*FuncType_1)(int); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_1>> callback_1( | 
|  | ThreadAwareCallback<FuncType_1>::Create(TestCallback_1)); | 
|  | callback_1->RunOnTargetThread(1); | 
|  |  | 
|  | typedef void (*FuncType_2)(int, const double*); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_2>> callback_2( | 
|  | ThreadAwareCallback<FuncType_2>::Create(TestCallback_2)); | 
|  | callback_2->RunOnTargetThread(1, &double_arg); | 
|  |  | 
|  | typedef void (*FuncType_3)(int, const double*, bool*); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_3>> callback_3( | 
|  | ThreadAwareCallback<FuncType_3>::Create(TestCallback_3)); | 
|  | callback_3->RunOnTargetThread(1, &double_arg, &bool_arg); | 
|  |  | 
|  | typedef void (*FuncType_4)(int, const double*, bool*, TestParameter); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_4>> callback_4( | 
|  | ThreadAwareCallback<FuncType_4>::Create(TestCallback_4)); | 
|  | callback_4->RunOnTargetThread(1, &double_arg, &bool_arg, object_arg); | 
|  |  | 
|  | typedef void (*FuncType_5)( | 
|  | int, const double*, bool*, TestParameter, const TestParameter&); | 
|  | std::unique_ptr<ThreadAwareCallback<FuncType_5>> callback_5( | 
|  | ThreadAwareCallback<FuncType_5>::Create(TestCallback_5)); | 
|  | callback_5->RunOnTargetThread( | 
|  | 1, &double_arg, &bool_arg, object_arg, object_arg); | 
|  |  | 
|  | EXPECT_EQ(6, called_num); | 
|  | } | 
|  |  | 
|  | TEST_F(ThreadAwareCallbackMultiThreadTest, RunOnTargetThread) { RunTest(); } | 
|  |  | 
|  | TEST_F(ThreadAwareCallbackAbortTest, NotRunIfAborted) { RunTest(); } | 
|  |  | 
|  | }  // namespace ppapi |