Skip to content

Commit

Permalink
src: make ProcessMetrics API thread-safe
Browse files Browse the repository at this point in the history
Previous calls to Update() or Get() could cause corruption because they
could attempt to write to stor_ from different threads. Put a lock
around all access to stor_ so that doesn't happen.

PR-URL: #86
Reviewed-by: Santiago Gimeno <santiago.gimeno@gmail.com>
  • Loading branch information
trevnorris committed Feb 23, 2024
1 parent 173d6ba commit e2d7087
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
15 changes: 14 additions & 1 deletion src/nsolid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,19 @@ static int get_cpu_usage(uint64_t* fields, uv_rusage_t* ru = nullptr) {
ProcessMetrics::ProcessMetrics() : cpu_prev_time_(uv_hrtime()) {
int er = get_cpu_usage(cpu_prev_);
CHECK_EQ(er, 0);
CHECK_EQ(uv_mutex_init(&stor_lock_), 0);
}


ProcessMetrics::~ProcessMetrics() {
uv_mutex_destroy(&stor_lock_);
}


std::string ProcessMetrics::toJSON() {
std::string metrics_string;

uv_mutex_lock(&stor_lock_);
metrics_string += "{";
#define V(Type, CName, JSName, MType) \
metrics_string += "\"" #JSName "\":"; \
Expand All @@ -173,13 +180,17 @@ std::string ProcessMetrics::toJSON() {
metrics_string += "\"cpu\":";
metrics_string += std::to_string(stor_.cpu_percent);
metrics_string += "}";
uv_mutex_unlock(&stor_lock_);

return metrics_string;
}


ProcessMetrics::MetricsStor ProcessMetrics::Get() {
return stor_;
uv_mutex_lock(&stor_lock_);
auto stor = stor_;
uv_mutex_unlock(&stor_lock_);
return stor;
}


Expand Down Expand Up @@ -223,6 +234,7 @@ int ProcessMetrics::Update() {
cpu_percent[1] = (cpu[1] - cpu_prev_[1]) * 100.0 * 1000.0 / elapsed;
cpu_percent[2] = (cpu[2] - cpu_prev_[2]) * 100.0 * 1000.0 / elapsed;

uv_mutex_lock(&stor_lock_);
stor_.title = title_buf;
stor_.user = pwd.username;
stor_.timestamp = duration_cast<milliseconds>(
Expand All @@ -249,6 +261,7 @@ int ProcessMetrics::Update() {
stor_.cpu_system_percent = cpu_percent[1];
stor_.cpu_percent = cpu_percent[2];
stor_.cpu = stor_.cpu_percent;
uv_mutex_unlock(&stor_lock_);

cpu_prev_[0] = cpu[0];
cpu_prev_[1] = cpu[1];
Expand Down
3 changes: 2 additions & 1 deletion src/nsolid.h
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ class NODE_EXTERN ProcessMetrics {
* @brief Destroy the Process Metrics object
*
*/
~ProcessMetrics() = default;
~ProcessMetrics();

/**
* @brief struct to store process metrics data.
Expand Down Expand Up @@ -598,6 +598,7 @@ class NODE_EXTERN ProcessMetrics {
int Update();

private:
uv_mutex_t stor_lock_;
MetricsStor stor_;
uint64_t cpu_prev_[3];
uint64_t cpu_prev_time_;
Expand Down
3 changes: 1 addition & 2 deletions test/addons/nsolid-proc-metrics/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
#include <assert.h>

node::nsolid::ProcessMetrics proc_metrics_;
node::nsolid::ProcessMetrics::MetricsStor proc_stor;

static void GetMetrics(const v8::FunctionCallbackInfo<v8::Value>& args) {
assert(0 == proc_metrics_.Update());
proc_stor = proc_metrics_.Get();
node::nsolid::ProcessMetrics::MetricsStor proc_stor = proc_metrics_.Get();
assert(proc_stor.system_uptime > 0);
}

Expand Down

0 comments on commit e2d7087

Please sign in to comment.