GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: req_wrap-inl.h Lines: 52 52 100.0 %
Date: 2022-09-19 04:21:54 Branches: 18 34 52.9 %

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
77675
ReqWrapBase::ReqWrapBase(Environment* env) {
13
77675
  CHECK(env->has_run_bootstrapping_code());
14
77675
  env->req_wrap_queue()->PushBack(this);
15
77675
}
16
17
template <typename T>
18
90939
ReqWrap<T>::ReqWrap(Environment* env,
19
                    v8::Local<v8::Object> object,
20
                    AsyncWrap::ProviderType provider)
21
    : AsyncWrap(env, object, provider),
22
90939
      ReqWrapBase(env) {
23
90939
  MakeWeak();
24
90939
  Reset();
25
90939
}
26
27
template <typename T>
28
155244
ReqWrap<T>::~ReqWrap() {}
29
30
template <typename T>
31
91131
void ReqWrap<T>::Dispatched() {
32
91131
  req_.data = this;
33
91131
}
34
35
template <typename T>
36
91152
void ReqWrap<T>::Reset() {
37
91152
  original_callback_ = nullptr;
38
91152
  req_.data = nullptr;
39
91152
}
40
41
template <typename T>
42
167899
ReqWrap<T>* ReqWrap<T>::from_req(T* req) {
43
167899
  return ContainerOf(&ReqWrap<T>::req_, req);
44
}
45
46
template <typename T>
47
163
void ReqWrap<T>::Cancel() {
48
163
  if (req_.data == this)  // Only cancel if already dispatched.
49
146
    uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
50
163
}
51
52
template <typename T>
53
26
AsyncWrap* ReqWrap<T>::GetAsyncWrap() {
54
26
  return this;
55
}
56
57
// Below is dark template magic designed to invoke libuv functions that
58
// initialize uv_req_t instances in a unified fashion, to allow easier
59
// tracking of active/inactive requests.
60
61
// Invoke a generic libuv function that initializes uv_req_t instances.
62
// This is, unfortunately, necessary since they come in three different
63
// variants that can not all be invoked in the same way:
64
// - int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);
65
// - int uv_foo(uv_req_t* request, ...);
66
// - void uv_foo(uv_req_t* request, ...);
67
template <typename ReqT, typename T>
68
struct CallLibuvFunction;
69
70
// Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`.
71
template <typename ReqT, typename... Args>
72
struct CallLibuvFunction<ReqT, int(*)(uv_loop_t*, ReqT*, Args...)> {
73
  using T = int(*)(uv_loop_t*, ReqT*, Args...);
74
  template <typename... PassedArgs>
75
128756
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
76
128756
    return fn(loop, req, args...);
77
  }
78
};
79
80
// Detect `int uv_foo(uv_req_t* request, ...);`.
81
template <typename ReqT, typename... Args>
82
struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> {
83
  using T = int(*)(ReqT*, Args...);
84
  template <typename... PassedArgs>
85
21363
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
86
21363
    return fn(req, args...);
87
  }
88
};
89
90
// Detect `void uv_foo(uv_req_t* request, ...);`.
91
template <typename ReqT, typename... Args>
92
struct CallLibuvFunction<ReqT, void(*)(ReqT*, Args...)> {
93
  using T = void(*)(ReqT*, Args...);
94
  template <typename... PassedArgs>
95
59
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
96
59
    fn(req, args...);
97
59
    return 0;
98
  }
99
};
100
101
// This is slightly darker magic: This template is 'applied' to each parameter
102
// passed to the libuv function. If the parameter type (aka `T`) is a
103
// function type, it is assumed that this it is the request callback, and a
104
// wrapper that calls the original callback is created.
105
// If not, the parameter is passed through verbatim.
106
template <typename ReqT, typename T>
107
struct MakeLibuvRequestCallback {
108
420636
  static T For(ReqWrap<ReqT>* req_wrap, T v) {
109
    static_assert(!is_callable<T>::value,
110
                  "MakeLibuvRequestCallback missed a callback");
111
420636
    return v;
112
  }
113
};
114
115
// Match the `void callback(uv_req_t*, ...);` signature that all libuv
116
// callbacks use.
117
template <typename ReqT, typename... Args>
118
struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> {
119
  using F = void(*)(ReqT* req, Args... args);
120
121
91114
  static void Wrapper(ReqT* req, Args... args) {
122
182180
    BaseObjectPtr<ReqWrap<ReqT>> req_wrap{ReqWrap<ReqT>::from_req(req)};
123
91114
    req_wrap->Detach();
124
91114
    req_wrap->env()->DecreaseWaitingRequestCounter();
125
91114
    F original_callback = reinterpret_cast<F>(req_wrap->original_callback_);
126
91114
    original_callback(req, args...);
127
91066
  }
128
129
91130
  static F For(ReqWrap<ReqT>* req_wrap, F v) {
130
91130
    CHECK_NULL(req_wrap->original_callback_);
131
91130
    req_wrap->original_callback_ =
132
        reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v);
133
91130
    return Wrapper;
134
  }
135
};
136
137
template <typename T>
138
template <typename LibuvFunction, typename... Args>
139
150178
int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
140
5554
  Dispatched();
141
  // This expands as:
142
  //
143
  // int err = fn(env()->event_loop(), req(), arg1, arg2, Wrapper, arg3, ...)
144
  //              ^                                       ^        ^
145
  //              |                                       |        |
146
  //              \-- Omitted if `fn` has no              |        |
147
  //                  first `uv_loop_t*` argument         |        |
148
  //                                                      |        |
149
  //        A function callback whose first argument      |        |
150
  //        matches the libuv request type is replaced ---/        |
151
  //        by the `Wrapper` method defined above                  |
152
  //                                                               |
153
  //               Other (non-function) arguments are passed  -----/
154
  //               through verbatim
155
77866
  int err = CallLibuvFunction<T, LibuvFunction>::Call(
156
      fn,
157
      env()->event_loop(),
158
      req(),
159
      MakeLibuvRequestCallback<T, Args>::For(this, args)...);
160







77866
  if (err >= 0) {
161
77864
    ClearWeak();
162
77864
    env()->IncreaseWaitingRequestCounter();
163
  }
164
77866
  return err;
165
}
166
167
}  // namespace node
168
169
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
170
171
#endif  // SRC_REQ_WRAP_INL_H_