Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/nodejs/src/req_wrap-inl.h
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 ReqWrapBase::ReqWrapBase(Environment* env) { 13 CHECK(env->has_run_bootstrapping_code()); 14 env->req_wrap_queue()->PushBack(this); 15 } 16 17 template <typename T> 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> 28 ReqWrap<T>::~ReqWrap() {} 29 30 template <typename T> 31 void ReqWrap<T>::Dispatched() { 32 req_.data = this; 33 } 34 35 template <typename T> 36 void ReqWrap<T>::Reset() { 37 original_callback_ = nullptr; 38 req_.data = nullptr; 39 } 40 41 template <typename T> 42 ReqWrap<T>* ReqWrap<T>::from_req(T* req) { 43 return ContainerOf(&ReqWrap<T>::req_, req); 44 } 45 46 template <typename T> 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> 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>, 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_