GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/req_wrap-inl.h Lines: 46 46 100.0 %
Date: 2019-01-07 12:15:22 Branches: 23 42 54.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 "env-inl.h"
9
#include "util-inl.h"
10
#include "uv.h"
11
12
namespace node {
13
14
template <typename T>
15
172484
ReqWrap<T>::ReqWrap(Environment* env,
16
                    v8::Local<v8::Object> object,
17
                    AsyncWrap::ProviderType provider)
18
172484
    : AsyncWrap(env, object, provider) {
19
20
  // FIXME(bnoordhuis) The fact that a reinterpret_cast is needed is
21
  // arguably a good indicator that there should be more than one queue.
22
172484
  env->req_wrap_queue()->PushBack(reinterpret_cast<ReqWrap<uv_req_t>*>(this));
23
24
172484
  Reset();
25
172484
}
26
27
template <typename T>
28
172471
ReqWrap<T>::~ReqWrap() {
29

344942
  CHECK_EQ(false, persistent().IsEmpty());
30

344942
}
31
32
template <typename T>
33
172661
void ReqWrap<T>::Dispatched() {
34
172661
  req_.data = this;
35
172661
}
36
37
template <typename T>
38
172692
void ReqWrap<T>::Reset() {
39
172692
  original_callback_ = nullptr;
40
172692
  req_.data = nullptr;
41
172692
}
42
43
template <typename T>
44
163416
ReqWrap<T>* ReqWrap<T>::from_req(T* req) {
45
163416
  return ContainerOf(&ReqWrap<T>::req_, req);
46
}
47
48
template <typename T>
49
32
void ReqWrap<T>::Cancel() {
50
32
  if (req_.data == this)  // Only cancel if already dispatched.
51
1
    uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
52
32
}
53
54
// Below is dark template magic designed to invoke libuv functions that
55
// initialize uv_req_t instances in a unified fashion, to allow easier
56
// tracking of active/inactive requests.
57
58
// Invoke a generic libuv function that initializes uv_req_t instances.
59
// This is, unfortunately, necessary since they come in three different
60
// variants that can not all be invoked in the same way:
61
// - int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);
62
// - int uv_foo(uv_req_t* request, ...);
63
// - void uv_foo(uv_req_t* request, ...);
64
template <typename ReqT, typename T>
65
struct CallLibuvFunction;
66
67
// Detect `int uv_foo(uv_loop_t* loop, uv_req_t* request, ...);`.
68
template <typename ReqT, typename... Args>
69
struct CallLibuvFunction<ReqT, int(*)(uv_loop_t*, ReqT*, Args...)> {
70
  using T = int(*)(uv_loop_t*, ReqT*, Args...);
71
  template <typename... PassedArgs>
72
163567
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
73
163567
    return fn(loop, req, args...);
74
  }
75
};
76
77
// Detect `int uv_foo(uv_req_t* request, ...);`.
78
template <typename ReqT, typename... Args>
79
struct CallLibuvFunction<ReqT, int(*)(ReqT*, Args...)> {
80
  using T = int(*)(ReqT*, Args...);
81
  template <typename... PassedArgs>
82
9041
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
83
9041
    return fn(req, args...);
84
  }
85
};
86
87
// Detect `void uv_foo(uv_req_t* request, ...);`.
88
template <typename ReqT, typename... Args>
89
struct CallLibuvFunction<ReqT, void(*)(ReqT*, Args...)> {
90
  using T = void(*)(ReqT*, Args...);
91
  template <typename... PassedArgs>
92
52
  static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
93
52
    fn(req, args...);
94
52
    return 0;
95
  }
96
};
97
98
// This is slightly darker magic: This template is 'applied' to each parameter
99
// passed to the libuv function. If the parameter type (aka `T`) is a
100
// function type, it is assumed that this it is the request callback, and a
101
// wrapper that calls the original callback is created.
102
// If not, the parameter is passed through verbatim.
103
template <typename ReqT, typename T>
104
struct MakeLibuvRequestCallback {
105
643254
  static T For(ReqWrap<ReqT>* req_wrap, T v) {
106
    static_assert(!is_callable<T>::value,
107
                  "MakeLibuvRequestCallback missed a callback");
108
643254
    return v;
109
  }
110
};
111
112
// Match the `void callback(uv_req_t*, ...);` signature that all libuv
113
// callbacks use.
114
template <typename ReqT, typename... Args>
115
struct MakeLibuvRequestCallback<ReqT, void(*)(ReqT*, Args...)> {
116
  using F = void(*)(ReqT* req, Args... args);
117
118
172655
  static void Wrapper(ReqT* req, Args... args) {
119
172655
    ReqWrap<ReqT>* req_wrap = ContainerOf(&ReqWrap<ReqT>::req_, req);
120
172655
    req_wrap->env()->DecreaseWaitingRequestCounter();
121
172655
    F original_callback = reinterpret_cast<F>(req_wrap->original_callback_);
122
172655
    original_callback(req, args...);
123
172646
  }
124
125
172660
  static F For(ReqWrap<ReqT>* req_wrap, F v) {
126

172660
    CHECK_NULL(req_wrap->original_callback_);
127
172660
    req_wrap->original_callback_ =
128
        reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v);
129
172660
    return Wrapper;
130
  }
131
};
132
133
template <typename T>
134
template <typename LibuvFunction, typename... Args>
135
172660
int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
136
172660
  Dispatched();
137
138
  // This expands as:
139
  //
140
  // int err = fn(env()->event_loop(), req(), arg1, arg2, Wrapper, arg3, ...)
141
  //              ^                                       ^        ^
142
  //              |                                       |        |
143
  //              \-- Omitted if `fn` has no              |        |
144
  //                  first `uv_loop_t*` argument         |        |
145
  //                                                      |        |
146
  //        A function callback whose first argument      |        |
147
  //        matches the libuv request type is replaced ---/        |
148
  //        by the `Wrapper` method defined above                  |
149
  //                                                               |
150
  //               Other (non-function) arguments are passed  -----/
151
  //               through verbatim
152
  int err = CallLibuvFunction<T, LibuvFunction>::Call(
153
      fn,
154
      env()->event_loop(),
155
      req(),
156
172660
      MakeLibuvRequestCallback<T, Args>::For(this, args)...);
157







172660
  if (err >= 0)
158
172659
    env()->IncreaseWaitingRequestCounter();
159
172660
  return err;
160
}
161
162
}  // namespace node
163
164
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
165
166
#endif  // SRC_REQ_WRAP_INL_H_