diff --git a/configure b/configure index 2c44090c3ca07d..6ee9b99a4111fa 100755 --- a/configure +++ b/configure @@ -664,7 +664,7 @@ def configure_v8(o): if options.shared_v8_libname: o['libraries'] += ['-l%s' % options.shared_v8_libname] elif options.shared_v8: - o['libraries'] += ['-lv8'] + o['libraries'] += ['-lv8', '-lv8_platform'] if options.shared_v8_includes: o['include_dirs'] += [options.shared_v8_includes] diff --git a/node.gyp b/node.gyp index bba8f562f5b6f2..c26d8ac75efb23 100644 --- a/node.gyp +++ b/node.gyp @@ -108,7 +108,6 @@ 'src/node_main.cc', 'src/node_os.cc', 'src/node_v8.cc', - 'src/node_v8_platform.cc', 'src/node_stat_watcher.cc', 'src/node_watchdog.cc', 'src/node_zlib.cc', @@ -312,7 +311,12 @@ 'deps/v8/include/v8.h', 'deps/v8/include/v8-debug.h', ], - 'dependencies': [ 'deps/v8/tools/gyp/v8.gyp:v8' ], + 'dependencies': [ + 'deps/v8/tools/gyp/v8.gyp:v8', + 'deps/v8/tools/gyp/v8.gyp:v8_libplatform', + ], + # libplatform/libplatform.h includes include/v8platform.h + 'include_dirs': [ 'deps/v8' ], }], [ 'node_shared_zlib=="false"', { diff --git a/src/node.cc b/src/node.cc index 02df0d8a5b25c3..716b9c1dbc4a66 100644 --- a/src/node.cc +++ b/src/node.cc @@ -5,7 +5,6 @@ #include "node_http_parser.h" #include "node_javascript.h" #include "node_version.h" -#include "node_v8_platform.h" #if defined HAVE_PERFCTR #include "node_counters.h" @@ -38,6 +37,7 @@ #include "string_bytes.h" #include "util.h" #include "uv.h" +#include "libplatform/libplatform.h" #include "v8-debug.h" #include "v8-profiler.h" #include "zlib.h" @@ -140,6 +140,7 @@ static bool debugger_running; static uv_async_t dispatch_debug_messages_async; static Isolate* node_isolate = nullptr; +static v8::Platform* default_platform; class ArrayBufferAllocator : public ArrayBuffer::Allocator { public: @@ -3824,8 +3825,11 @@ static void StartNodeInstance(void* arg) { bool more; do { + v8::platform::PumpMessageLoop(default_platform, isolate); more = uv_run(env->event_loop(), UV_RUN_ONCE); + if (more == false) { + v8::platform::PumpMessageLoop(default_platform, isolate); EmitBeforeExit(env); // Emit `beforeExit` if the loop became alive either after emitting @@ -3872,7 +3876,9 @@ int Start(int argc, char** argv) { V8::SetEntropySource(crypto::EntropySource); #endif - V8::InitializePlatform(new Platform(4)); + const int thread_pool_size = 4; + default_platform = v8::platform::CreateDefaultPlatform(thread_pool_size); + V8::InitializePlatform(default_platform); V8::Initialize(); int exit_code = 1; @@ -3889,6 +3895,9 @@ int Start(int argc, char** argv) { } V8::Dispose(); + delete default_platform; + default_platform = nullptr; + delete[] exec_argv; exec_argv = nullptr; diff --git a/src/node_v8_platform.cc b/src/node_v8_platform.cc deleted file mode 100644 index d2b5a6cd7ddd98..00000000000000 --- a/src/node_v8_platform.cc +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright Fedor Indutny and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "node_v8_platform.h" - -#include "node.h" -#include "util.h" -#include "util-inl.h" -#include "uv.h" -#include "v8-platform.h" - -namespace node { - -using v8::Task; -using v8::Isolate; - -// The last task to encounter before killing the worker -class StopTask : public Task { - public: - void Run() {} -}; - -static StopTask stop_task_; - - -Platform::Platform(unsigned int worker_count) : worker_count_(worker_count) { - workers_ = new uv_thread_t[worker_count_]; - - for (unsigned int i = 0; i < worker_count_; i++) { - int err; - - err = uv_thread_create(worker_at(i), WorkerBody, this); - CHECK_EQ(err, 0); - } -} - - -Platform::~Platform() { - // Push stop task - for (unsigned int i = 0; i < worker_count(); i++) - global_queue()->Push(&stop_task_); - - // And wait for workers to exit - for (unsigned int i = 0; i < worker_count(); i++) { - int err; - - err = uv_thread_join(worker_at(i)); - CHECK_EQ(err, 0); - } - delete[] workers_; -} - - -void Platform::CallOnBackgroundThread(Task* task, - ExpectedRuntime expected_runtime) { - global_queue()->Push(task); -} - - -void Platform::CallOnForegroundThread(Isolate* isolate, Task* task) { - // TODO(indutny): create per-isolate thread pool - global_queue()->Push(task); -} - - -double Platform::MonotonicallyIncreasingTime() { - // uv_hrtime() returns a uint64_t but doubles can only represent integrals up - // to 2^53 accurately. Take steps to prevent loss of precision on overflow. - const uint64_t timestamp = uv_hrtime(); - const uint64_t billion = 1000 * 1000 * 1000; - const uint64_t seconds = timestamp / billion; - const uint64_t nanoseconds = timestamp % billion; - return seconds + 1.0 / nanoseconds; -} - - -void Platform::WorkerBody(void* arg) { - Platform* p = static_cast(arg); - - for (;;) { - Task* task = p->global_queue()->Shift(); - if (task == &stop_task_) - break; - - task->Run(); - delete task; - } -} - - -TaskQueue::TaskQueue() : read_off_(0), write_off_(0) { - CHECK_EQ(0, uv_cond_init(&read_cond_)); - CHECK_EQ(0, uv_cond_init(&write_cond_)); - CHECK_EQ(0, uv_mutex_init(&mutex_)); -} - - -TaskQueue::~TaskQueue() { - uv_mutex_lock(&mutex_); - CHECK_EQ(read_off_, write_off_); - uv_mutex_unlock(&mutex_); - uv_cond_destroy(&read_cond_); - uv_cond_destroy(&write_cond_); - uv_mutex_destroy(&mutex_); -} - - -void TaskQueue::Push(Task* task) { - uv_mutex_lock(&mutex_); - - while (can_write() == false) - uv_cond_wait(&write_cond_, &mutex_); // Wait until there is a free slot. - - ring_[write_off_] = task; - write_off_ = next(write_off_); - uv_cond_signal(&read_cond_); - uv_mutex_unlock(&mutex_); -} - - -Task* TaskQueue::Shift() { - uv_mutex_lock(&mutex_); - - while (can_read() == false) - uv_cond_wait(&read_cond_, &mutex_); - - Task* task = ring_[read_off_]; - if (can_write() == false) - uv_cond_signal(&write_cond_); // Signal waiters that we freed up a slot. - read_off_ = next(read_off_); - uv_mutex_unlock(&mutex_); - - return task; -} - - -unsigned int TaskQueue::next(unsigned int n) { - return (n + 1) % ARRAY_SIZE(TaskQueue {}.ring_); -} - - -bool TaskQueue::can_read() const { - return read_off_ != write_off_; -} - - -// The read pointer chases the write pointer in the circular queue. -// This method checks that the write pointer hasn't advanced so much -// that it has gone full circle and caught up with the read pointer. -// -// can_write() returns false when there is an empty slot but the read pointer -// points to the first element and the write pointer to the last element. -// That should be rare enough that it is not worth the extra bookkeeping -// to work around that. It's not harmful either, just mildly inefficient. -bool TaskQueue::can_write() const { - return next(write_off_) != read_off_; -} - - -} // namespace node diff --git a/src/node_v8_platform.h b/src/node_v8_platform.h deleted file mode 100644 index 5bc9df9d9fa34a..00000000000000 --- a/src/node_v8_platform.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright Fedor Indutny and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -#ifndef SRC_NODE_V8_PLATFORM_H_ -#define SRC_NODE_V8_PLATFORM_H_ - -#include "uv.h" -#include "v8-platform.h" - -namespace node { - -class TaskQueue { - public: - TaskQueue(); - ~TaskQueue(); - - void Push(v8::Task* task); - v8::Task* Shift(); - - private: - static unsigned int next(unsigned int n); - bool can_read() const; - bool can_write() const; - uv_cond_t read_cond_; - uv_cond_t write_cond_; - uv_mutex_t mutex_; - unsigned int read_off_; - unsigned int write_off_; - v8::Task* ring_[1024]; -}; - -class Platform : public v8::Platform { - public: - explicit Platform(unsigned int worker_count); - virtual ~Platform() override; - - void CallOnBackgroundThread(v8::Task* task, - ExpectedRuntime expected_runtime) override; - void CallOnForegroundThread(v8::Isolate* isolate, v8::Task* task) override; - double MonotonicallyIncreasingTime() override; - - protected: - static void WorkerBody(void* arg); - - inline TaskQueue* global_queue() { return &global_queue_; } - inline uv_thread_t* worker_at(unsigned int index) { return &workers_[index]; } - inline unsigned int worker_count() const { return worker_count_; } - - uv_thread_t* workers_; - unsigned int worker_count_; - TaskQueue global_queue_; -}; - -} // namespace node - -#endif // SRC_NODE_V8_PLATFORM_H_