Skip to content

Commit a3a4d2c

Browse files
jasnelltargos
authored andcommitted
src: add TimerWrap utility
Consolidate uv_timer_t boilerplate code into a shared utility. There are several places throughout the code where we use uv_timer_t internally (inspector, perf, quic), with some code duplication. This eliminates the duplicated code, ensures that cleanup occurs correctly, and simplifies use of the timers. Signed-off-by: James M Snell <[email protected]> PR-URL: #34186 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent ae9bd89 commit a3a4d2c

File tree

3 files changed

+180
-0
lines changed

3 files changed

+180
-0
lines changed

node.gyp

+2
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@
638638
'src/string_decoder.cc',
639639
'src/tcp_wrap.cc',
640640
'src/timers.cc',
641+
'src/timer_wrap.cc',
641642
'src/tracing/agent.cc',
642643
'src/tracing/node_trace_buffer.cc',
643644
'src/tracing/node_trace_writer.cc',
@@ -742,6 +743,7 @@
742743
'src/tracing/trace_event.h',
743744
'src/tracing/trace_event_common.h',
744745
'src/tracing/traced_value.h',
746+
'src/timer_wrap.h',
745747
'src/tty_wrap.h',
746748
'src/udp_wrap.h',
747749
'src/util.h',

src/timer_wrap.cc

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#include "env-inl.h"
2+
#include "memory_tracker-inl.h"
3+
#include "timer_wrap.h"
4+
#include "uv.h"
5+
6+
namespace node {
7+
8+
TimerWrap::TimerWrap(Environment* env, TimerCb fn, void* user_data)
9+
: env_(env),
10+
fn_(fn),
11+
user_data_(user_data) {
12+
uv_timer_init(env->event_loop(), &timer_);
13+
timer_.data = this;
14+
}
15+
16+
void TimerWrap::Stop(bool close) {
17+
if (timer_.data == nullptr) return;
18+
uv_timer_stop(&timer_);
19+
if (LIKELY(close)) {
20+
timer_.data = nullptr;
21+
env_->CloseHandle(reinterpret_cast<uv_handle_t*>(&timer_), TimerClosedCb);
22+
}
23+
}
24+
25+
void TimerWrap::TimerClosedCb(uv_handle_t* handle) {
26+
std::unique_ptr<TimerWrap> ptr(
27+
ContainerOf(&TimerWrap::timer_,
28+
reinterpret_cast<uv_timer_t*>(handle)));
29+
}
30+
31+
void TimerWrap::Update(uint64_t interval, uint64_t repeat) {
32+
if (timer_.data == nullptr) return;
33+
uv_timer_start(&timer_, OnTimeout, interval, repeat);
34+
}
35+
36+
void TimerWrap::Ref() {
37+
if (timer_.data == nullptr) return;
38+
uv_ref(reinterpret_cast<uv_handle_t*>(&timer_));
39+
}
40+
41+
void TimerWrap::Unref() {
42+
if (timer_.data == nullptr) return;
43+
uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
44+
}
45+
46+
void TimerWrap::OnTimeout(uv_timer_t* timer) {
47+
TimerWrap* t = ContainerOf(&TimerWrap::timer_, timer);
48+
t->fn_(t->user_data_);
49+
}
50+
51+
TimerWrapHandle::TimerWrapHandle(
52+
Environment* env,
53+
TimerWrap::TimerCb fn,
54+
void* user_data) {
55+
timer_ = new TimerWrap(env, fn, user_data);
56+
env->AddCleanupHook(CleanupHook, this);
57+
}
58+
59+
void TimerWrapHandle::Stop(bool close) {
60+
if (UNLIKELY(!close))
61+
return timer_->Stop(close);
62+
63+
if (timer_ != nullptr) {
64+
timer_->env()->RemoveCleanupHook(CleanupHook, this);
65+
timer_->Stop();
66+
}
67+
timer_ = nullptr;
68+
}
69+
70+
void TimerWrapHandle::Ref() {
71+
if (timer_ != nullptr)
72+
timer_->Ref();
73+
}
74+
75+
void TimerWrapHandle::Unref() {
76+
if (timer_ != nullptr)
77+
timer_->Unref();
78+
}
79+
80+
void TimerWrapHandle::Update(uint64_t interval, uint64_t repeat) {
81+
if (timer_ != nullptr)
82+
timer_->Update(interval, repeat);
83+
}
84+
85+
void TimerWrapHandle::CleanupHook(void* data) {
86+
static_cast<TimerWrapHandle*>(data)->Stop();
87+
}
88+
89+
void TimerWrapHandle::MemoryInfo(node::MemoryTracker* tracker) const {
90+
if (timer_ != nullptr)
91+
tracker->TrackField("timer", *timer_);
92+
}
93+
94+
} // namespace node

src/timer_wrap.h

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#ifndef SRC_TIMER_WRAP_H_
2+
#define SRC_TIMER_WRAP_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "memory_tracker.h"
7+
#include "env.h"
8+
#include "uv.h"
9+
10+
#include <functional>
11+
12+
namespace node {
13+
14+
// Utility class that makes working with libuv timers a bit easier.
15+
class TimerWrap final : public MemoryRetainer {
16+
public:
17+
using TimerCb = std::function<void(void*)>;
18+
19+
TimerWrap(Environment* env, TimerCb fn, void* user_data);
20+
TimerWrap(const TimerWrap&) = delete;
21+
22+
inline Environment* env() const { return env_; }
23+
24+
// Completely stops the timer, making it no longer usable.
25+
void Stop(bool close = true);
26+
27+
// Starts / Restarts the Timer
28+
void Update(uint64_t interval, uint64_t repeat = 0);
29+
30+
void Ref();
31+
32+
void Unref();
33+
34+
SET_NO_MEMORY_INFO();
35+
SET_MEMORY_INFO_NAME(TimerWrap)
36+
SET_SELF_SIZE(TimerWrap)
37+
38+
private:
39+
static void TimerClosedCb(uv_handle_t* handle);
40+
static void OnTimeout(uv_timer_t* timer);
41+
~TimerWrap() = default;
42+
43+
Environment* env_;
44+
TimerCb fn_;
45+
uv_timer_t timer_;
46+
void* user_data_ = nullptr;
47+
48+
friend std::unique_ptr<TimerWrap>::deleter_type;
49+
};
50+
51+
class TimerWrapHandle : public MemoryRetainer {
52+
public:
53+
TimerWrapHandle(
54+
Environment* env,
55+
TimerWrap::TimerCb fn,
56+
void* user_data = nullptr);
57+
58+
TimerWrapHandle(const TimerWrapHandle&) = delete;
59+
60+
~TimerWrapHandle() { Stop(); }
61+
62+
void Update(uint64_t interval, uint64_t repeat = 0);
63+
64+
void Ref();
65+
66+
void Unref();
67+
68+
void Stop(bool close = true);
69+
70+
void MemoryInfo(node::MemoryTracker* tracker) const override;
71+
72+
SET_MEMORY_INFO_NAME(TimerWrapHandle)
73+
SET_SELF_SIZE(TimerWrapHandle)
74+
75+
private:
76+
static void CleanupHook(void* data);
77+
TimerWrap* timer_;
78+
};
79+
80+
} // namespace node
81+
82+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
83+
84+
#endif // SRC_TIMER_WRAP_H_

0 commit comments

Comments
 (0)