GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: req_wrap-inl.h Lines: 50 50 100.0 %
Date: 2022-08-14 04:19:53 Branches: 19 36 52.8 %

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_