diff --git a/agents/otlp/src/otlp_agent.cc b/agents/otlp/src/otlp_agent.cc index 1788aac5e20..3e9e244ba9c 100644 --- a/agents/otlp/src/otlp_agent.cc +++ b/agents/otlp/src/otlp_agent.cc @@ -422,7 +422,7 @@ void OTLPAgent::span_msg_cb_(nsuv::ns_async*, OTLPAgent* agent) { for (auto& item : agent->env_metrics_map_) { // Retrieve metrics from the Metrics API. Ignore any return error since // there's nothing to be done. - item.second.metrics_.Update(thr_metrics_cb_, agent); + item.second.metrics_->Update(thr_metrics_cb_, agent); } } @@ -435,12 +435,11 @@ void OTLPAgent::span_msg_cb_(nsuv::ns_async*, OTLPAgent* agent) { std::vector> thr_metrics_vector; - ThreadMetrics* m; - while (agent->thr_metrics_msg_q_.dequeue(&m)) { - auto it = agent->env_metrics_map_.find(m->thread_id()); + ThreadMetricsStor stor; + while (agent->thr_metrics_msg_q_.dequeue(stor)) { + auto it = agent->env_metrics_map_.find(stor.thread_id); if (it != agent->env_metrics_map_.end()) { auto& metrics = it->second; - ThreadMetricsStor stor = m->Get(); thr_metrics_vector.emplace_back(stor, metrics.prev_); metrics.prev_ = stor; } @@ -452,14 +451,14 @@ void OTLPAgent::span_msg_cb_(nsuv::ns_async*, OTLPAgent* agent) { } -/*static*/void OTLPAgent::thr_metrics_cb_(ThreadMetrics* metrics, +/*static*/void OTLPAgent::thr_metrics_cb_(SharedThreadMetrics metrics, OTLPAgent* agent) { nsuv::ns_rwlock::scoped_rdlock lock(exit_lock_); if (!is_running_) { return; } - agent->thr_metrics_msg_q_.enqueue(metrics); + agent->thr_metrics_msg_q_.enqueue(metrics->Get()); ASSERT_EQ(0, uv_async_send(&agent->metrics_msg_)); } diff --git a/agents/otlp/src/otlp_agent.h b/agents/otlp/src/otlp_agent.h index 33f369ecfa4..bf077c0dc4e 100644 --- a/agents/otlp/src/otlp_agent.h +++ b/agents/otlp/src/otlp_agent.h @@ -28,10 +28,11 @@ namespace nsolid { namespace otlp { struct JSThreadMetrics { - ThreadMetrics metrics_; + SharedThreadMetrics metrics_; ThreadMetrics::MetricsStor prev_; - explicit JSThreadMetrics(SharedEnvInst envinst): metrics_(envinst), - prev_() {} + explicit JSThreadMetrics(SharedEnvInst envinst) + : metrics_(ThreadMetrics::Create(envinst)), + prev_() {} }; class OTLPAgent { @@ -73,7 +74,7 @@ class OTLPAgent { static void metrics_msg_cb_(nsuv::ns_async*, OTLPAgent* agent); - static void thr_metrics_cb_(ThreadMetrics*, OTLPAgent*); + static void thr_metrics_cb_(SharedThreadMetrics, OTLPAgent*); void do_start(); @@ -132,7 +133,7 @@ class OTLPAgent { ProcessMetrics::MetricsStor proc_prev_stor_; std::map env_metrics_map_; nsuv::ns_async metrics_msg_; - TSQueue thr_metrics_msg_q_; + TSQueue thr_metrics_msg_q_; nsuv::ns_timer metrics_timer_; std::unique_ptr metrics_exporter_; diff --git a/agents/statsd/src/statsd_agent.cc b/agents/statsd/src/statsd_agent.cc index bfcf59c9a96..6ef388c8389 100644 --- a/agents/statsd/src/statsd_agent.cc +++ b/agents/statsd/src/statsd_agent.cc @@ -465,9 +465,7 @@ void StatsDAgent::env_msg_cb(nsuv::ns_async*, StatsDAgent* agent) { bool creation = std::get<1>(tup); if (creation) { auto pair = agent->env_metrics_map_.emplace( - std::piecewise_construct, - std::forward_as_tuple(GetThreadId(envinst)), - std::forward_as_tuple(envinst)); + GetThreadId(envinst), ThreadMetrics::Create(envinst)); ASSERT(pair.second); } else { ASSERT_EQ(1, agent->env_metrics_map_.erase(GetThreadId(envinst))); @@ -480,10 +478,8 @@ void StatsDAgent::shutdown_cb_(nsuv::ns_async*, StatsDAgent* agent) { } void StatsDAgent::metrics_msg_cb_(nsuv::ns_async*, StatsDAgent* agent) { - ThreadMetrics* m; - while (agent->metrics_msg_q_.dequeue(&m)) { - uint64_t thread_id = m->thread_id(); - ThreadMetrics::MetricsStor stor = m->Get(); + ThreadMetrics::MetricsStor stor; + while (agent->metrics_msg_q_.dequeue(stor)) { json body = { #define V(Type, CName, JSName, MType) \ { #JSName, stor.CName }, @@ -491,7 +487,7 @@ void StatsDAgent::metrics_msg_cb_(nsuv::ns_async*, StatsDAgent* agent) { #undef V }; - agent->send_metrics(body, thread_id, stor.thread_name.c_str()); + agent->send_metrics(body, stor.thread_id, stor.thread_name.c_str()); } } @@ -734,10 +730,10 @@ void StatsDAgent::metrics_timer_cb_(nsuv::ns_timer*, StatsDAgent* agent) { for (auto it = agent->env_metrics_map_.begin(); it != agent->env_metrics_map_.end(); ++it) { - ThreadMetrics& e_metrics = std::get<1>(*it); + SharedThreadMetrics& e_metrics = std::get<1>(*it); // Retrieve metrics from the Metrics API. Ignore any return error since // there's nothing to be done. - e_metrics.Update(env_metrics_cb_, agent); + e_metrics->Update(env_metrics_cb_, agent); } // Get and send proc metrics @@ -753,13 +749,14 @@ void StatsDAgent::metrics_timer_cb_(nsuv::ns_timer*, StatsDAgent* agent) { agent->send_metrics(body); } -void StatsDAgent::env_metrics_cb_(ThreadMetrics* metrics, StatsDAgent* agent) { +void StatsDAgent::env_metrics_cb_(SharedThreadMetrics metrics, + StatsDAgent* agent) { // Check if the agent is already closing if (agent->metrics_msg_.is_closing()) { return; } - agent->metrics_msg_q_.enqueue(metrics); + agent->metrics_msg_q_.enqueue(metrics->Get()); ASSERT_EQ(0, agent->metrics_msg_.send()); } diff --git a/agents/statsd/src/statsd_agent.h b/agents/statsd/src/statsd_agent.h index 5a314ad32ea..70d5fe385ea 100644 --- a/agents/statsd/src/statsd_agent.h +++ b/agents/statsd/src/statsd_agent.h @@ -204,7 +204,7 @@ class StatsDAgent { static void send_stats_msg_cb_(nsuv::ns_async*, StatsDAgent*); - static void env_metrics_cb_(ThreadMetrics*, StatsDAgent*); + static void env_metrics_cb_(SharedThreadMetrics, StatsDAgent*); static void status_command_cb_(SharedEnvInst, StatsDAgent*); @@ -258,11 +258,11 @@ class StatsDAgent { nsuv::ns_timer retry_timer_; // For the Metrics API - std::map env_metrics_map_; + std::map env_metrics_map_; ProcessMetrics proc_metrics_; uint64_t metrics_period_; nsuv::ns_async metrics_msg_; - TSQueue metrics_msg_q_; + TSQueue metrics_msg_q_; nsuv::ns_timer metrics_timer_; // For the Configuration API diff --git a/agents/zmq/src/zmq_agent.cc b/agents/zmq/src/zmq_agent.cc index 8989115448c..1da0502cbc4 100644 --- a/agents/zmq/src/zmq_agent.cc +++ b/agents/zmq/src/zmq_agent.cc @@ -881,18 +881,17 @@ void ZmqAgent::got_trace(Tracer* tracer, } -void ZmqAgent::got_env_metrics(ThreadMetrics* t_metrics) { +void ZmqAgent::got_env_metrics(const ThreadMetrics::MetricsStor& stor) { ProcessMetrics::MetricsStor proc_stor; - auto iter = env_metrics_map_.find(t_metrics->thread_id()); + auto iter = env_metrics_map_.find(stor.thread_id); if (iter != env_metrics_map_.end()) { - ASSERT_PTR_EQ(t_metrics, &iter->second.t_metrics); iter->second.fetching = false; // Store into the completed_env_metrics_ vector so we have easy access once // the metrics from all the threads are retrieved. Make a copy of // ThreadMetrics to make sure the metrics are still valid even if the // thread is gone. - completed_env_metrics_.push_back(t_metrics->Get()); + completed_env_metrics_.push_back(stor); } bool done = true; @@ -951,9 +950,9 @@ NSOLID_ENV_METRICS_STRINGS(V) void ZmqAgent::metrics_msg_cb(nsuv::ns_async*, ZmqAgent* agent) { - ThreadMetrics* metrics; - while (agent->metrics_msg_q_.dequeue(&metrics)) { - agent->got_env_metrics(metrics); + ThreadMetrics::MetricsStor stor; + while (agent->metrics_msg_q_.dequeue(stor)) { + agent->got_env_metrics(stor); } } @@ -1641,19 +1640,19 @@ void ZmqAgent::metrics_timer_cb(nsuv::ns_timer*, ZmqAgent* agent) { stor.fetching = false; // Retrieve metrics from the Metrics API. Ignore any return error since // there's nothing to be done. - int r = stor.t_metrics.Update(env_metrics_cb, agent); + int r = stor.t_metrics->Update(env_metrics_cb, agent); if (r == 0) stor.fetching = true; } } -void ZmqAgent::env_metrics_cb(ThreadMetrics* metrics, ZmqAgent* agent) { +void ZmqAgent::env_metrics_cb(SharedThreadMetrics metrics, ZmqAgent* agent) { // Check if the agent is already delete or it's closing if (!is_running || agent->metrics_msg_.is_closing()) { return; } - agent->metrics_msg_q_.enqueue(metrics); + agent->metrics_msg_q_.enqueue(metrics->Get()); ASSERT_EQ(0, agent->metrics_msg_.send()); } diff --git a/agents/zmq/src/zmq_agent.h b/agents/zmq/src/zmq_agent.h index ff219807ba2..2ece452254e 100644 --- a/agents/zmq/src/zmq_agent.h +++ b/agents/zmq/src/zmq_agent.h @@ -356,10 +356,12 @@ class ZmqAgent { }; struct EnvMetricsStor { - ThreadMetrics t_metrics; + SharedThreadMetrics t_metrics; bool fetching; - explicit EnvMetricsStor(SharedEnvInst envinst, bool f): t_metrics(envinst), - fetching(f) {} + NSOLID_DELETE_DEFAULT_CONSTRUCTORS(EnvMetricsStor) + explicit EnvMetricsStor(SharedEnvInst envinst, bool f) + : t_metrics(ThreadMetrics::Create(envinst)), + fetching(f) {} }; struct ZmqCommandError { @@ -478,7 +480,7 @@ class ZmqAgent { static void update_state_msg_cb(nsuv::ns_async*, ZmqAgent*); - static void env_metrics_cb(ThreadMetrics*, ZmqAgent*); + static void env_metrics_cb(SharedThreadMetrics, ZmqAgent*); static void status_command_cb(SharedEnvInst, ZmqAgent*); @@ -555,7 +557,7 @@ class ZmqAgent { const std::pair&, const std::pair&); - void got_env_metrics(ThreadMetrics* t_metrics); + void got_env_metrics(const ThreadMetrics::MetricsStor& stor); void got_heap_snapshot(int status, const std::string& snaphost, @@ -657,7 +659,7 @@ class ZmqAgent { ProcessMetrics proc_metrics_; uint64_t metrics_period_; nsuv::ns_async metrics_msg_; - TSQueue metrics_msg_q_; + TSQueue metrics_msg_q_; nsuv::ns_timer metrics_timer_; std::string cached_metrics_; std::set pending_metrics_reqs_; diff --git a/src/nsolid.cc b/src/nsolid.cc index 1ad216b8efa..305370abc33 100644 --- a/src/nsolid.cc +++ b/src/nsolid.cc @@ -260,7 +260,8 @@ int ProcessMetrics::Update() { ThreadMetrics::ThreadMetrics(SharedEnvInst envinst) - : thread_id_(envinst->thread_id()) { + : thread_id_(envinst->thread_id()), + user_data_(nullptr, nullptr) { CHECK_NOT_NULL(envinst.get()); CHECK_EQ(uv_mutex_init(&stor_lock_), 0); stor_.thread_id = thread_id_; @@ -275,7 +276,8 @@ ThreadMetrics::~ThreadMetrics() { ThreadMetrics::ThreadMetrics(uint64_t thread_id) - : thread_id_(thread_id) { + : thread_id_(thread_id), + user_data_(nullptr, nullptr) { CHECK_EQ(uv_mutex_init(&stor_lock_), 0); stor_.thread_id = thread_id_; stor_.prev_call_time_ = uv_hrtime(); @@ -283,6 +285,11 @@ ThreadMetrics::ThreadMetrics(uint64_t thread_id) } +SharedThreadMetrics ThreadMetrics::Create(SharedEnvInst envinst) { + return SharedThreadMetrics(new ThreadMetrics(envinst)); +} + + std::string ThreadMetrics::toJSON() { MetricsStor dup; std::string metrics_string; @@ -340,25 +347,76 @@ int ThreadMetrics::Update(v8::Isolate* isolate) { } -int ThreadMetrics::get_thread_metrics_() { +int ThreadMetrics::get_thread_metrics() { // Might need to fire myself for using nested lambdas. - void (*cb)(SharedEnvInst, ThreadMetrics*) = + auto cb = [](SharedEnvInst ei, ThreadMetrics* tm) { // This runs from the worker thread. - [](SharedEnvInst ei, ThreadMetrics* tm) { - void (*ret_proxy)(ThreadMetrics*) = - [](ThreadMetrics* tm) { - tm->proxy_(tm); - }; + auto ret_proxy = [](ThreadMetrics* tm) { + // This runs from the NSolid thread. + tm->proxy_(tm); + }; + + uv_mutex_lock(&tm->stor_lock_); + ei->GetThreadMetrics(&tm->stor_); + uv_mutex_unlock(&tm->stor_lock_); + + QueueCallback(ret_proxy, tm); + }; + + std::weak_ptr wp = weak_from_this(); + if (!wp.expired()) { + return UV_EINVAL; + } + + return RunCommand(GetEnvInst(thread_id_), + CommandType::Interrupt, + cb, + this); +} - uv_mutex_lock(&tm->stor_lock_); - ei->GetThreadMetrics(&tm->stor_); - uv_mutex_unlock(&tm->stor_lock_); +int ThreadMetrics::get_shared_thread_metrics() { + // Might need to fire myself for using nested lambdas. + auto cb = [](SharedEnvInst ei, std::weak_ptr wp) { + // This runs from the worker thread. + auto ret_proxy = [](std::weak_ptr wp) { // This runs from the NSolid thread. - QueueCallback(ret_proxy, tm); + SharedThreadMetrics tm_sp = wp.lock(); + if (tm_sp == nullptr) { + return; + } + + tm_sp->shared_proxy_(tm_sp); }; - return RunCommand(GetEnvInst(thread_id_), CommandType::Interrupt, cb, this); + SharedThreadMetrics tm_sp = wp.lock(); + if (tm_sp == nullptr) { + return; + } + + uv_mutex_lock(&tm_sp->stor_lock_); + ei->GetThreadMetrics(&tm_sp->stor_); + uv_mutex_unlock(&tm_sp->stor_lock_); + + QueueCallback(ret_proxy, tm_sp); + }; + + std::weak_ptr wp = weak_from_this(); + if (wp.expired()) { + return UV_EINVAL; + } + + return RunCommand(GetEnvInst(thread_id_), + CommandType::Interrupt, + cb, + wp); +} + + +void ThreadMetrics::reset() { + proxy_ = nullptr; + shared_proxy_ = nullptr; + update_running_ = false; } diff --git a/src/nsolid.h b/src/nsolid.h index 25411b66f18..878613f60c9 100644 --- a/src/nsolid.h +++ b/src/nsolid.h @@ -180,13 +180,12 @@ enum NSolidErr { #undef X }; - -class ProcessMetrics; class ThreadMetrics; enum class CommandType; using SharedEnvInst = std::shared_ptr; +using SharedThreadMetrics = std::shared_ptr; using ns_error_tp = std::tuple; /** @cond DONT_DOCUMENT */ @@ -601,9 +600,11 @@ class NODE_EXTERN ProcessMetrics { * @brief Class that allows to retrieve thread-specific metrics from a process. * */ -class NODE_EXTERN ThreadMetrics { +class NODE_EXTERN ThreadMetrics: + public std::enable_shared_from_this { public: using thread_metrics_proxy_sig = void(*)(ThreadMetrics*); + using shared_thread_metrics_proxy_sig = void(*)(SharedThreadMetrics); /** * @brief struct to store thread metrics data. @@ -624,13 +625,23 @@ class NODE_EXTERN ThreadMetrics { uint64_t current_hrtime_; }; + /** + * @brief Create a SharedThreadMetrics instance + * + * @param thread_id the id of the JS thread the metrics are going to be + * retrieved from. + */ + static SharedThreadMetrics Create(SharedEnvInst envinst); /** * @brief Construct a new Thread Metrics object * * @param thread_id the id of the JS thread the metrics are going to be * retrieved from. + * + * @deprecated since v5.x.x. Use ThreadMetrics::Create(envinst) instead. */ - explicit ThreadMetrics(SharedEnvInst envinst); + NODE_DEPRECATED("Use ThreadMetrics::Create(envinst)", + explicit ThreadMetrics(SharedEnvInst envinst)); ThreadMetrics() = delete; ThreadMetrics(const ThreadMetrics&) = delete; ThreadMetrics& operator=(const ThreadMetrics&) = delete; @@ -664,7 +675,11 @@ class NODE_EXTERN ThreadMetrics { * called when the retrieval has completed. * * @param cb callback function with the following signature - * `void(*)(ThreadMetrics*, ...Data)` + * `void(*)(SharedThreadMetrics, ...Data)`. Callbacks with signature + * `void(*)(ThreadMetrics*, ...Data)` are still supported for backwards + * compatibility but its use is discouraged. The former should be passed when + * using SharedThreadMetrics whereas the latter when using ThreadMetrics* + * directly. Failing to do so will result in NSOLID_E_UV_EINVAL error. * @param data variable number of arguments to be propagated to the callback. * @return NSOLID_E_SUCCESS in case of success or a different NSOLID_E_ * error value otherwise. @@ -684,14 +699,20 @@ class NODE_EXTERN ThreadMetrics { friend class EnvInst; explicit ThreadMetrics(uint64_t thread_id); - int get_thread_metrics_(); + int get_thread_metrics(); + int get_shared_thread_metrics(); + void reset(); template static void thread_metrics_proxy_(ThreadMetrics* tm); + template + static void shared_thread_metrics_proxy_(SharedThreadMetrics tm_sp); + uint64_t thread_id_ = 0xFFFFFFFFFFFFFFFF; - void* user_data_ = nullptr; + internal::user_data user_data_; thread_metrics_proxy_sig proxy_; + shared_thread_metrics_proxy_sig shared_proxy_; std::atomic update_running_ = {false}; uv_mutex_t stor_lock_; @@ -988,37 +1009,49 @@ int ThreadMetrics::Update(Cb&& cb, Data&&... data) { return UV_EBUSY; } - // _1 - ThreadMetrics* - UserData* user_data = new (std::nothrow) UserData( - std::bind(std::forward(cb), _1, std::forward(data)...)); + user_data_ = internal::user_data( + new UserData( + std::bind(std::forward(cb), _1, std::forward(data)...)), + internal::delete_proxy_); - if (user_data == nullptr) { + if (user_data_ == nullptr) { return UV_ENOMEM; } - user_data_ = user_data; - proxy_ = thread_metrics_proxy_; stor_.thread_id = thread_id_; - int er = get_thread_metrics_(); - if (er) { - user_data_ = nullptr; - proxy_ = nullptr; - delete user_data; - update_running_ = false; + if constexpr (std::is_invocable_v) { + proxy_ = thread_metrics_proxy_; + int er = get_thread_metrics(); + if (er) { + reset(); + } + return er; + } else { + shared_proxy_ = shared_thread_metrics_proxy_; + int er = get_shared_thread_metrics(); + if (er) { + reset(); + } + + return er; } - return er; } template void ThreadMetrics::thread_metrics_proxy_(ThreadMetrics* tm) { - G* g = static_cast(tm->user_data_); - tm->user_data_ = nullptr; - tm->proxy_ = nullptr; - tm->update_running_ = false; + G* g = static_cast(tm->user_data_.get()); + tm->reset(); (*g)(tm); - delete g; +} + + +template +void ThreadMetrics::shared_thread_metrics_proxy_(SharedThreadMetrics tm_sp) { + G* g = static_cast(tm_sp->user_data_.get()); + tm_sp->reset(); + (*g)(tm_sp); } diff --git a/test/addons/nsolid-env-metrics/binding.cc b/test/addons/nsolid-env-metrics/binding.cc index 99c911e8540..b7680a0f58f 100644 --- a/test/addons/nsolid-env-metrics/binding.cc +++ b/test/addons/nsolid-env-metrics/binding.cc @@ -8,10 +8,10 @@ std::atomic cb_cntr = { 0 }; using node::nsolid::ThreadMetrics; +using node::nsolid::SharedThreadMetrics; -static void got_env_metrics(ThreadMetrics* tm) { +static void got_env_metrics(SharedThreadMetrics tm_sp) { cb_cntr++; - delete tm; } static void GetMetrics(const v8::FunctionCallbackInfo& args) { @@ -27,11 +27,10 @@ static void GetMetrics(const v8::FunctionCallbackInfo& args) { assert(envinst != nullptr); } - auto* tm = new node::nsolid::ThreadMetrics(envinst); + SharedThreadMetrics tm_sp = ThreadMetrics::Create(envinst); - int er = tm->Update(got_env_metrics); - if (er) - delete tm; + int er = tm_sp->Update(got_env_metrics); + args.GetReturnValue().Set(er); } NODE_MODULE_INIT(/* exports, module, context */) { diff --git a/test/addons/nsolid-metrics/binding.cc b/test/addons/nsolid-metrics/binding.cc index b16ea5f4fc5..55f862e6991 100644 --- a/test/addons/nsolid-metrics/binding.cc +++ b/test/addons/nsolid-metrics/binding.cc @@ -5,7 +5,9 @@ #include #include +using node::nsolid::GetEnvInst; using node::nsolid::ProcessMetrics; +using node::nsolid::SharedThreadMetrics; using node::nsolid::ThreadMetrics; using v8::FunctionCallbackInfo; @@ -14,21 +16,81 @@ using v8::Uint32; using v8::Value; std::atomic cb_cntr = { 0 }; +std::atomic cb_cntr_lambda = { 0 }; +std::atomic cb_cntr_shared = { 0 }; +std::atomic cb_cntr_shared_lambda = { 0 }; static void metrics_cb(ThreadMetrics* tm, void*, ThreadMetrics*) { cb_cntr++; delete tm; } +static void metrics_cb_shared(SharedThreadMetrics tm, void*, ThreadMetrics*) { + cb_cntr_shared++; +} + static void GetEnvMetrics(const FunctionCallbackInfo& args) { assert(args[0]->IsNumber()); uint64_t thread_id = args[0].As()->Value(); - auto* tm = new ThreadMetrics(node::nsolid::GetEnvInst(thread_id)); + auto* tm = new ThreadMetrics(GetEnvInst(thread_id)); + + assert(UV_EINVAL == tm->Update(metrics_cb_shared, nullptr, tm)); args.GetReturnValue().Set(tm->Update(metrics_cb, nullptr, tm)); } +static void GetEnvMetricsLambda(const FunctionCallbackInfo& args) { + assert(args[0]->IsNumber()); + + uint64_t thread_id = args[0].As()->Value(); + auto* tm = new ThreadMetrics(GetEnvInst(thread_id)); + + int ret = tm->Update([](SharedThreadMetrics tm, void*, ThreadMetrics*) { + }, nullptr, tm); + + assert(ret == UV_EINVAL); + + ret = tm->Update([](ThreadMetrics* tm, void*, ThreadMetrics* tm1) { + assert(tm == tm1); + cb_cntr_lambda++; + delete tm; + }, nullptr, tm); + args.GetReturnValue().Set(ret); +} + +static void GetEnvMetricsShared(const FunctionCallbackInfo& args) { + assert(args[0]->IsNumber()); + + uint64_t thread_id = args[0].As()->Value(); + SharedThreadMetrics tm = ThreadMetrics::Create(GetEnvInst(thread_id)); + + assert(UV_EINVAL == tm->Update(metrics_cb, nullptr, tm.get())); + + // The cb should never be called as SharedThreadMetrics is destroyed right + // after leaving the current scope. + args.GetReturnValue().Set(tm->Update(metrics_cb_shared, nullptr, tm.get())); +} + +static void getEnvMetricsSharedLambda(const FunctionCallbackInfo& args) { + assert(args[0]->IsNumber()); + + uint64_t thread_id = args[0].As()->Value(); + SharedThreadMetrics tm = ThreadMetrics::Create(GetEnvInst(thread_id)); + + int ret = tm->Update([](ThreadMetrics* tm, void*, ThreadMetrics* tm1) { + }, nullptr, tm.get()); + + assert(ret == UV_EINVAL); + + // The cb should never be called as SharedThreadMetrics is destroyed right + // after leaving the current scope. + ret = tm->Update([](SharedThreadMetrics tm, void*, ThreadMetrics*) { + cb_cntr_shared_lambda++; + }, nullptr, tm.get()); + args.GetReturnValue().Set(ret); +} + static void GetProcMetrics(const FunctionCallbackInfo& args) { ProcessMetrics pm; @@ -46,8 +108,28 @@ static void GetCbCntr(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(cb_cntr); } +static void GetCbCntrLambda(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(cb_cntr_lambda); +} + +static void GetCbCntrShared(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(cb_cntr_shared); +} + +static void GetCbCntrSharedLambda(const FunctionCallbackInfo& args) { + args.GetReturnValue().Set(cb_cntr_shared_lambda); +} + NODE_MODULE_INIT(/* exports, module, context */) { NODE_SET_METHOD(exports, "getCbCntr", GetCbCntr); + NODE_SET_METHOD(exports, "getCbCntrLambda", GetCbCntrLambda); + NODE_SET_METHOD(exports, "getCbCntrShared", GetCbCntrShared); + NODE_SET_METHOD(exports, "getCbCntrSharedLambda", GetCbCntrSharedLambda); NODE_SET_METHOD(exports, "getEnvMetrics", GetEnvMetrics); + NODE_SET_METHOD(exports, "getEnvMetricsLambda", GetEnvMetricsLambda); + NODE_SET_METHOD(exports, "getEnvMetricsShared", GetEnvMetricsShared); + NODE_SET_METHOD(exports, + "getEnvMetricsSharedLambda", + getEnvMetricsSharedLambda); NODE_SET_METHOD(exports, "getProcMetrics", GetProcMetrics); } diff --git a/test/addons/nsolid-metrics/nsolid-metrics.js b/test/addons/nsolid-metrics/nsolid-metrics.js index 39f2d436ad3..060a2457c9a 100644 --- a/test/addons/nsolid-metrics/nsolid-metrics.js +++ b/test/addons/nsolid-metrics/nsolid-metrics.js @@ -25,6 +25,9 @@ if (!isMainThread) { process.on('beforeExit', mustCall(() => { assert.strictEqual(binding.getCbCntr(), wkr_count); + assert.strictEqual(binding.getCbCntrLambda(), wkr_count); + assert.strictEqual(binding.getCbCntrShared(), 0); + assert.strictEqual(binding.getCbCntrSharedLambda(), 0); })); const metrics = binding.getProcMetrics(); @@ -37,6 +40,9 @@ for (let i = 0; i < wkr_count; i++) { })); worker.on('online', mustCall(() => { assert.strictEqual(binding.getEnvMetrics(worker.threadId), 0); + assert.strictEqual(binding.getEnvMetricsLambda(worker.threadId), 0); + assert.strictEqual(binding.getEnvMetricsShared(worker.threadId), 0); + assert.strictEqual(binding.getEnvMetricsSharedLambda(worker.threadId), 0); worker.postMessage('exit'); })); }