src: drop homegrown thread pool, use libplatform
authorBen Noordhuis <info@bnoordhuis.nl>
Thu, 2 Apr 2015 21:51:01 +0000 (23:51 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Fri, 3 Apr 2015 22:21:39 +0000 (00:21 +0200)
Drop the homegrown thread pool that was introduced in commit 50839a0
("v8_platform: provide default v8::Platform impl") and use one from
V8's libplatform library.  Performance is comparable and it removes
a few hundred lines of code.

The calls to v8::platform::PumpMessageLoop() are currently no-ops
because V8 does not (yet?) use v8::Platform::CallOnForegroundThread().

Packagers that link against a shared libv8 now also need to make
libv8_platform available.

PR-URL: https://github.com/iojs/io.js/pull/1329
Reviewed-By: Fedor Indutny <fedor@indutny.com>
configure
node.gyp
src/node.cc
src/node_v8_platform.cc [deleted file]
src/node_v8_platform.h [deleted file]

index 2c44090..6ee9b99 100755 (executable)
--- 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]
 
index bba8f56..c26d8ac 100644 (file)
--- a/node.gyp
+++ b/node.gyp
         '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',
             '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"', {
index 02df0d8..716b9c1 100644 (file)
@@ -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 (file)
index d2b5a6c..0000000
+++ /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<Platform*>(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 (file)
index 5bc9df9..0000000
+++ /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_