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