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   int value_;
     24 };
     25 
     26 int called_num = 0;
     27 
     28 void TestCallback_0() { ++called_num; }
     29 
     30 void TestCallback_1(int p1) { ++called_num; }
     31 
     32 void TestCallback_2(int p1, const double* p2) { ++called_num; }
     33 
     34 void TestCallback_3(int p1, const double* p2, bool* p3) { ++called_num; }
     35 
     36 void TestCallback_4(int p1, const double* p2, bool* p3, TestParameter p4) {
     37   ++called_num;
     38 }
     39 
     40 void TestCallback_5(int p1,
     41                     const double* p2,
     42                     bool* p3,
     43                     TestParameter p4,
     44                     const TestParameter& p5) {
     45   ++called_num;
     46 }
     47 
     48 typedef 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.
     52 class 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.
    100 class 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 
    149 TEST_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 
    195 TEST_F(ThreadAwareCallbackMultiThreadTest, RunOnTargetThread) { RunTest(); }
    196 
    197 TEST_F(ThreadAwareCallbackAbortTest, NotRunIfAborted) { RunTest(); }
    198 
    199 }  // namespace ppapi
    200