70222a9d03
Follow-up to https://chromium-review.googlesource.com/c/v8/v8/+/941442. "background" refers to a priority and is inappropriate to refer to worker threads as many tasks posted to worker threads by v8 are in fact high priority. Also took advantage of this rename to make NumberOfWorkerThreads() return an int instead of size_t. While it is never negative, int is simpler and Google C++ style guide states to avoid unsigned integers in such cases (ref. "On Unsigned Integers" @ https://google.github.io/styleguide/cppguide.html#Integer_Types). The Chromium embedder for that call provided an int which was converted to size_t for this override and most often casted back down to int on the v8 side, adding churn, and readability overhead. R=ahaas@chromium.org Bug: v8:7310 Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng Change-Id: Ib5280df73d2846b111d985be65a10b049995ea6a Reviewed-on: https://chromium-review.googlesource.com/941944 Commit-Queue: Gabriel Charette <gab@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#51662}
323 lines
9.2 KiB
C++
323 lines
9.2 KiB
C++
// Copyright 2014 the V8 project 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 "src/libplatform/default-platform.h"
|
|
#include "src/base/platform/semaphore.h"
|
|
#include "src/base/platform/time.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
|
|
using testing::InSequence;
|
|
using testing::StrictMock;
|
|
|
|
namespace v8 {
|
|
namespace platform {
|
|
namespace default_platform_unittest {
|
|
|
|
namespace {
|
|
|
|
struct MockTask : public Task {
|
|
virtual ~MockTask() { Die(); }
|
|
MOCK_METHOD0(Run, void());
|
|
MOCK_METHOD0(Die, void());
|
|
};
|
|
|
|
struct MockIdleTask : public IdleTask {
|
|
virtual ~MockIdleTask() { Die(); }
|
|
MOCK_METHOD1(Run, void(double deadline_in_seconds));
|
|
MOCK_METHOD0(Die, void());
|
|
};
|
|
|
|
class DefaultPlatformWithMockTime : public DefaultPlatform {
|
|
public:
|
|
DefaultPlatformWithMockTime()
|
|
: DefaultPlatform(IdleTaskSupport::kEnabled, nullptr) {
|
|
mock_time_ = 0.0;
|
|
SetTimeFunctionForTesting([]() { return mock_time_; });
|
|
}
|
|
void IncreaseTime(double seconds) { mock_time_ += seconds; }
|
|
|
|
private:
|
|
static double mock_time_;
|
|
};
|
|
|
|
double DefaultPlatformWithMockTime::mock_time_ = 0.0;
|
|
|
|
} // namespace
|
|
|
|
|
|
TEST(DefaultPlatformTest, PumpMessageLoop) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatform platform;
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
StrictMock<MockTask>* task = new StrictMock<MockTask>;
|
|
platform.CallOnForegroundThread(isolate, task);
|
|
EXPECT_CALL(*task, Run());
|
|
EXPECT_CALL(*task, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PumpMessageLoopWithTaskRunner) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatform platform;
|
|
std::shared_ptr<TaskRunner> taskrunner =
|
|
platform.GetForegroundTaskRunner(isolate);
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
StrictMock<MockTask>* task = new StrictMock<MockTask>;
|
|
taskrunner->PostTask(std::unique_ptr<Task>(task));
|
|
EXPECT_CALL(*task, Run());
|
|
EXPECT_CALL(*task, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PumpMessageLoopDelayed) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
|
|
StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
|
|
platform.CallDelayedOnForegroundThread(isolate, task2, 100);
|
|
platform.CallDelayedOnForegroundThread(isolate, task1, 10);
|
|
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
platform.IncreaseTime(11);
|
|
EXPECT_CALL(*task1, Run());
|
|
EXPECT_CALL(*task1, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
platform.IncreaseTime(90);
|
|
EXPECT_CALL(*task2, Run());
|
|
EXPECT_CALL(*task2, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PumpMessageLoopDelayedWithTaskRunner) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
std::shared_ptr<TaskRunner> taskrunner =
|
|
platform.GetForegroundTaskRunner(isolate);
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
|
|
StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
|
|
taskrunner->PostDelayedTask(std::unique_ptr<Task>(task2), 100);
|
|
taskrunner->PostDelayedTask(std::unique_ptr<Task>(task1), 10);
|
|
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
platform.IncreaseTime(11);
|
|
EXPECT_CALL(*task1, Run());
|
|
EXPECT_CALL(*task1, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
platform.IncreaseTime(90);
|
|
EXPECT_CALL(*task2, Run());
|
|
EXPECT_CALL(*task2, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PumpMessageLoopNoStarvation) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
EXPECT_FALSE(platform.PumpMessageLoop(isolate));
|
|
|
|
StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
|
|
StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
|
|
StrictMock<MockTask>* task3 = new StrictMock<MockTask>;
|
|
platform.CallOnForegroundThread(isolate, task1);
|
|
platform.CallDelayedOnForegroundThread(isolate, task2, 10);
|
|
platform.IncreaseTime(11);
|
|
|
|
EXPECT_CALL(*task1, Run());
|
|
EXPECT_CALL(*task1, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
|
|
platform.CallOnForegroundThread(isolate, task3);
|
|
|
|
EXPECT_CALL(*task2, Run());
|
|
EXPECT_CALL(*task2, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
EXPECT_CALL(*task3, Run());
|
|
EXPECT_CALL(*task3, Die());
|
|
EXPECT_TRUE(platform.PumpMessageLoop(isolate));
|
|
}
|
|
|
|
|
|
TEST(DefaultPlatformTest, PendingDelayedTasksAreDestroyedOnShutdown) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
{
|
|
DefaultPlatformWithMockTime platform;
|
|
StrictMock<MockTask>* task = new StrictMock<MockTask>;
|
|
platform.CallDelayedOnForegroundThread(isolate, task, 10);
|
|
EXPECT_CALL(*task, Die());
|
|
}
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, RunIdleTasks) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
|
|
StrictMock<MockIdleTask>* task = new StrictMock<MockIdleTask>;
|
|
platform.CallIdleOnForegroundThread(isolate, task);
|
|
EXPECT_CALL(*task, Run(42.0 + 23.0));
|
|
EXPECT_CALL(*task, Die());
|
|
platform.IncreaseTime(23.0);
|
|
platform.RunIdleTasks(isolate, 42.0);
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, RunIdleTasksWithTaskRunner) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
std::shared_ptr<TaskRunner> taskrunner =
|
|
platform.GetForegroundTaskRunner(isolate);
|
|
|
|
StrictMock<MockIdleTask>* task = new StrictMock<MockIdleTask>;
|
|
taskrunner->PostIdleTask(std::unique_ptr<IdleTask>(task));
|
|
EXPECT_CALL(*task, Run(42.0 + 23.0));
|
|
EXPECT_CALL(*task, Die());
|
|
platform.IncreaseTime(23.0);
|
|
platform.RunIdleTasks(isolate, 42.0);
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PendingIdleTasksAreDestroyedOnShutdown) {
|
|
InSequence s;
|
|
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
{
|
|
DefaultPlatformWithMockTime platform;
|
|
StrictMock<MockIdleTask>* task = new StrictMock<MockIdleTask>;
|
|
platform.CallIdleOnForegroundThread(isolate, task);
|
|
EXPECT_CALL(*task, Die());
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
class TestBackgroundTask : public Task {
|
|
public:
|
|
explicit TestBackgroundTask(base::Semaphore* sem, bool* executed)
|
|
: sem_(sem), executed_(executed) {}
|
|
|
|
virtual ~TestBackgroundTask() { Die(); }
|
|
MOCK_METHOD0(Die, void());
|
|
|
|
void Run() {
|
|
*executed_ = true;
|
|
sem_->Signal();
|
|
}
|
|
|
|
private:
|
|
base::Semaphore* sem_;
|
|
bool* executed_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST(DefaultPlatformTest, RunBackgroundTask) {
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatform platform;
|
|
platform.SetThreadPoolSize(1);
|
|
std::shared_ptr<TaskRunner> taskrunner =
|
|
platform.GetWorkerThreadsTaskRunner(isolate);
|
|
|
|
base::Semaphore sem(0);
|
|
bool task_executed = false;
|
|
StrictMock<TestBackgroundTask>* task =
|
|
new StrictMock<TestBackgroundTask>(&sem, &task_executed);
|
|
EXPECT_CALL(*task, Die());
|
|
taskrunner->PostTask(std::unique_ptr<Task>(task));
|
|
EXPECT_TRUE(sem.WaitFor(base::TimeDelta::FromSeconds(1)));
|
|
EXPECT_TRUE(task_executed);
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, NoIdleTasksInBackground) {
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
DefaultPlatform platform;
|
|
platform.SetThreadPoolSize(1);
|
|
std::shared_ptr<TaskRunner> taskrunner =
|
|
platform.GetWorkerThreadsTaskRunner(isolate);
|
|
EXPECT_FALSE(taskrunner->IdleTasksEnabled());
|
|
}
|
|
|
|
TEST(DefaultPlatformTest, PostTaskAfterPlatformTermination) {
|
|
std::shared_ptr<TaskRunner> foreground_taskrunner;
|
|
std::shared_ptr<TaskRunner> background_taskrunner;
|
|
{
|
|
int dummy;
|
|
Isolate* isolate = reinterpret_cast<Isolate*>(&dummy);
|
|
|
|
DefaultPlatformWithMockTime platform;
|
|
platform.SetThreadPoolSize(1);
|
|
foreground_taskrunner = platform.GetForegroundTaskRunner(isolate);
|
|
background_taskrunner = platform.GetWorkerThreadsTaskRunner(isolate);
|
|
}
|
|
// It should still be possible to post tasks, even when the platform does not
|
|
// exist anymore.
|
|
StrictMock<MockTask>* task1 = new StrictMock<MockTask>;
|
|
EXPECT_CALL(*task1, Die());
|
|
foreground_taskrunner->PostTask(std::unique_ptr<Task>(task1));
|
|
|
|
StrictMock<MockTask>* task2 = new StrictMock<MockTask>;
|
|
EXPECT_CALL(*task2, Die());
|
|
foreground_taskrunner->PostDelayedTask(std::unique_ptr<Task>(task2), 10);
|
|
|
|
StrictMock<MockIdleTask>* task3 = new StrictMock<MockIdleTask>;
|
|
EXPECT_CALL(*task3, Die());
|
|
foreground_taskrunner->PostIdleTask(std::unique_ptr<IdleTask>(task3));
|
|
|
|
StrictMock<MockTask>* task4 = new StrictMock<MockTask>;
|
|
EXPECT_CALL(*task4, Die());
|
|
background_taskrunner->PostTask(std::unique_ptr<Task>(task4));
|
|
}
|
|
|
|
} // namespace default_platform_unittest
|
|
} // namespace platform
|
|
} // namespace v8
|