Commit f70c2d62 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[d8] Changes needed for testing Atomics.waitasync

Design doc:
https://docs.google.com/document/d/1BU-Zyco8YPP2Ra0Y3eVZ_BllzpUkJaJhmVmmnGD44Yc/edit#heading=h.mmdxlkic7kqd

Bug: v8:10239
Change-Id: Ie1b953c8242e32a0447440aaae7c2ed377c97511
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2259933
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarShu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68540}
parent bad4049c
......@@ -79,6 +79,17 @@ V8_PLATFORM_EXPORT void SetTracingController(
v8::Platform* platform,
v8::platform::tracing::TracingController* tracing_controller);
/**
* Notifies the given platform about the Isolate getting deleted soon. Has to be
* called for all Isolates which are deleted - unless we're shutting down the
* platform.
*
* The |platform| has to be created using |NewDefaultPlatform|.
*
*/
V8_PLATFORM_EXPORT void NotifyIsolateShutdown(v8::Platform* platform,
Isolate* isolate);
} // namespace platform
} // namespace v8
......
This diff is collapsed.
......@@ -25,6 +25,10 @@ namespace v8 {
class D8Console;
namespace internal {
class CancelableTaskManager;
}
// A single counter in a counter collection.
class Counter {
public:
......@@ -158,14 +162,14 @@ class SerializationDataQueue {
std::vector<std::unique_ptr<SerializationData>> data_;
};
class Worker {
class Worker : public std::enable_shared_from_this<Worker> {
public:
explicit Worker(const char* script);
~Worker();
// Post a message to the worker's incoming message queue. The worker will
// take ownership of the SerializationData.
// This function should only be called by the thread that created the Worker.
// Post a message to the worker. The worker will take ownership of the
// SerializationData. This function should only be called by the thread that
// created the Worker.
void PostMessage(std::unique_ptr<SerializationData> data);
// Synchronously retrieve messages from the worker's outgoing message queue.
// If there is no message in the queue, block until a message is available.
......@@ -185,6 +189,12 @@ class Worker {
static bool StartWorkerThread(std::shared_ptr<Worker> worker);
private:
friend class ProcessMessageTask;
friend class TerminateTask;
void ProcessMessage(std::unique_ptr<SerializationData> data);
void ProcessMessages();
class WorkerThread : public base::Thread {
public:
explicit WorkerThread(std::shared_ptr<Worker> worker)
......@@ -200,13 +210,25 @@ class Worker {
void ExecuteInThread();
static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
base::Semaphore in_semaphore_;
base::Semaphore out_semaphore_;
SerializationDataQueue in_queue_;
base::Semaphore out_semaphore_{0};
SerializationDataQueue out_queue_;
base::Thread* thread_;
base::Thread* thread_ = nullptr;
char* script_;
base::Atomic32 running_;
std::atomic<bool> running_;
// For signalling that the worker has started.
base::Semaphore started_semaphore_{0};
// For posting tasks to the worker
std::shared_ptr<TaskRunner> task_runner_;
i::CancelableTaskManager* task_manager_;
// Protects reading / writing task_runner_. (The TaskRunner itself doesn't
// need locking, but accessing the Worker's data member does.)
base::Mutex worker_mutex_;
// Only accessed by the worker thread.
Isolate* isolate_ = nullptr;
v8::Persistent<v8::Context> context_;
};
class PerIsolateData {
......
......@@ -53,13 +53,26 @@ double DefaultForegroundTaskRunner::MonotonicallyIncreasingTime() {
return time_function_();
}
void DefaultForegroundTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) {
void DefaultForegroundTaskRunner::PostDelayedTaskLocked(
std::unique_ptr<Task> task, double delay_in_seconds,
Nestability nestability, const base::MutexGuard&) {
DCHECK_GE(delay_in_seconds, 0.0);
base::MutexGuard guard(&lock_);
if (terminated_) return;
double deadline = MonotonicallyIncreasingTime() + delay_in_seconds;
delayed_task_queue_.push(std::make_pair(deadline, std::move(task)));
delayed_task_queue_.push({deadline, nestability, std::move(task)});
event_loop_control_.NotifyOne();
}
void DefaultForegroundTaskRunner::PostDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) {
base::MutexGuard guard(&lock_);
PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNestable, guard);
}
void DefaultForegroundTaskRunner::PostNonNestableDelayedTask(
std::unique_ptr<Task> task, double delay_in_seconds) {
base::MutexGuard guard(&lock_);
PostDelayedTaskLocked(std::move(task), delay_in_seconds, kNonNestable, guard);
}
void DefaultForegroundTaskRunner::PostIdleTask(std::unique_ptr<IdleTask> task) {
......@@ -91,19 +104,26 @@ bool DefaultForegroundTaskRunner::HasPoppableTaskInQueue() const {
return false;
}
void DefaultForegroundTaskRunner::MoveExpiredDelayedTasks(
const base::MutexGuard& guard) {
Nestability nestability;
std::unique_ptr<Task> task =
PopTaskFromDelayedQueueLocked(guard, &nestability);
while (task) {
PostTaskLocked(std::move(task), nestability, guard);
task = PopTaskFromDelayedQueueLocked(guard, &nestability);
}
}
std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
MessageLoopBehavior wait_for_work) {
base::MutexGuard guard(&lock_);
// Move delayed tasks that hit their deadline to the main queue.
std::unique_ptr<Task> task = PopTaskFromDelayedQueueLocked(guard);
while (task) {
PostTaskLocked(std::move(task), kNestable, guard);
task = PopTaskFromDelayedQueueLocked(guard);
}
MoveExpiredDelayedTasks(guard);
while (!HasPoppableTaskInQueue()) {
if (wait_for_work == MessageLoopBehavior::kDoNotWait) return {};
WaitForTaskLocked(guard);
MoveExpiredDelayedTasks(guard);
}
auto it = task_queue_.begin();
......@@ -113,7 +133,7 @@ std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
if (nesting_depth_ == 0 || it->first == kNestable) break;
}
DCHECK(it != task_queue_.end());
task = std::move(it->second);
std::unique_ptr<Task> task = std::move(it->second);
task_queue_.erase(it);
return task;
......@@ -121,22 +141,22 @@ std::unique_ptr<Task> DefaultForegroundTaskRunner::PopTaskFromQueue(
std::unique_ptr<Task>
DefaultForegroundTaskRunner::PopTaskFromDelayedQueueLocked(
const base::MutexGuard&) {
const base::MutexGuard&, Nestability* nestability) {
if (delayed_task_queue_.empty()) return {};
double now = MonotonicallyIncreasingTime();
const DelayedEntry& deadline_and_task = delayed_task_queue_.top();
if (deadline_and_task.first > now) return {};
const DelayedEntry& entry = delayed_task_queue_.top();
if (entry.timeout_time > now) return {};
// The const_cast here is necessary because there does not exist a clean way
// to get a unique_ptr out of the priority queue. We provide the priority
// queue with a custom comparison operator to make sure that the priority
// queue does not access the unique_ptr. Therefore it should be safe to reset
// the unique_ptr in the priority queue here. Note that the DelayedEntry is
// removed from the priority_queue immediately afterwards.
std::unique_ptr<Task> result =
std::move(const_cast<DelayedEntry&>(deadline_and_task).second);
std::unique_ptr<Task> task = std::move(const_cast<DelayedEntry&>(entry).task);
*nestability = entry.nestability;
delayed_task_queue_.pop();
return result;
return task;
}
std::unique_ptr<IdleTask> DefaultForegroundTaskRunner::PopTaskFromIdleQueue() {
......@@ -150,7 +170,20 @@ std::unique_ptr<IdleTask> DefaultForegroundTaskRunner::PopTaskFromIdleQueue() {
}
void DefaultForegroundTaskRunner::WaitForTaskLocked(const base::MutexGuard&) {
event_loop_control_.Wait(&lock_);
if (!delayed_task_queue_.empty()) {
double now = MonotonicallyIncreasingTime();
const DelayedEntry& entry = delayed_task_queue_.top();
double time_until_task = entry.timeout_time - now;
if (time_until_task > 0) {
bool woken_up = event_loop_control_.WaitFor(
&lock_,
base::TimeDelta::FromMicroseconds(
time_until_task * base::TimeConstants::kMicrosecondsPerSecond));
USE(woken_up);
}
} else {
event_loop_control_.Wait(&lock_);
}
}
} // namespace platform
......
......@@ -41,8 +41,6 @@ class V8_PLATFORM_EXPORT DefaultForegroundTaskRunner
std::unique_ptr<IdleTask> PopTaskFromIdleQueue();
void WaitForTaskLocked(const base::MutexGuard&);
double MonotonicallyIncreasingTime();
// v8::TaskRunner implementation.
......@@ -54,26 +52,41 @@ class V8_PLATFORM_EXPORT DefaultForegroundTaskRunner
bool IdleTasksEnabled() override;
void PostNonNestableTask(std::unique_ptr<Task> task) override;
void PostNonNestableDelayedTask(std::unique_ptr<Task> task,
double delay_in_seconds) override;
bool NonNestableTasksEnabled() const override;
private:
enum Nestability { kNestable, kNonNestable };
void WaitForTaskLocked(const base::MutexGuard&);
// The same as PostTask or PostNonNestableTask, but the lock is already held
// by the caller. The {guard} parameter should make sure that the caller is
// holding the lock.
void PostTaskLocked(std::unique_ptr<Task> task, Nestability nestability,
const base::MutexGuard&);
// The same as PostDelayedTask or PostNonNestableDelayedTask, but the lock is
// already held by the caller. The {guard} parameter should make sure that the
// caller is holding the lock.
void PostDelayedTaskLocked(std::unique_ptr<Task> task,
double delay_in_seconds, Nestability nestability,
const base::MutexGuard&);
// A caller of this function has to hold {lock_}. The {guard} parameter should
// make sure that the caller is holding the lock.
std::unique_ptr<Task> PopTaskFromDelayedQueueLocked(const base::MutexGuard&);
std::unique_ptr<Task> PopTaskFromDelayedQueueLocked(const base::MutexGuard&,
Nestability* nestability);
// A non-nestable task is poppable only if the task runner is not nested,
// i.e. if a task is not being run from within a task. A nestable task is
// always poppable.
bool HasPoppableTaskInQueue() const;
// Move delayed tasks that hit their deadline to the main queue.
void MoveExpiredDelayedTasks(const base::MutexGuard& guard);
bool terminated_ = false;
base::Mutex lock_;
base::ConditionVariable event_loop_control_;
......@@ -86,14 +99,19 @@ class V8_PLATFORM_EXPORT DefaultForegroundTaskRunner
std::queue<std::unique_ptr<IdleTask>> idle_task_queue_;
// Some helper constructs for the {delayed_task_queue_}.
using DelayedEntry = std::pair<double, std::unique_ptr<Task>>;
struct DelayedEntry {
double timeout_time;
Nestability nestability;
std::unique_ptr<Task> task;
};
// Define a comparison operator for the delayed_task_queue_ to make sure
// that the unique_ptr in the DelayedEntry is not accessed in the priority
// queue. This is necessary because we have to reset the unique_ptr when we
// remove a DelayedEntry from the priority queue.
struct DelayedEntryCompare {
bool operator()(const DelayedEntry& left, const DelayedEntry& right) const {
return left.first > right.first;
return left.timeout_time > right.timeout_time;
}
};
std::priority_queue<DelayedEntry, std::vector<DelayedEntry>,
......
......@@ -64,6 +64,10 @@ void SetTracingController(
std::unique_ptr<v8::TracingController>(tracing_controller));
}
void NotifyIsolateShutdown(v8::Platform* platform, Isolate* isolate) {
static_cast<DefaultPlatform*>(platform)->NotifyIsolateShutdown(isolate);
}
namespace {
constexpr int kMaxThreadPoolSize = 16;
......@@ -247,5 +251,14 @@ v8::PageAllocator* DefaultPlatform::GetPageAllocator() {
return page_allocator_.get();
}
void DefaultPlatform::NotifyIsolateShutdown(Isolate* isolate) {
base::MutexGuard guard(&lock_);
auto it = foreground_task_runner_map_.find(isolate);
if (it != foreground_task_runner_map_.end()) {
it->second->Terminate();
foreground_task_runner_map_.erase(it);
}
}
} // namespace platform
} // namespace v8
......@@ -66,6 +66,8 @@ class V8_PLATFORM_EXPORT DefaultPlatform : public NON_EXPORTED_BASE(Platform) {
StackTracePrinter GetStackTracePrinter() override;
v8::PageAllocator* GetPageAllocator() override;
void NotifyIsolateShutdown(Isolate* isolate);
private:
base::Mutex lock_;
const int thread_pool_size_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment