summaryrefslogtreecommitdiff
path: root/chromium/gin/v8_platform_unittest.cc
blob: 2bd442953eb81d5f2f0c2bc16fcc519d1af818f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gin/public/v8_platform.h"

#include <atomic>

#include "base/barrier_closure.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "base/test/test_waitable_event.h"
#include "base/trace_event/trace_event.h"
#include "testing/gtest/include/gtest/gtest.h"

class TestTraceStateObserver
    : public v8::TracingController::TraceStateObserver {
 public:
  void OnTraceEnabled() final { ++enabled_; }
  void OnTraceDisabled() final { ++disabled_; }
  int Enabled() { return enabled_; }
  int Disabled() { return disabled_; }

 private:
  int enabled_ = 0;
  int disabled_ = 0;
};

namespace gin {

TEST(V8PlatformTest, TraceStateObserverAPI) {
  TestTraceStateObserver test_observer;
  ASSERT_EQ(0, test_observer.Enabled());
  ASSERT_EQ(0, test_observer.Disabled());

  V8Platform::Get()->GetTracingController()->AddTraceStateObserver(
      &test_observer);
  base::trace_event::TraceLog::GetInstance()->SetEnabled(
      base::trace_event::TraceConfig("*", ""),
      base::trace_event::TraceLog::RECORDING_MODE);
  ASSERT_EQ(1, test_observer.Enabled());
  ASSERT_EQ(0, test_observer.Disabled());
  base::trace_event::TraceLog::GetInstance()->SetDisabled();
  ASSERT_EQ(1, test_observer.Enabled());
  ASSERT_EQ(1, test_observer.Disabled());

  V8Platform::Get()->GetTracingController()->RemoveTraceStateObserver(
      &test_observer);
  base::trace_event::TraceLog::GetInstance()->SetEnabled(
      base::trace_event::TraceConfig("*", ""),
      base::trace_event::TraceLog::RECORDING_MODE);
  base::trace_event::TraceLog::GetInstance()->SetDisabled();
  ASSERT_EQ(1, test_observer.Enabled());
  ASSERT_EQ(1, test_observer.Disabled());
}

TEST(V8PlatformTest, TraceStateObserverFired) {
  TestTraceStateObserver test_observer;
  ASSERT_EQ(0, test_observer.Enabled());
  ASSERT_EQ(0, test_observer.Disabled());

  base::trace_event::TraceLog::GetInstance()->SetEnabled(
      base::trace_event::TraceConfig("*", ""),
      base::trace_event::TraceLog::RECORDING_MODE);
  V8Platform::Get()->GetTracingController()->AddTraceStateObserver(
      &test_observer);
  ASSERT_EQ(1, test_observer.Enabled());
  ASSERT_EQ(0, test_observer.Disabled());
}

// Tests that PostJob runs a task and is done after Join.
TEST(V8PlatformTest, PostJobSimple) {
  base::test::TaskEnvironment task_environment;
  std::atomic_size_t num_tasks_to_run(4);
  class Task : public v8::JobTask {
   public:
    explicit Task(std::atomic_size_t* num_tasks_to_run)
        : num_tasks_to_run(num_tasks_to_run) {}
    void Run(v8::JobDelegate* delegate) override { --(*num_tasks_to_run); }

    size_t GetMaxConcurrency(size_t /* worker_count*/) const override {
      return *num_tasks_to_run;
    }

    raw_ptr<std::atomic_size_t> num_tasks_to_run;
  };
  auto handle =
      V8Platform::Get()->PostJob(v8::TaskPriority::kUserVisible,
                                 std::make_unique<Task>(&num_tasks_to_run));
  EXPECT_TRUE(handle->IsValid());
  handle->Join();
  EXPECT_FALSE(handle->IsValid());
  DCHECK_EQ(num_tasks_to_run, 0U);
}

// Tests that JobTask's lifetime is extended beyond job handle, until no
// references are left; and is gracefully destroyed.
TEST(V8PlatformTest, PostJobLifetime) {
  std::atomic_size_t num_tasks_to_run(4);

  base::TestWaitableEvent threads_running;
  base::TestWaitableEvent threads_continue;
  base::RepeatingClosure threads_running_barrier = base::BarrierClosure(
      num_tasks_to_run,
      BindOnce(&base::TestWaitableEvent::Signal, Unretained(&threads_running)));

  class Task : public v8::JobTask {
   public:
    explicit Task(std::atomic_size_t* num_tasks_to_run,
                  base::RepeatingClosure threads_running_barrier,
                  base::TestWaitableEvent* threads_continue)
        : num_tasks_to_run_(num_tasks_to_run),
          threads_running_barrier_(std::move(threads_running_barrier)),
          threads_continue_(threads_continue) {}
    ~Task() override {
      // This should only be destroyed once all workers returned.
      EXPECT_EQ(*num_tasks_to_run_, 0U);
    }

    void Run(v8::JobDelegate* delegate) override {
      threads_running_barrier_.Run();
      threads_continue_->Wait();
      --(*num_tasks_to_run_);
    }

    size_t GetMaxConcurrency(size_t /* worker_count*/) const override {
      return *num_tasks_to_run_;
    }

    raw_ptr<std::atomic_size_t> num_tasks_to_run_;
    base::RepeatingClosure threads_running_barrier_;
    raw_ptr<base::TestWaitableEvent> threads_continue_;
  };

  base::test::TaskEnvironment task_environment;

  auto handle = V8Platform::Get()->PostJob(
      v8::TaskPriority::kUserVisible,
      std::make_unique<Task>(&num_tasks_to_run,
                             std::move(threads_running_barrier),
                             &threads_continue));
  EXPECT_TRUE(handle->IsValid());
  threads_running.Wait();
  handle->CancelAndDetach();
  handle.reset();

  // Release workers and let the job get destroyed.
  threads_continue.Signal();
}

}  // namespace gin