普通文本  |  180行  |  4.09 KB

// Copyright (c) 2013 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 <string>

#include "base/bind.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/test_globals.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ppapi {

namespace {

bool expect_to_be_locked = false;
void CheckLockState() {
  if (expect_to_be_locked) {
    ProxyLock::AssertAcquired();
  } else {
    // If we expect to be unlocked, try to lock. We rely on the checking inside
    // base::Lock that prevents recursive locking.
    ProxyAutoLock lock;
  }
}

int called_num = 0;

class CheckLockStateInDestructor
    : public base::RefCounted<CheckLockStateInDestructor> {
 public:
  CheckLockStateInDestructor() {}
  void Method() { ++called_num; }

 private:
  friend class base::RefCounted<CheckLockStateInDestructor>;
  ~CheckLockStateInDestructor() { CheckLockState(); }
  DISALLOW_COPY_AND_ASSIGN(CheckLockStateInDestructor);
};

void TestCallback_0() {
  CheckLockState();
  ++called_num;
}

void TestCallback_1(int p1) {
  CheckLockState();
  ++called_num;
}

void TestCallback_2(int p1, const std::string& p2) {
  CheckLockState();
  ++called_num;
}

struct Param {};
void TestCallback_3(int p1, const std::string& p2, Param p3) {
  CheckLockState();
  ++called_num;
}

}  // namespace

TEST(PpapiProxyLockTest, Locking) {
  TestGlobals globals;
  expect_to_be_locked = true;

  base::Callback<void()> cb0;
  {
    ProxyAutoLock lock;
    cb0 = RunWhileLocked(base::Bind(TestCallback_0));
  }
  cb0.Run();
  ASSERT_EQ(1, called_num);
  called_num = 0;

  {
    ProxyAutoLock lock;
    cb0 = RunWhileLocked(base::Bind(TestCallback_1, 123));
  }
  cb0.Run();
  ASSERT_EQ(1, called_num);
  called_num = 0;

  {
    ProxyAutoLock lock;
    scoped_refptr<CheckLockStateInDestructor> object =
        new CheckLockStateInDestructor();
    cb0 =
        RunWhileLocked(base::Bind(&CheckLockStateInDestructor::Method, object));
    // Note after this scope, the Callback owns the only reference.
  }
  cb0.Run();
  ASSERT_EQ(1, called_num);
  called_num = 0;

  base::Callback<void(int)> cb1;
  {
    ProxyAutoLock lock;
    cb1 = RunWhileLocked(base::Bind(TestCallback_1));
  }
  cb1.Run(123);
  ASSERT_EQ(1, called_num);
  called_num = 0;

  base::Callback<void(int, const std::string&)> cb2;
  {
    ProxyAutoLock lock;
    cb2 = RunWhileLocked(base::Bind(TestCallback_2));
  }
  cb2.Run(123, std::string("yo"));
  ASSERT_EQ(1, called_num);
  called_num = 0;

  base::Callback<void(int, const std::string&, Param)> cb3;
  {
    ProxyAutoLock lock;
    cb3 = RunWhileLocked(base::Bind(TestCallback_3));
  }
  cb3.Run(123, std::string("yo"), Param());
  ASSERT_EQ(1, called_num);
  called_num = 0;

  base::Callback<void(const std::string&)> cb1_string;
  {
    ProxyAutoLock lock;
    cb1_string = RunWhileLocked(base::Bind(TestCallback_2, 123));
  }
  cb1_string.Run(std::string("yo"));
  ASSERT_EQ(1, called_num);
  called_num = 0;

  {
    ProxyAutoLock lock;
    cb0 = RunWhileLocked(base::Bind(TestCallback_2, 123, std::string("yo")));
  }
  cb0.Run();
  ASSERT_EQ(1, called_num);
  called_num = 0;
}

TEST(PpapiProxyLockTest, Unlocking) {
  TestGlobals globals;
  expect_to_be_locked = false;
  // These calls should all try to _unlock_, so we must be locked before
  // entering them.
  ProxyAutoLock auto_lock;

  {
    CallWhileUnlocked(TestCallback_0);
    ASSERT_EQ(1, called_num);
    called_num = 0;
  }
  {
    CallWhileUnlocked(TestCallback_1, 123);
    ASSERT_EQ(1, called_num);
    called_num = 0;
  }
  {
    // TODO(dmichael): Make const-ref arguments work properly with type
    // deduction.
    CallWhileUnlocked<void, int, const std::string&>(
        TestCallback_2, 123, std::string("yo"));
    ASSERT_EQ(1, called_num);
    called_num = 0;
  }
  {
    base::Callback<void()> callback(base::Bind(TestCallback_0));
    CallWhileUnlocked(callback);
    ASSERT_EQ(1, called_num);
    called_num = 0;
  }
}

}  // namespace ppapi