Skip to content

Commit 78f2238

Browse files
addaleaxjasnell
authored andcommitted
src: unify ReqWrap libuv calling
Original PR: ayojs/ayo#85 > This allows easier tracking of whether there are active `ReqWrap`s. > PR-URL: ayojs/ayo#85 > Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
1 parent f254a37 commit 78f2238

7 files changed

Lines changed: 150 additions & 48 deletions

File tree

src/cares_wrap.cc

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,13 +1969,11 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
19691969
hints.ai_socktype = SOCK_STREAM;
19701970
hints.ai_flags = flags;
19711971

1972-
int err = uv_getaddrinfo(env->event_loop(),
1973-
req_wrap->req(),
1974-
AfterGetAddrInfo,
1975-
*hostname,
1976-
nullptr,
1977-
&hints);
1978-
req_wrap->Dispatched();
1972+
int err = req_wrap->Dispatch(uv_getaddrinfo,
1973+
AfterGetAddrInfo,
1974+
*hostname,
1975+
nullptr,
1976+
&hints);
19791977
if (err)
19801978
delete req_wrap;
19811979

@@ -1999,12 +1997,10 @@ void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
19991997

20001998
GetNameInfoReqWrap* req_wrap = new GetNameInfoReqWrap(env, req_wrap_obj);
20011999

2002-
int err = uv_getnameinfo(env->event_loop(),
2003-
req_wrap->req(),
2004-
AfterGetNameInfo,
2005-
(struct sockaddr*)&addr,
2006-
NI_NAMEREQD);
2007-
req_wrap->Dispatched();
2000+
int err = req_wrap->Dispatch(uv_getnameinfo,
2001+
AfterGetNameInfo,
2002+
(struct sockaddr*)&addr,
2003+
NI_NAMEREQD);
20082004
if (err)
20092005
delete req_wrap;
20102006

src/node_file.cc

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -355,11 +355,7 @@ class fs_req_wrap {
355355
CHECK(request->IsObject()); \
356356
FSReqWrap* req_wrap = FSReqWrap::New(env, request.As<Object>(), \
357357
#func, dest, encoding); \
358-
int err = uv_fs_ ## func(env->event_loop(), \
359-
req_wrap->req(), \
360-
__VA_ARGS__, \
361-
After); \
362-
req_wrap->Dispatched(); \
358+
int err = req_wrap->Dispatch(uv_fs_ ## func, __VA_ARGS__, After); \
363359
if (err < 0) { \
364360
uv_fs_t* uv_req = req_wrap->req(); \
365361
uv_req->result = err; \
@@ -1123,13 +1119,12 @@ static void WriteString(const FunctionCallbackInfo<Value>& args) {
11231119

11241120
FSReqWrap* req_wrap =
11251121
FSReqWrap::New(env, req.As<Object>(), "write", buf, UTF8, ownership);
1126-
int err = uv_fs_write(env->event_loop(),
1127-
req_wrap->req(),
1128-
fd,
1129-
&uvbuf,
1130-
1,
1131-
pos,
1132-
After);
1122+
int err = req_wrap->Dispatch(uv_fs_write,
1123+
fd,
1124+
&uvbuf,
1125+
1,
1126+
pos,
1127+
After);
11331128
req_wrap->Dispatched();
11341129
if (err < 0) {
11351130
uv_fs_t* uv_req = req_wrap->req();

src/pipe_wrap.cc

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,10 @@ void PipeWrap::Connect(const FunctionCallbackInfo<Value>& args) {
194194

195195
ConnectWrap* req_wrap =
196196
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_PIPECONNECTWRAP);
197-
uv_pipe_connect(req_wrap->req(),
198-
&wrap->handle_,
199-
*name,
200-
AfterConnect);
201-
req_wrap->Dispatched();
197+
req_wrap->Dispatch(uv_pipe_connect,
198+
&wrap->handle_,
199+
*name,
200+
AfterConnect);
202201

203202
args.GetReturnValue().Set(0); // uv_pipe_connect() doesn't return errors.
204203
}

src/req-wrap-inl.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,110 @@ void ReqWrap<T>::Cancel() {
4444
uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
4545
}
4646

47+
/* Below is dark template magic designed to invoke libuv functions that
48+
* initialize uv_req_t instances in a unified fashion, to allow easier
49+
* tracking of active/inactive requests. */
50+
51+
// Invoke a generic libuv function that initializes uv_req_t instances.
52+
// This is, unfortunately, necessary since they come in three different
53+
// variants that can not all be invoked in the same way:
54+
// - int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);
55+
// - int uv_foo(uv_req_t* request, ...);
56+
// - void uv_foo(uv_req_t* request, ...);
57+
template<typename ReqT, typename T>
58+
struct CallLibuvFunction;
59+
60+
// Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`.
61+
template<typename ReqT, typename... Args>
62+
struct CallLibuvFunction<ReqT, int(*)(uv_loop_t*, ReqT*, Args...)> {
63+
typedef int(*T)(uv_loop_t*, ReqT*, Args...);
64+
template<typename... PassedArgs>
65+
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
66+
return fn(loop, req, args...);
67+
}
68+
};
69+
70+
// Detect `int uv_foo(uv_req_t* request, ...);`.
71+
template<typename ReqT, typename... Args>
72+
struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> {
73+
typedef int(*T)(ReqT*, Args...);
74+
template<typename... PassedArgs>
75+
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
76+
return fn(req, args...);
77+
}
78+
};
79+
80+
// Detect `void uv_foo(uv_req_t* request, ...);`.
81+
template<typename ReqT, typename... Args>
82+
struct CallLibuvFunction<ReqT, void(*)(ReqT*, Args...)> {
83+
typedef void(*T)(ReqT*, Args...);
84+
template<typename... PassedArgs>
85+
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
86+
fn(req, args...);
87+
return 0;
88+
}
89+
};
90+
91+
// This is slightly darker magic: This template is 'applied' to each parameter
92+
// passed to the libuv function. If the parameter type (aka `T`) is a
93+
// function type, it is assumed that this it is the request callback, and a
94+
// wrapper that calls the original callback is created.
95+
// If not, the parameter is passed through verbatim.
96+
template<typename ReqT, typename T>
97+
struct MakeLibuvRequestCallback {
98+
static T For(ReqWrap<ReqT>* req_wrap, T v) {
99+
static_assert(!std::is_function<T>::value,
100+
"MakeLibuvRequestCallback missed a callback");
101+
return v;
102+
}
103+
};
104+
105+
// Match the `void callback(uv_req_t*, ...);` signature that all libuv
106+
// callbacks use.
107+
template<typename ReqT, typename... Args>
108+
struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> {
109+
typedef void(*T)(ReqT* req, Args... args);
110+
111+
static void Wrapper(ReqT* req, Args... args) {
112+
ReqWrap<ReqT>* req_wrap = ContainerOf(&ReqWrap<ReqT>::req_, req);
113+
T original_callback = reinterpret_cast<T>(req_wrap->original_callback_);
114+
original_callback(req, args...);
115+
}
116+
117+
static T For(ReqWrap<ReqT>* req_wrap, T v) {
118+
CHECK_EQ(req_wrap->original_callback_, nullptr);
119+
req_wrap->original_callback_ =
120+
reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v);
121+
return Wrapper;
122+
}
123+
};
124+
125+
template <typename T>
126+
template <typename LibuvFunction, typename... Args>
127+
int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
128+
Dispatched();
129+
130+
// This expands as:
131+
//
132+
// return fn(env()->event_loop(), req(), arg1, arg2, Wrapper, arg3, ...)
133+
// ^ ^ ^
134+
// | | |
135+
// \-- Omitted if `fn` has no | |
136+
// first `uv_loop_t*` argument | |
137+
// | |
138+
// A function callback whose first argument | |
139+
// matches the libuv request type is replaced ---/ |
140+
// by the `Wrapper` method defined above |
141+
// |
142+
// Other (non-function) arguments are passed -----/
143+
// through verbatim
144+
return CallLibuvFunction<T, LibuvFunction>::Call(
145+
fn,
146+
env()->event_loop(),
147+
req(),
148+
MakeLibuvRequestCallback<T, Args>::For(this, args)...);
149+
}
150+
47151
} // namespace node
48152

49153
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

src/req-wrap.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,25 @@ class ReqWrap : public AsyncWrap {
1717
v8::Local<v8::Object> object,
1818
AsyncWrap::ProviderType provider);
1919
inline ~ReqWrap() override;
20-
inline void Dispatched(); // Call this after the req has been dispatched.
20+
// Call this after the req has been dispatched, if that did not already
21+
// happen by using Dispatch().
22+
inline void Dispatched();
2123
T* req() { return &req_; }
2224
inline void Cancel();
2325

26+
template <typename LibuvFunction, typename... Args>
27+
inline int Dispatch(LibuvFunction fn, Args... args);
28+
2429
private:
2530
friend class Environment;
31+
template<typename ReqT, typename U>
32+
friend struct MakeLibuvRequestCallback;
33+
2634
ListNode<ReqWrap> req_wrap_queue_;
2735

36+
typedef void (*callback_t)();
37+
callback_t original_callback_ = nullptr;
38+
2839
protected:
2940
// req_wrap_queue_ needs to be at a fixed offset from the start of the class
3041
// because it is used by ContainerOf to calculate the address of the embedding

src/tcp_wrap.cc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,10 @@ void TCPWrap::Connect(const FunctionCallbackInfo<Value>& args) {
271271
env->set_init_trigger_async_id(wrap->get_async_id());
272272
ConnectWrap* req_wrap =
273273
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP);
274-
err = uv_tcp_connect(req_wrap->req(),
275-
&wrap->handle_,
276-
reinterpret_cast<const sockaddr*>(&addr),
277-
AfterConnect);
278-
req_wrap->Dispatched();
274+
err = req_wrap->Dispatch(uv_tcp_connect,
275+
&wrap->handle_,
276+
reinterpret_cast<const sockaddr*>(&addr),
277+
AfterConnect);
279278
if (err)
280279
delete req_wrap;
281280
}
@@ -307,11 +306,10 @@ void TCPWrap::Connect6(const FunctionCallbackInfo<Value>& args) {
307306
env->set_init_trigger_async_id(wrap->get_async_id());
308307
ConnectWrap* req_wrap =
309308
new ConnectWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_TCPCONNECTWRAP);
310-
err = uv_tcp_connect(req_wrap->req(),
311-
&wrap->handle_,
312-
reinterpret_cast<const sockaddr*>(&addr),
313-
AfterConnect);
314-
req_wrap->Dispatched();
309+
err = req_wrap->Dispatch(uv_tcp_connect,
310+
&wrap->handle_,
311+
reinterpret_cast<const sockaddr*>(&addr),
312+
AfterConnect);
315313
if (err)
316314
delete req_wrap;
317315
}

src/udp_wrap.cc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -384,15 +384,14 @@ void UDPWrap::DoSend(const FunctionCallbackInfo<Value>& args, int family) {
384384
}
385385

386386
if (err == 0) {
387-
err = uv_udp_send(req_wrap->req(),
388-
&wrap->handle_,
389-
*bufs,
390-
count,
391-
reinterpret_cast<const sockaddr*>(&addr),
392-
OnSend);
387+
err = req_wrap->Dispatch(uv_udp_send,
388+
&wrap->handle_,
389+
*bufs,
390+
count,
391+
reinterpret_cast<const sockaddr*>(&addr),
392+
OnSend);
393393
}
394394

395-
req_wrap->Dispatched();
396395
if (err)
397396
delete req_wrap;
398397

0 commit comments

Comments
 (0)