• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ReqWrapBase(Environment * env)12 ReqWrapBase::ReqWrapBase(Environment* env) {
13   CHECK(env->has_run_bootstrapping_code());
14   env->req_wrap_queue()->PushBack(this);
15 }
16 
17 template <typename T>
ReqWrap(Environment * env,v8::Local<v8::Object> object,AsyncWrap::ProviderType provider)18 ReqWrap<T>::ReqWrap(Environment* env,
19                     v8::Local<v8::Object> object,
20                     AsyncWrap::ProviderType provider)
21     : AsyncWrap(env, object, provider),
22       ReqWrapBase(env) {
23   MakeWeak();
24   Reset();
25 }
26 
27 template <typename T>
~ReqWrap()28 ReqWrap<T>::~ReqWrap() {}
29 
30 template <typename T>
Dispatched()31 void ReqWrap<T>::Dispatched() {
32   req_.data = this;
33 }
34 
35 template <typename T>
Reset()36 void ReqWrap<T>::Reset() {
37   original_callback_ = nullptr;
38   req_.data = nullptr;
39 }
40 
41 template <typename T>
from_req(T * req)42 ReqWrap<T>* ReqWrap<T>::from_req(T* req) {
43   return ContainerOf(&ReqWrap<T>::req_, req);
44 }
45 
46 template <typename T>
Cancel()47 void ReqWrap<T>::Cancel() {
48   if (req_.data == this)  // Only cancel if already dispatched.
49     uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
50 }
51 
52 template <typename T>
GetAsyncWrap()53 AsyncWrap* ReqWrap<T>::GetAsyncWrap() {
54   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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
76     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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
86     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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
96     fn(req, args...);
97     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   static T For(ReqWrap<ReqT>* req_wrap, T v) {
109     static_assert(!is_callable<T>::value,
110                   "MakeLibuvRequestCallback missed a callback");
111     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   static void Wrapper(ReqT* req, Args... args) {
122     BaseObjectPtr<ReqWrap<ReqT>> req_wrap{ReqWrap<ReqT>::from_req(req)};
123     req_wrap->Detach();
124     req_wrap->env()->DecreaseWaitingRequestCounter();
125     F original_callback = reinterpret_cast<F>(req_wrap->original_callback_);
126     original_callback(req, args...);
127   }
128 
129   static F For(ReqWrap<ReqT>* req_wrap, F v) {
130     CHECK_NULL(req_wrap->original_callback_);
131     req_wrap->original_callback_ =
132         reinterpret_cast<typename ReqWrap<ReqT>::callback_t>(v);
133     return Wrapper;
134   }
135 };
136 
137 template <typename T>
138 template <typename LibuvFunction, typename... Args>
139 int ReqWrap<T>::Dispatch(LibuvFunction fn, Args... args) {
140   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   int err = CallLibuvFunction<T, LibuvFunction>::Call(
156       fn,
157       env()->event_loop(),
158       req(),
159       MakeLibuvRequestCallback<T, Args>::For(this, args)...);
160   if (err >= 0) {
161     ClearWeak();
162     env()->IncreaseWaitingRequestCounter();
163   }
164   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_
172