src: make implementing CancelPendingDelayedTasks for platform optional

Fold `CancelPendingDelayedTasks()` into `UnregisterIsolate()` and
make implementing it optional.

It makes sense for these two operations to happen at the same time,
so it is sufficient to provide a single operation instead of two
separate ones.

PR-URL: https://github.com/nodejs/node/pull/30034
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Shelley Vohr <codebytere@gmail.com>
pull/30069/head
Anna Henningsen 2019-10-19 02:24:06 +02:00 committed by Rich Trott
parent 45efe67a84
commit 2dc70657a3
6 changed files with 38 additions and 31 deletions

View File

@ -260,7 +260,11 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
// flushing. // flushing.
virtual bool FlushForegroundTasks(v8::Isolate* isolate) = 0; virtual bool FlushForegroundTasks(v8::Isolate* isolate) = 0;
virtual void DrainTasks(v8::Isolate* isolate) = 0; virtual void DrainTasks(v8::Isolate* isolate) = 0;
virtual void CancelPendingDelayedTasks(v8::Isolate* isolate) = 0;
// TODO(addaleax): Remove this, it is unnecessary.
// This would currently be called before `UnregisterIsolate()` but will be
// folded into it in the future.
virtual void CancelPendingDelayedTasks(v8::Isolate* isolate);
// This needs to be called between the calls to `Isolate::Allocate()` and // This needs to be called between the calls to `Isolate::Allocate()` and
// `Isolate::Initialize()`, so that initialization can already start // `Isolate::Initialize()`, so that initialization can already start
@ -270,7 +274,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
virtual void RegisterIsolate(v8::Isolate* isolate, virtual void RegisterIsolate(v8::Isolate* isolate,
struct uv_loop_s* loop) = 0; struct uv_loop_s* loop) = 0;
// This needs to be called right before calling `Isolate::Dispose()`. // This needs to be called right before calling `Isolate::Dispose()`.
// This function may only be called once per `Isolate`. // This function may only be called once per `Isolate`, and discard any
// pending delayed tasks scheduled for that isolate.
virtual void UnregisterIsolate(v8::Isolate* isolate) = 0; virtual void UnregisterIsolate(v8::Isolate* isolate) = 0;
// The platform should call the passed function once all state associated // The platform should call the passed function once all state associated
// with the given isolate has been cleaned up. This can, but does not have to, // with the given isolate has been cleaned up. This can, but does not have to,

View File

@ -155,7 +155,6 @@ int NodeMainInstance::Run() {
RunAtExit(env.get()); RunAtExit(env.get());
per_process::v8_platform.DrainVMTasks(isolate_); per_process::v8_platform.DrainVMTasks(isolate_);
per_process::v8_platform.CancelVMTasks(isolate_);
#if defined(LEAK_SANITIZER) #if defined(LEAK_SANITIZER)
__lsan_do_leak_check(); __lsan_do_leak_check();

View File

@ -285,22 +285,33 @@ void PerIsolatePlatformData::Shutdown() {
// effectively deleting the tasks instead of running them. // effectively deleting the tasks instead of running them.
foreground_delayed_tasks_.PopAll(); foreground_delayed_tasks_.PopAll();
foreground_tasks_.PopAll(); foreground_tasks_.PopAll();
scheduled_delayed_tasks_.clear();
CancelPendingDelayedTasks(); // Both destroying the scheduled_delayed_tasks_ lists and closing
// flush_tasks_ handle add tasks to the event loop. We keep a count of all
ShutdownCbList* copy = new ShutdownCbList(std::move(shutdown_callbacks_)); // non-closed handles, and when that reaches zero, we inform any shutdown
flush_tasks_->data = copy; // callbacks that the platform is done as far as this Isolate is concerned.
self_reference_ = shared_from_this();
uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_), uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_),
[](uv_handle_t* handle) { [](uv_handle_t* handle) {
std::unique_ptr<ShutdownCbList> callbacks( std::unique_ptr<uv_async_t> flush_tasks {
static_cast<ShutdownCbList*>(handle->data)); reinterpret_cast<uv_async_t*>(handle) };
for (const auto& callback : *callbacks) PerIsolatePlatformData* platform_data =
callback.cb(callback.data); static_cast<PerIsolatePlatformData*>(flush_tasks->data);
delete reinterpret_cast<uv_async_t*>(handle); platform_data->DecreaseHandleCount();
platform_data->self_reference_.reset();
}); });
flush_tasks_ = nullptr; flush_tasks_ = nullptr;
} }
void PerIsolatePlatformData::DecreaseHandleCount() {
CHECK_GE(uv_handle_count_, 1);
if (--uv_handle_count_ == 0) {
for (const auto& callback : shutdown_callbacks_)
callback.cb(callback.data);
}
}
NodePlatform::NodePlatform(int thread_pool_size, NodePlatform::NodePlatform(int thread_pool_size,
TracingController* tracing_controller) { TracingController* tracing_controller) {
if (tracing_controller) { if (tracing_controller) {
@ -382,10 +393,6 @@ void PerIsolatePlatformData::RunForegroundTask(uv_timer_t* handle) {
delayed->platform_data->DeleteFromScheduledTasks(delayed); delayed->platform_data->DeleteFromScheduledTasks(delayed);
} }
void PerIsolatePlatformData::CancelPendingDelayedTasks() {
scheduled_delayed_tasks_.clear();
}
void NodePlatform::DrainTasks(Isolate* isolate) { void NodePlatform::DrainTasks(Isolate* isolate) {
std::shared_ptr<PerIsolatePlatformData> per_isolate = ForIsolate(isolate); std::shared_ptr<PerIsolatePlatformData> per_isolate = ForIsolate(isolate);
@ -409,12 +416,15 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
// the delay is non-zero. This should not be a problem in practice. // the delay is non-zero. This should not be a problem in practice.
uv_timer_start(&delayed->timer, RunForegroundTask, delay_millis, 0); uv_timer_start(&delayed->timer, RunForegroundTask, delay_millis, 0);
uv_unref(reinterpret_cast<uv_handle_t*>(&delayed->timer)); uv_unref(reinterpret_cast<uv_handle_t*>(&delayed->timer));
uv_handle_count_++;
scheduled_delayed_tasks_.emplace_back(delayed.release(), scheduled_delayed_tasks_.emplace_back(delayed.release(),
[](DelayedTask* delayed) { [](DelayedTask* delayed) {
uv_close(reinterpret_cast<uv_handle_t*>(&delayed->timer), uv_close(reinterpret_cast<uv_handle_t*>(&delayed->timer),
[](uv_handle_t* handle) { [](uv_handle_t* handle) {
delete static_cast<DelayedTask*>(handle->data); std::unique_ptr<DelayedTask> task {
static_cast<DelayedTask*>(handle->data) };
task->platform_data->DecreaseHandleCount();
}); });
}); });
} }
@ -454,10 +464,6 @@ bool NodePlatform::FlushForegroundTasks(Isolate* isolate) {
return ForIsolate(isolate)->FlushForegroundTasksInternal(); return ForIsolate(isolate)->FlushForegroundTasksInternal();
} }
void NodePlatform::CancelPendingDelayedTasks(Isolate* isolate) {
ForIsolate(isolate)->CancelPendingDelayedTasks();
}
bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; } bool NodePlatform::IdleTasksEnabled(Isolate* isolate) { return false; }
std::shared_ptr<v8::TaskRunner> std::shared_ptr<v8::TaskRunner>
@ -548,4 +554,6 @@ std::queue<std::unique_ptr<T>> TaskQueue<T>::PopAll() {
return result; return result;
} }
void MultiIsolatePlatform::CancelPendingDelayedTasks(Isolate* isolate) {}
} // namespace node } // namespace node

View File

@ -78,12 +78,12 @@ class PerIsolatePlatformData :
// posted during flushing of the queue are postponed until the next // posted during flushing of the queue are postponed until the next
// flushing. // flushing.
bool FlushForegroundTasksInternal(); bool FlushForegroundTasksInternal();
void CancelPendingDelayedTasks();
const uv_loop_t* event_loop() const { return loop_; } const uv_loop_t* event_loop() const { return loop_; }
private: private:
void DeleteFromScheduledTasks(DelayedTask* task); void DeleteFromScheduledTasks(DelayedTask* task);
void DecreaseHandleCount();
static void FlushTasks(uv_async_t* handle); static void FlushTasks(uv_async_t* handle);
static void RunForegroundTask(std::unique_ptr<v8::Task> task); static void RunForegroundTask(std::unique_ptr<v8::Task> task);
@ -95,6 +95,9 @@ class PerIsolatePlatformData :
}; };
typedef std::vector<ShutdownCallback> ShutdownCbList; typedef std::vector<ShutdownCallback> ShutdownCbList;
ShutdownCbList shutdown_callbacks_; ShutdownCbList shutdown_callbacks_;
// shared_ptr to self to keep this object alive during shutdown.
std::shared_ptr<PerIsolatePlatformData> self_reference_;
uint32_t uv_handle_count_ = 1; // 1 = flush_tasks_
uv_loop_t* const loop_; uv_loop_t* const loop_;
uv_async_t* flush_tasks_ = nullptr; uv_async_t* flush_tasks_ = nullptr;
@ -102,7 +105,7 @@ class PerIsolatePlatformData :
TaskQueue<DelayedTask> foreground_delayed_tasks_; TaskQueue<DelayedTask> foreground_delayed_tasks_;
// Use a custom deleter because libuv needs to close the handle first. // Use a custom deleter because libuv needs to close the handle first.
typedef std::unique_ptr<DelayedTask, std::function<void(DelayedTask*)>> typedef std::unique_ptr<DelayedTask, void(*)(DelayedTask*)>
DelayedTaskPointer; DelayedTaskPointer;
std::vector<DelayedTaskPointer> scheduled_delayed_tasks_; std::vector<DelayedTaskPointer> scheduled_delayed_tasks_;
}; };
@ -137,7 +140,6 @@ class NodePlatform : public MultiIsolatePlatform {
~NodePlatform() override = default; ~NodePlatform() override = default;
void DrainTasks(v8::Isolate* isolate) override; void DrainTasks(v8::Isolate* isolate) override;
void CancelPendingDelayedTasks(v8::Isolate* isolate) override;
void Shutdown(); void Shutdown();
// v8::Platform implementation. // v8::Platform implementation.

View File

@ -113,10 +113,6 @@ struct V8Platform {
platform_->DrainTasks(isolate); platform_->DrainTasks(isolate);
} }
inline void CancelVMTasks(v8::Isolate* isolate) {
platform_->CancelPendingDelayedTasks(isolate);
}
inline void StartTracingAgent() { inline void StartTracingAgent() {
// Attach a new NodeTraceWriter only if this function hasn't been called // Attach a new NodeTraceWriter only if this function hasn't been called
// before. // before.
@ -150,7 +146,6 @@ struct V8Platform {
inline void Initialize(int thread_pool_size) {} inline void Initialize(int thread_pool_size) {}
inline void Dispose() {} inline void Dispose() {}
inline void DrainVMTasks(v8::Isolate* isolate) {} inline void DrainVMTasks(v8::Isolate* isolate) {}
inline void CancelVMTasks(v8::Isolate* isolate) {}
inline void StartTracingAgent() { inline void StartTracingAgent() {
if (!per_process::cli_options->trace_event_categories.empty()) { if (!per_process::cli_options->trace_event_categories.empty()) {
fprintf(stderr, fprintf(stderr,

View File

@ -148,8 +148,6 @@ class WorkerThreadData {
w_->isolate_ = nullptr; w_->isolate_ = nullptr;
} }
w_->platform_->CancelPendingDelayedTasks(isolate);
bool platform_finished = false; bool platform_finished = false;
isolate_data_.reset(); isolate_data_.reset();