• 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   Reset();
24 }
25 
26 template <typename T>
~ReqWrap()27 ReqWrap<T>::~ReqWrap() {
28   CHECK_EQ(false, persistent().IsEmpty());
29 }
30 
31 template <typename T>
Dispatched()32 void ReqWrap<T>::Dispatched() {
33   req_.data = this;
34 }
35 
36 template <typename T>
Reset()37 void ReqWrap<T>::Reset() {
38   original_callback_ = nullptr;
39   req_.data = nullptr;
40 }
41 
42 template <typename T>
from_req(T * req)43 ReqWrap<T>* ReqWrap<T>::from_req(T* req) {
44   return ContainerOf(&ReqWrap<T>::req_, req);
45 }
46 
47 template <typename T>
Cancel()48 void ReqWrap<T>::Cancel() {
49   if (req_.data == this)  // Only cancel if already dispatched.
50     uv_cancel(reinterpret_cast<uv_req_t*>(&req_));
51 }
52 
53 template <typename T>
GetAsyncWrap()54 AsyncWrap* ReqWrap<T>::GetAsyncWrap() {
55   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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
77     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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
87     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   static int Call(T fn, uv_loop_t* loop, ReqT* req, PassedArgs... args) {
97     fn(req, args...);
98     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   static T For(ReqWrap<ReqT>* req_wrap, T v) {
110     static_assert(!is_callable<T>::value,
111                   "MakeLibuvRequestCallback missed a callback");
112     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   static void Wrapper(ReqT* req, Args... args) {
123     ReqWrap<ReqT>* req_wrap = ReqWrap<ReqT>::from_req(req);
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 
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   int err = CallLibuvFunction<T, LibuvFunction>::Call(
157       fn,
158       env()->event_loop(),
159       req(),
160       MakeLibuvRequestCallback<T, Args>::For(this, args)...);
161   if (err >= 0)
162     env()->IncreaseWaitingRequestCounter();
163   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_
171