GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#ifndef SRC_REQ_WRAP_INL_H_ |
||
2 |
#define SRC_REQ_WRAP_INL_H_ |
||
3 |
|||
4 |
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
||
5 |
|||
6 |
#include "req_wrap.h" |
||
7 |
#include "async_wrap-inl.h" |
||
8 |
#include "uv.h" |
||
9 |
|||
10 |
namespace node { |
||
11 |
|||
12 |
76925 |
ReqWrapBase::ReqWrapBase(Environment* env) { |
|
13 |
✗✓ | 76925 |
CHECK(env->has_run_bootstrapping_code()); |
14 |
76925 |
env->req_wrap_queue()->PushBack(this); |
|
15 |
76925 |
} |
|
16 |
|||
17 |
template <typename T> |
||
18 |
89922 |
ReqWrap<T>::ReqWrap(Environment* env, |
|
19 |
v8::Local<v8::Object> object, |
||
20 |
AsyncWrap::ProviderType provider) |
||
21 |
: AsyncWrap(env, object, provider), |
||
22 |
89922 |
ReqWrapBase(env) { |
|
23 |
89922 |
Reset(); |
|
24 |
89922 |
} |
|
25 |
|||
26 |
template <typename T> |
||
27 |
153748 |
ReqWrap<T>::~ReqWrap() { |
|
28 |
✗✓ | 153748 |
CHECK_EQ(false, persistent().IsEmpty()); |
29 |
} |
||
30 |
|||
31 |
template <typename T> |
||
32 |
90114 |
void ReqWrap<T>::Dispatched() { |
|
33 |
90114 |
req_.data = this; |
|
34 |
90114 |
} |
|
35 |
|||
36 |
template <typename T> |
||
37 |
90135 |
void ReqWrap<T>::Reset() { |
|
38 |
90135 |
original_callback_ = nullptr; |
|
39 |
90135 |
req_.data = nullptr; |
|
40 |
90135 |
} |
|
41 |
|||
42 |
template <typename T> |
||
43 |
165836 |
ReqWrap<T>* ReqWrap<T>::from_req(T* req) { |
|
44 |
165836 |
return ContainerOf(&ReqWrap<T>::req_, req); |
|
45 |
} |
||
46 |
|||
47 |
template <typename T> |
||
48 |
164 |
void ReqWrap<T>::Cancel() { |
|
49 |
✓✓ | 164 |
if (req_.data == this) // Only cancel if already dispatched. |
50 |
146 |
uv_cancel(reinterpret_cast<uv_req_t*>(&req_)); |
|
51 |
164 |
} |
|
52 |
|||
53 |
template <typename T> |
||
54 |
26 |
AsyncWrap* ReqWrap<T>::GetAsyncWrap() { |
|
55 |
26 |
return this; |
|
56 |
} |
||
57 |
|||
58 |
// Below is dark template magic designed to invoke libuv functions that |
||
59 |
// initialize uv_req_t instances in a unified fashion, to allow easier |
||
60 |
// tracking of active/inactive requests. |
||
61 |
|||
62 |
// Invoke a generic libuv function that initializes uv_req_t instances. |
||
63 |
// This is, unfortunately, necessary since they come in three different |
||
64 |
// variants that can not all be invoked in the same way: |
||
65 |
// - int uv_foo(uv_loop_t* loop, uv_req_t* request, ...); |
||
66 |
// - int uv_foo(uv_req_t* request, ...); |
||
67 |
// - void uv_foo(uv_req_t* request, ...); |
||
68 |
template <typename ReqT, typename T> |
||
69 |
struct CallLibuvFunction; |
||
70 |
|||
71 |
// Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`. |
||
72 |
template <typename ReqT, typename... Args> |
||
73 |
struct CallLibuvFunction<ReqT, int(*)(uv_loop_t*, ReqT*, Args...)> { |
||
74 |
using T = int(*)(uv_loop_t*, ReqT*, Args...); |
||
75 |
template <typename... PassedArgs> |
||
76 |
127688 |
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) { |
|
77 |
127688 |
return fn(loop, req, args...); |
|
78 |
} |
||
79 |
}; |
||
80 |
|||
81 |
// Detect `int uv_foo(uv_req_t* request, ...);`. |
||
82 |
template <typename ReqT, typename... Args> |
||
83 |
struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> { |
||
84 |
using T = int(*)(ReqT*, Args...); |
||
85 |
template <typename... PassedArgs> |
||
86 |
20896 |
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) { |
|
87 |
20896 |
return fn(req, args...); |
|
88 |
} |
||
89 |
}; |
||
90 |
|||
91 |
// Detect `void uv_foo(uv_req_t* request, ...);`. |
||
92 |
template <typename ReqT, typename... Args> |
||
93 |
struct CallLibuvFunction<ReqT, void(*)(ReqT*, Args...)> { |
||
94 |
using T = void(*)(ReqT*, Args...); |
||
95 |
template <typename... PassedArgs> |
||
96 |
59 |
static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) { |
|
97 |
59 |
fn(req, args...); |
|
98 |
59 |
return 0; |
|
99 |
} |
||
100 |
}; |
||
101 |
|||
102 |
// This is slightly darker magic: This template is 'applied' to each parameter |
||
103 |
// passed to the libuv function. If the parameter type (aka `T`) is a |
||
104 |
// function type, it is assumed that this it is the request callback, and a |
||
105 |
// wrapper that calls the original callback is created. |
||
106 |
// If not, the parameter is passed through verbatim. |
||
107 |
template <typename ReqT, typename T> |
||
108 |
struct MakeLibuvRequestCallback { |
||
109 |
417238 |
static T For(ReqWrap<ReqT>* req_wrap, T v) { |
|
110 |
static_assert(!is_callable<T>::value, |
||
111 |
"MakeLibuvRequestCallback missed a callback"); |
||
112 |
417238 |
return v; |
|
113 |
} |
||
114 |
}; |
||
115 |
|||
116 |
// Match the `void callback(uv_req_t*, ...);` signature that all libuv |
||
117 |
// callbacks use. |
||
118 |
template <typename ReqT, typename... Args> |
||
119 |
struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> { |
||
120 |
using F = void(*)(ReqT* req, Args... args); |
||
121 |
|||
122 |
90097 |
static void Wrapper(ReqT* req, Args... args) { |
|
123 |
90097 |
ReqWrap<ReqT>* req_wrap = ReqWrap<ReqT>::from_req(req); |
|
124 |
90097 |
req_wrap->env()->DecreaseWaitingRequestCounter(); |
|
125 |
90097 |
F original_callback = reinterpret_cast<F>(req_wrap->original_callback_); |
|
126 |
90097 |
original_callback(req, args...); |
|
127 |
90051 |
} |
|
128 |
|||
129 |
90113 |
static F For(ReqWrap<ReqT>* req_wrap, F v) { |
|
130 |
✗✓ | 90113 |
CHECK_NULL(req_wrap->original_callback_); |
131 |
90113 |
req_wrap->original_callback_ = |
|
132 |
reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v); |
||
133 |
90113 |
return Wrapper; |
|
134 |
} |
||
135 |
}; |
||
136 |
|||
137 |
template <typename T> |
||
138 |
template <typename LibuvFunction, typename... Args> |
||
139 |
148643 |
int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) { |
|
140 |
5589 |
Dispatched(); |
|
141 |
|||
142 |
// This expands as: |
||
143 |
// |
||
144 |
// int err = fn(env()->event_loop(), req(), arg1, arg2, Wrapper, arg3, ...) |
||
145 |
// ^ ^ ^ |
||
146 |
// | | | |
||
147 |
// \-- Omitted if `fn` has no | | |
||
148 |
// first `uv_loop_t*` argument | | |
||
149 |
// | | |
||
150 |
// A function callback whose first argument | | |
||
151 |
// matches the libuv request type is replaced ---/ | |
||
152 |
// by the `Wrapper` method defined above | |
||
153 |
// | |
||
154 |
// Other (non-function) arguments are passed -----/ |
||
155 |
// through verbatim |
||
156 |
77116 |
int err = CallLibuvFunction<T, LibuvFunction>::Call( |
|
157 |
fn, |
||
158 |
env()->event_loop(), |
||
159 |
req(), |
||
160 |
MakeLibuvRequestCallback<T, Args>::For(this, args)...); |
||
161 |
✓✗✓✓ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✓✗ ✓✗✓✗ ✓✗✓✗ |
77116 |
if (err >= 0) |
162 |
77114 |
env()->IncreaseWaitingRequestCounter(); |
|
163 |
77116 |
return err; |
|
164 |
} |
||
165 |
|||
166 |
} // namespace node |
||
167 |
|||
168 |
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
||
169 |
|||
170 |
#endif // SRC_REQ_WRAP_INL_H_ |
Generated by: GCOVR (Version 4.2) |