From 6d774d919fc81e3b1daa56c3ea8dce8d4ce5c21b Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Mon, 30 Dec 2024 15:58:09 -0300 Subject: [PATCH 1/4] src: use a default thread name for inspector This commit sets a default thread name whenever the inspector thread is created (InspectorIo) --- src/inspector_io.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/inspector_io.cc b/src/inspector_io.cc index 4e76e529fcf341..580d36e1777e11 100644 --- a/src/inspector_io.cc +++ b/src/inspector_io.cc @@ -283,6 +283,11 @@ void InspectorIo::ThreadMain(void* io) { } void InspectorIo::ThreadMain() { + int thread_name_error = uv_thread_setname("InspectorIo"); + if (!thread_name_error) [[unlikely]] { + per_process::Debug(node::DebugCategory::INSPECTOR_SERVER, + "Failed to set thread name for Inspector\n"); + } uv_loop_t loop; loop.data = nullptr; int err = uv_loop_init(&loop); From 7667e8f4b25dcaec00e161e38dd7aacf3fa62df1 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Mon, 30 Dec 2024 16:19:36 -0300 Subject: [PATCH 2/4] src: set worker thread name using worker.name Set the worker thread name using worker.name value and changing the default to "WorkerThread" --- doc/api/worker_threads.md | 13 ++++++++++--- lib/internal/worker.js | 2 +- src/node_worker.cc | 1 + test/parallel/test-trace-events-worker-metadata.js | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 4e63345d208493..da6883e9d4a4e0 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1229,9 +1229,16 @@ changes: used for generated code. * `stackSizeMb` {number} The default maximum stack size for the thread. Small values may lead to unusable Worker instances. **Default:** `4`. - * `name` {string} An optional `name` to be appended to the worker title - for debugging/identification purposes, making the final title as - `[worker ${id}] ${name}`. **Default:** `''`. + * `name` {string} An optional `name` to be replaced in the thread name + and to the worker title for debugging/identification purposes, + making the final title as `[worker ${id}] ${name}`. + This parameter has a maximum allowed size, depending on the operating + system. If the provided name exceeds the limit, it will be truncated + * Maximum sizes: + * Windows: 32,767 characters + * macOS: 64 characters + * Other systems: 16 characters + **Default:** `'WorkerThread'`. ### Event: `'error'` diff --git a/lib/internal/worker.js b/lib/internal/worker.js index e5a2cd06892c75..39ca1778c7ddf0 100644 --- a/lib/internal/worker.js +++ b/lib/internal/worker.js @@ -204,7 +204,7 @@ class Worker extends EventEmitter { options.env); } - let name = ''; + let name = 'WorkerThread'; if (options.name) { validateString(options.name, 'options.name'); name = StringPrototypeTrim(options.name); diff --git a/src/node_worker.cc b/src/node_worker.cc index 1fc3774948dae3..edb43bc796c320 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -740,6 +740,7 @@ void Worker::StartThread(const FunctionCallbackInfo& args) { Worker* w = static_cast(arg); const uintptr_t stack_top = reinterpret_cast(&arg); + uv_thread_setname(w->name_.c_str()); // Leave a few kilobytes just to make sure we're within limits and have // some space to do work in C++ land. w->stack_base_ = stack_top - (w->stack_size_ - kStackBufferSize); diff --git a/test/parallel/test-trace-events-worker-metadata.js b/test/parallel/test-trace-events-worker-metadata.js index 6a8702ccadbc7b..844b3769ce201c 100644 --- a/test/parallel/test-trace-events-worker-metadata.js +++ b/test/parallel/test-trace-events-worker-metadata.js @@ -23,7 +23,7 @@ if (isMainThread) { assert(traces.length > 0); assert(traces.some((trace) => trace.cat === '__metadata' && trace.name === 'thread_name' && - trace.args.name === '[worker 1]')); + trace.args.name === '[worker 1] WorkerThread')); })); })); } else { From f62cfd68a438a8e0e41f0b387f13286ca0f3716c Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Tue, 31 Dec 2024 15:52:30 -0300 Subject: [PATCH 3/4] src: set thread name for main thread and v8 worker --- src/node.cc | 1 + src/node_platform.cc | 1 + test/addons/uv-thread-name/binding.cc | 29 +++++++++++++++++++++ test/addons/uv-thread-name/binding.gyp | 9 +++++++ test/addons/uv-thread-name/test.js | 35 ++++++++++++++++++++++++++ 5 files changed, 75 insertions(+) create mode 100644 test/addons/uv-thread-name/binding.cc create mode 100644 test/addons/uv-thread-name/binding.gyp create mode 100644 test/addons/uv-thread-name/test.js diff --git a/src/node.cc b/src/node.cc index 480681d0b02ff8..6b5ae7f7e455f8 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1165,6 +1165,7 @@ InitializeOncePerProcessInternal(const std::vector& args, } if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) { + uv_thread_setname("MainThread"); per_process::v8_platform.Initialize( static_cast(per_process::cli_options->v8_thread_pool_size)); result->platform_ = per_process::v8_platform.Platform(); diff --git a/src/node_platform.cc b/src/node_platform.cc index c042bae4e082cf..3d1cc522db380b 100644 --- a/src/node_platform.cc +++ b/src/node_platform.cc @@ -25,6 +25,7 @@ struct PlatformWorkerData { }; static void PlatformWorkerThread(void* data) { + uv_thread_setname("V8Worker"); std::unique_ptr worker_data(static_cast(data)); diff --git a/test/addons/uv-thread-name/binding.cc b/test/addons/uv-thread-name/binding.cc new file mode 100644 index 00000000000000..e09cc7ff176833 --- /dev/null +++ b/test/addons/uv-thread-name/binding.cc @@ -0,0 +1,29 @@ +#include +#include +#include + +using v8::FunctionCallbackInfo; +using v8::Isolate; +using v8::String; +using v8::Value; + +void GetThreadName(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + uv_thread_t thread; + char thread_name[16]; +#ifdef _WIN32 + /* uv_thread_self isn't defined for the main thread on Windows. */ + thread = GetCurrentThread(); +#else + thread = uv_thread_self(); +#endif + uv_thread_getname(&thread, thread_name, sizeof(thread_name)); + args.GetReturnValue().Set( + String::NewFromUtf8(isolate, thread_name).ToLocalChecked()); +} + +void init(v8::Local exports) { + NODE_SET_METHOD(exports, "getThreadName", GetThreadName); +} + +NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, init) diff --git a/test/addons/uv-thread-name/binding.gyp b/test/addons/uv-thread-name/binding.gyp new file mode 100644 index 00000000000000..55fbe7050f18e4 --- /dev/null +++ b/test/addons/uv-thread-name/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'includes': ['../common.gypi'], + } + ] +} diff --git a/test/addons/uv-thread-name/test.js b/test/addons/uv-thread-name/test.js new file mode 100644 index 00000000000000..f4ddefb55291f7 --- /dev/null +++ b/test/addons/uv-thread-name/test.js @@ -0,0 +1,35 @@ +'use strict'; +const common = require('../../common'); + +if (common.isAIX) { + common.skip('AIX is not supported by libuv'); +} + +const assert = require('node:assert'); +const { parentPort, Worker, isMainThread } = require('node:worker_threads'); +const bindingPath = require.resolve(`./build/${common.buildType}/binding`); +const binding = require(bindingPath); + +if (isMainThread) { + assert.strictEqual(binding.getThreadName(), 'MainThread'); + + const worker = new Worker(__filename); + worker.on('message', common.mustCall((data) => { + assert.strictEqual(data, 'WorkerThread'); + })); + worker.on('error', common.mustNotCall()); + worker.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); + + const namedWorker = new Worker(__filename, { name: 'NamedThread' }); + namedWorker.on('message', common.mustCall((data) => { + assert.strictEqual(data, 'NamedThread'); + })); + namedWorker.on('error', common.mustNotCall()); + namedWorker.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} else { + parentPort.postMessage(binding.getThreadName()); +} From 1a588ebf5834c36a17d24c130b88bb89b7d56eba Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Tue, 31 Dec 2024 15:55:58 -0300 Subject: [PATCH 4/4] src: set signal inspector io thread name --- doc/api/worker_threads.md | 4 +++- src/inspector_agent.cc | 1 + src/inspector_io.cc | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index da6883e9d4a4e0..45fe04d37fe823 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -1237,7 +1237,9 @@ changes: * Maximum sizes: * Windows: 32,767 characters * macOS: 64 characters - * Other systems: 16 characters + * Linux: 16 characters + * NetBSD: limited to `PTHREAD_MAX_NAMELEN_NP` + * FreeBSD and OpenBSD: limited to `MAXCOMLEN` **Default:** `'WorkerThread'`. ### Event: `'error'` diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index be767c1825d64f..f98060b59ba037 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -86,6 +86,7 @@ static void StartIoThreadWakeup(int signo, siginfo_t* info, void* ucontext) { } inline void* StartIoThreadMain(void* unused) { + uv_thread_setname("SignalInspector"); for (;;) { uv_sem_wait(&start_io_thread_semaphore); Mutex::ScopedLock lock(start_io_thread_async_mutex); diff --git a/src/inspector_io.cc b/src/inspector_io.cc index 580d36e1777e11..b338d45a795c15 100644 --- a/src/inspector_io.cc +++ b/src/inspector_io.cc @@ -286,7 +286,7 @@ void InspectorIo::ThreadMain() { int thread_name_error = uv_thread_setname("InspectorIo"); if (!thread_name_error) [[unlikely]] { per_process::Debug(node::DebugCategory::INSPECTOR_SERVER, - "Failed to set thread name for Inspector\n"); + "Failed to set thread name for Inspector\n"); } uv_loop_t loop; loop.data = nullptr;