Home | History | Annotate | Download | only in shared_impl
      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 
     15 namespace ppapi {
     16 
     17 namespace {
     18 
     19 class TestParameter {
     20  public:
     21   TestParameter() : value_(0) {
     22   }
     23 
     24   int value_;
     25 };
     26 
     27 int called_num = 0;
     28 
     29 void TestCallback_0() {
     30   ++called_num;
     31 }
     32 
     33 void TestCallback_1(int p1) {
     34   ++called_num;
     35 }
     36 
     37 void TestCallback_2(int p1, const double* p2) {
     38   ++called_num;
     39 }
     40 
     41 void TestCallback_3(int p1, const double* p2, bool* p3) {
     42   ++called_num;
     43 }
     44 
     45 void TestCallback_4(int p1, const double* p2, bool* p3, TestParameter p4) {
     46   ++called_num;
     47 }
     48 
     49 void TestCallback_5(int p1,
     50                     const double* p2,
     51                     bool* p3,
     52                     TestParameter p4,
     53                     const TestParameter& p5) {
     54   ++called_num;
     55 }
     56 
     57 typedef 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.
     61 class 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.
    110 class 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 
    161 TEST_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 
    210 TEST_F(ThreadAwareCallbackMultiThreadTest, RunOnTargetThread) {
    211   RunTest();
    212 }
    213 
    214 TEST_F(ThreadAwareCallbackAbortTest, NotRunIfAborted) {
    215   RunTest();
    216 }
    217 
    218 }  // namespace ppapi
    219