Skip to content

Commit bced2ed

Browse files
committed
src: don't allow parallel calls to Update()
ThreadMetrics::Update() is supposed to be thread-safe, so we need to guard against calls being made in parallel. Return UV_EBUSY if an asynchronous Update() is already being processed. PR-URL: #13 Santiago Gimeno <[email protected]>
1 parent 733f1ac commit bced2ed

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

src/nsolid.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ int ThreadMetrics::Update(v8::Isolate* isolate) {
326326
if (envinst == nullptr || envinst->thread_id() != thread_id_) {
327327
return UV_ESRCH;
328328
}
329+
// An async update request is currently in process. Let that complete before
330+
// running Update() again.
331+
if (update_running_) {
332+
return UV_EBUSY;
333+
}
329334

330335
uv_mutex_lock(&stor_lock_);
331336
envinst->GetThreadMetrics(&stor_);

src/nsolid.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,7 @@ class NODE_EXTERN ThreadMetrics {
693693
void* user_data_ = nullptr;
694694
thread_metrics_proxy_sig proxy_;
695695

696+
std::atomic<bool> update_running_ = {false};
696697
uv_mutex_t stor_lock_;
697698
MetricsStor stor_;
698699
};
@@ -976,22 +977,32 @@ class NODE_EXTERN Snapshot {
976977
/** @cond DONT_DOCUMENT */
977978
template <typename Cb, typename... Data>
978979
int ThreadMetrics::Update(Cb&& cb, Data&&... data) {
980+
bool expected = false;
979981
// NOLINTNEXTLINE(build/namespaces)
980982
using namespace std::placeholders;
981983
using UserData = decltype(std::bind(
982984
std::forward<Cb>(cb), _1, std::forward<Data>(data)...));
983985

986+
update_running_.compare_exchange_strong(expected, true);
987+
if (expected) {
988+
return UV_EBUSY;
989+
}
990+
984991
// _1 - ThreadMetrics*
985-
std::unique_ptr<UserData> user_data = std::make_unique<UserData>(std::bind(
986-
std::forward<Cb>(cb), _1, std::forward<Data>(data)...));
992+
UserData* user_data = new UserData(
993+
std::bind(std::forward<Cb>(cb), _1, std::forward<Data>(data)...));
987994

988-
user_data_ = static_cast<void*>(user_data.get());
995+
user_data_ = user_data;
989996
proxy_ = thread_metrics_proxy_<UserData>;
990997
stor_.thread_id = thread_id_;
991998

992999
int er = get_thread_metrics_();
993-
if (!er)
994-
user_data.release();
1000+
if (er) {
1001+
user_data_ = nullptr;
1002+
proxy_ = nullptr;
1003+
delete user_data;
1004+
update_running_ = false;
1005+
}
9951006
return er;
9961007
}
9971008

@@ -1001,6 +1012,7 @@ void ThreadMetrics::thread_metrics_proxy_(ThreadMetrics* tm) {
10011012
G* g = static_cast<G*>(tm->user_data_);
10021013
tm->user_data_ = nullptr;
10031014
tm->proxy_ = nullptr;
1015+
tm->update_running_ = false;
10041016
(*g)(tm);
10051017
delete g;
10061018
}

0 commit comments

Comments
 (0)