Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,7 @@
'test/cctest/test_base64.cc',
'test/cctest/test_node_postmortem_metadata.cc',
'test/cctest/test_environment.cc',
'test/cctest/test_platform.cc',
'test/cctest/test_util.cc',
'test/cctest/test_url.cc'
],
Expand Down
18 changes: 16 additions & 2 deletions src/node_platform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ void PerIsolatePlatformData::PostDelayedTask(
}

PerIsolatePlatformData::~PerIsolatePlatformData() {
FlushForegroundTasksInternal();
while (FlushForegroundTasksInternal()) {}
CancelPendingDelayedTasks();

uv_close(reinterpret_cast<uv_handle_t*>(flush_tasks_),
Expand Down Expand Up @@ -223,7 +223,13 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() {
});
});
}
while (std::unique_ptr<Task> task = foreground_tasks_.Pop()) {
// Move all foreground tasks into a separate queue and flush that queue.
// This way tasks that are posted while flushing the queue will be run on the
// next call of FlushForegroundTasksInternal.
std::queue<std::unique_ptr<Task>> tasks = foreground_tasks_.PopAll();
while (!tasks.empty()) {
std::unique_ptr<Task> task = std::move(tasks.front());
tasks.pop();
did_work = true;
RunForegroundTask(std::move(task));
}
Expand Down Expand Up @@ -348,4 +354,12 @@ void TaskQueue<T>::Stop() {
tasks_available_.Broadcast(scoped_lock);
}

template <class T>
std::queue<std::unique_ptr<T>> TaskQueue<T>::PopAll() {
Mutex::ScopedLock scoped_lock(lock_);
std::queue<std::unique_ptr<T>> result;
result.swap(task_queue_);
return result;
}

} // namespace node
3 changes: 3 additions & 0 deletions src/node_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class TaskQueue {
void Push(std::unique_ptr<T> task);
std::unique_ptr<T> Pop();
std::unique_ptr<T> BlockingPop();
std::queue<std::unique_ptr<T>> PopAll();
void NotifyOfCompletion();
void BlockingDrain();
void Stop();
Expand Down Expand Up @@ -66,6 +67,8 @@ class PerIsolatePlatformData :
int unref();

// Returns true iff work was dispatched or executed.
// New tasks that are posted during flushing of the queue are postponed until
// the next flushing.
bool FlushForegroundTasksInternal();
void CancelPendingDelayedTasks();

Expand Down
54 changes: 54 additions & 0 deletions test/cctest/test_platform.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "node_internals.h"
#include "libplatform/libplatform.h"

#include <string>
#include "gtest/gtest.h"
#include "node_test_fixture.h"

// This task increments the given run counter and reposts itself until the
// repost counter reaches zero.
class RepostingTask : public v8::Task {
public:
explicit RepostingTask(int repost_count,
int* run_count,
v8::Isolate* isolate,
node::NodePlatform* platform)
: repost_count_(repost_count),
run_count_(run_count),
isolate_(isolate),
platform_(platform) {}

// v8::Task implementation
void Run() final {
++*run_count_;
if (repost_count_ > 0) {
--repost_count_;
platform_->CallOnForegroundThread(isolate_,
new RepostingTask(repost_count_, run_count_, isolate_, platform_));
}
}

private:
int repost_count_;
int* run_count_;
v8::Isolate* isolate_;
node::NodePlatform* platform_;
};

class PlatformTest : public EnvironmentTestFixture {};

TEST_F(PlatformTest, SkipNewTasksInFlushForegroundTasks) {
v8::Isolate::Scope isolate_scope(isolate_);
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
Env env {handle_scope, argv};
int run_count = 0;
platform->CallOnForegroundThread(
isolate_, new RepostingTask(3, &run_count, isolate_, platform.get()));
platform->FlushForegroundTasks(isolate_);
EXPECT_EQ(1, run_count);
platform->FlushForegroundTasks(isolate_);
EXPECT_EQ(2, run_count);
platform->FlushForegroundTasks(isolate_);
EXPECT_EQ(3, run_count);
}