diff --git a/node.gyp b/node.gyp index 8506b286853145..01a67a08c86bba 100644 --- a/node.gyp +++ b/node.gyp @@ -144,12 +144,12 @@ 'src/node_wrap.h', 'src/node_i18n.h', 'src/pipe_wrap.h', - 'src/queue.h', 'src/smalloc.h', 'src/tty_wrap.h', 'src/tcp_wrap.h', 'src/udp_wrap.h', - 'src/req_wrap.h', + 'src/req-wrap.h', + 'src/req-wrap-inl.h', 'src/string_bytes.h', 'src/stream_wrap.h', 'src/tree.h', diff --git a/src/async-wrap-inl.h b/src/async-wrap-inl.h index f0b5c1ea08f16a..b08f791c2e7635 100644 --- a/src/async-wrap-inl.h +++ b/src/async-wrap-inl.h @@ -17,9 +17,7 @@ inline AsyncWrap::AsyncWrap(Environment* env, v8::Handle object, ProviderType provider, AsyncWrap* parent) - : BaseObject(env, object), - has_async_queue_(false), - provider_type_(provider) { + : BaseObject(env, object), bits_(static_cast(provider) << 1) { // Check user controlled flag to see if the init callback should run. if (!env->using_asyncwrap()) return; @@ -49,7 +47,7 @@ inline AsyncWrap::AsyncWrap(Environment* env, if (try_catch.HasCaught()) FatalError("node::AsyncWrap::AsyncWrap", "init hook threw"); - has_async_queue_ = true; + bits_ |= 1; // has_async_queue() is true now. if (parent != nullptr) { env->async_hooks_post_function()->Call(parent_obj, 0, nullptr); @@ -59,8 +57,13 @@ inline AsyncWrap::AsyncWrap(Environment* env, } -inline uint32_t AsyncWrap::provider_type() const { - return provider_type_; +inline bool AsyncWrap::has_async_queue() const { + return static_cast(bits_ & 1); +} + + +inline AsyncWrap::ProviderType AsyncWrap::provider_type() const { + return static_cast(bits_ >> 1); } diff --git a/src/async-wrap.cc b/src/async-wrap.cc index 3ee97f6a820c00..7887caf4f5b027 100644 --- a/src/async-wrap.cc +++ b/src/async-wrap.cc @@ -104,7 +104,7 @@ Handle AsyncWrap::MakeCallback(const Handle cb, } } - if (has_async_queue_) { + if (has_async_queue()) { try_catch.SetVerbose(false); env()->async_hooks_pre_function()->Call(context, 0, nullptr); if (try_catch.HasCaught()) @@ -118,7 +118,7 @@ Handle AsyncWrap::MakeCallback(const Handle cb, return Undefined(env()->isolate()); } - if (has_async_queue_) { + if (has_async_queue()) { try_catch.SetVerbose(false); env()->async_hooks_post_function()->Call(context, 0, nullptr); if (try_catch.HasCaught()) diff --git a/src/async-wrap.h b/src/async-wrap.h index 5bed59498aa668..86748a5fefd89b 100644 --- a/src/async-wrap.h +++ b/src/async-wrap.h @@ -2,9 +2,10 @@ #define SRC_ASYNC_WRAP_H_ #include "base-object.h" -#include "env.h" #include "v8.h" +#include + namespace node { #define NODE_ASYNC_PROVIDER_TYPES(V) \ @@ -31,6 +32,8 @@ namespace node { V(WRITEWRAP) \ V(ZLIB) +class Environment; + class AsyncWrap : public BaseObject { public: enum ProviderType { @@ -47,7 +50,7 @@ class AsyncWrap : public BaseObject { inline virtual ~AsyncWrap() override = default; - inline uint32_t provider_type() const; + inline ProviderType provider_type() const; // Only call these within a valid HandleScope. v8::Handle MakeCallback(const v8::Handle cb, @@ -62,12 +65,12 @@ class AsyncWrap : public BaseObject { private: inline AsyncWrap(); + inline bool has_async_queue() const; // When the async hooks init JS function is called from the constructor it is // expected the context object will receive a _asyncQueue object property // that will be used to call pre/post in MakeCallback. - bool has_async_queue_; - ProviderType provider_type_; + uint32_t bits_; }; } // namespace node diff --git a/src/base-object-inl.h b/src/base-object-inl.h index 0b220bb74bf0fe..db0daa1e82f559 100644 --- a/src/base-object-inl.h +++ b/src/base-object-inl.h @@ -2,6 +2,8 @@ #define SRC_BASE_OBJECT_INL_H_ #include "base-object.h" +#include "env.h" +#include "env-inl.h" #include "util.h" #include "util-inl.h" #include "v8.h" diff --git a/src/base-object.h b/src/base-object.h index 6665662c7b3497..5a7b95827e8f11 100644 --- a/src/base-object.h +++ b/src/base-object.h @@ -1,11 +1,12 @@ #ifndef SRC_BASE_OBJECT_H_ #define SRC_BASE_OBJECT_H_ -#include "env.h" #include "v8.h" namespace node { +class Environment; + class BaseObject { public: BaseObject(Environment* env, v8::Local handle); diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index f170f07e40957c..373675f0f0d724 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -5,7 +5,8 @@ #include "env.h" #include "env-inl.h" #include "node.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "tree.h" #include "util.h" #include "uv.h" diff --git a/src/debug-agent.cc b/src/debug-agent.cc index 955adc6255bef6..39d8bfe9e5afcc 100644 --- a/src/debug-agent.cc +++ b/src/debug-agent.cc @@ -29,7 +29,6 @@ #include "v8-debug.h" #include "util.h" #include "util-inl.h" -#include "queue.h" #include @@ -64,8 +63,6 @@ Agent::Agent(Environment* env) : state_(kNone), err = uv_mutex_init(&message_mutex_); CHECK_EQ(err, 0); - - QUEUE_INIT(&messages_); } @@ -75,13 +72,8 @@ Agent::~Agent() { uv_sem_destroy(&start_sem_); uv_mutex_destroy(&message_mutex_); - // Clean-up messages - while (!QUEUE_EMPTY(&messages_)) { - QUEUE* q = QUEUE_HEAD(&messages_); - QUEUE_REMOVE(q); - AgentMessage* msg = ContainerOf(&AgentMessage::member, q); + while (AgentMessage* msg = messages_.PopFront()) delete msg; - } } @@ -281,13 +273,9 @@ void Agent::ChildSignalCb(uv_async_t* signal) { Local api = PersistentToLocal(isolate, a->api_); uv_mutex_lock(&a->message_mutex_); - while (!QUEUE_EMPTY(&a->messages_)) { - QUEUE* q = QUEUE_HEAD(&a->messages_); - AgentMessage* msg = ContainerOf(&AgentMessage::member, q); - + while (AgentMessage* msg = a->messages_.PopFront()) { // Time to close everything if (msg->data() == nullptr) { - QUEUE_REMOVE(q); delete msg; MakeCallback(isolate, api, "onclose", 0, nullptr); @@ -296,10 +284,11 @@ void Agent::ChildSignalCb(uv_async_t* signal) { // Waiting for client, do not send anything just yet // TODO(indutny): move this to js-land - if (a->wait_) + if (a->wait_) { + a->messages_.PushFront(msg); // Push message back into the ready queue. break; + } - QUEUE_REMOVE(q); Local argv[] = { String::NewFromTwoByte(isolate, msg->data(), @@ -321,7 +310,7 @@ void Agent::ChildSignalCb(uv_async_t* signal) { void Agent::EnqueueMessage(AgentMessage* message) { uv_mutex_lock(&message_mutex_); - QUEUE_INSERT_TAIL(&messages_, &message->member); + messages_.PushBack(message); uv_mutex_unlock(&message_mutex_); uv_async_send(&child_signal_); } diff --git a/src/debug-agent.h b/src/debug-agent.h index 616fa9ff0d49bd..f18683a8287f39 100644 --- a/src/debug-agent.h +++ b/src/debug-agent.h @@ -22,10 +22,11 @@ #ifndef SRC_DEBUG_AGENT_H_ #define SRC_DEBUG_AGENT_H_ +#include "util.h" +#include "util-inl.h" #include "uv.h" #include "v8.h" #include "v8-debug.h" -#include "queue.h" #include @@ -37,7 +38,31 @@ class Environment; namespace node { namespace debugger { -class AgentMessage; +class AgentMessage { + public: + AgentMessage(uint16_t* val, int length) : length_(length) { + if (val == nullptr) { + data_ = val; + } else { + data_ = new uint16_t[length]; + memcpy(data_, val, length * sizeof(*data_)); + } + } + + ~AgentMessage() { + delete[] data_; + data_ = nullptr; + } + + inline const uint16_t* data() const { return data_; } + inline int length() const { return length_; } + + ListNode member; + + private: + uint16_t* data_; + int length_; +}; class Agent { public: @@ -100,37 +125,11 @@ class Agent { uv_loop_t child_loop_; v8::Persistent api_; - QUEUE messages_; + ListHead messages_; DispatchHandler dispatch_handler_; }; -class AgentMessage { - public: - AgentMessage(uint16_t* val, int length) : length_(length) { - if (val == nullptr) { - data_ = val; - } else { - data_ = new uint16_t[length]; - memcpy(data_, val, length * sizeof(*data_)); - } - } - - ~AgentMessage() { - delete[] data_; - data_ = nullptr; - } - - inline const uint16_t* data() const { return data_; } - inline int length() const { return length_; } - - QUEUE member; - - private: - uint16_t* data_; - int length_; -}; - } // namespace debugger } // namespace node diff --git a/src/env-inl.h b/src/env-inl.h index ac97f8ea172b4b..abe2a5a5260dd7 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -175,9 +175,6 @@ inline Environment::Environment(v8::Local context, set_binding_cache_object(v8::Object::New(isolate())); set_module_load_list_array(v8::Array::New(isolate())); RB_INIT(&cares_task_list_); - QUEUE_INIT(&req_wrap_queue_); - QUEUE_INIT(&handle_wrap_queue_); - QUEUE_INIT(&handle_cleanup_queue_); handle_cleanup_waiting_ = 0; } @@ -193,11 +190,7 @@ inline Environment::~Environment() { } inline void Environment::CleanupHandles() { - while (!QUEUE_EMPTY(&handle_cleanup_queue_)) { - QUEUE* q = QUEUE_HEAD(&handle_cleanup_queue_); - QUEUE_REMOVE(q); - - HandleCleanup* hc = ContainerOf(&HandleCleanup::handle_cleanup_queue_, q); + while (HandleCleanup* hc = handle_cleanup_queue_.PopFront()) { handle_cleanup_waiting_++; hc->cb_(this, hc->handle_, hc->arg_); delete hc; @@ -259,8 +252,7 @@ inline uv_check_t* Environment::idle_check_handle() { inline void Environment::RegisterHandleCleanup(uv_handle_t* handle, HandleCleanupCb cb, void *arg) { - HandleCleanup* hc = new HandleCleanup(handle, cb, arg); - QUEUE_INSERT_TAIL(&handle_cleanup_queue_, &hc->handle_cleanup_queue_); + handle_cleanup_queue_.PushBack(new HandleCleanup(handle, cb, arg)); } inline void Environment::FinishHandleCleanup(uv_handle_t* handle) { diff --git a/src/env.h b/src/env.h index f28d5ffad2a901..ccacbb09f52c2f 100644 --- a/src/env.h +++ b/src/env.h @@ -3,11 +3,12 @@ #include "ares.h" #include "debug-agent.h" +#include "handle_wrap.h" +#include "req-wrap.h" #include "tree.h" #include "util.h" #include "uv.h" #include "v8.h" -#include "queue.h" #include @@ -333,13 +334,12 @@ class Environment { : handle_(handle), cb_(cb), arg_(arg) { - QUEUE_INIT(&handle_cleanup_queue_); } uv_handle_t* handle_; HandleCleanupCb cb_; void* arg_; - QUEUE handle_cleanup_queue_; + ListNode handle_cleanup_queue_; }; static inline Environment* GetCurrent(v8::Isolate* isolate); @@ -453,8 +453,12 @@ class Environment { return &debugger_agent_; } - inline QUEUE* handle_wrap_queue() { return &handle_wrap_queue_; } - inline QUEUE* req_wrap_queue() { return &req_wrap_queue_; } + typedef ListHead HandleWrapQueue; + typedef ListHead, &ReqWrap::req_wrap_queue_> + ReqWrapQueue; + + inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; } + inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; } private: static const int kIsolateSlot = NODE_ISOLATE_SLOT; @@ -486,9 +490,10 @@ class Environment { bool printed_error_; debugger::Agent debugger_agent_; - QUEUE handle_wrap_queue_; - QUEUE req_wrap_queue_; - QUEUE handle_cleanup_queue_; + HandleWrapQueue handle_wrap_queue_; + ReqWrapQueue req_wrap_queue_; + ListHead handle_cleanup_queue_; int handle_cleanup_waiting_; v8::Persistent external_; diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index f0e5896372967f..70e7cbb12aca06 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -6,7 +6,6 @@ #include "util.h" #include "util-inl.h" #include "node.h" -#include "queue.h" namespace node { @@ -70,13 +69,12 @@ HandleWrap::HandleWrap(Environment* env, handle__->data = this; HandleScope scope(env->isolate()); Wrap(object, this); - QUEUE_INSERT_TAIL(env->handle_wrap_queue(), &handle_wrap_queue_); + env->handle_wrap_queue()->PushBack(this); } HandleWrap::~HandleWrap() { CHECK(persistent().IsEmpty()); - QUEUE_REMOVE(&handle_wrap_queue_); } diff --git a/src/handle_wrap.h b/src/handle_wrap.h index 901c12213d14b3..94cfe3d5586deb 100644 --- a/src/handle_wrap.h +++ b/src/handle_wrap.h @@ -2,14 +2,14 @@ #define SRC_HANDLE_WRAP_H_ #include "async-wrap.h" -#include "env.h" -#include "node.h" -#include "queue.h" +#include "util.h" #include "uv.h" #include "v8.h" namespace node { +class Environment; + // Rules: // // - Do not throw from handle methods. Set errno. @@ -51,9 +51,10 @@ class HandleWrap : public AsyncWrap { virtual ~HandleWrap() override; private: + friend class Environment; friend void GetActiveHandles(const v8::FunctionCallbackInfo&); static void OnClose(uv_handle_t* handle); - QUEUE handle_wrap_queue_; + ListNode handle_wrap_queue_; unsigned int flags_; // Using double underscore due to handle_ member in tcp_wrap. Probably // tcp_wrap should rename it's member to 'handle'. diff --git a/src/node.cc b/src/node.cc index c8299f9a3614b7..bffcd04cfd8b5e 100644 --- a/src/node.cc +++ b/src/node.cc @@ -33,7 +33,8 @@ #include "env.h" #include "env-inl.h" #include "handle_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "string_bytes.h" #include "util.h" #include "uv.h" @@ -1486,15 +1487,11 @@ static void GetActiveRequests(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Local ary = Array::New(args.GetIsolate()); - QUEUE* q = nullptr; int i = 0; - QUEUE_FOREACH(q, env->req_wrap_queue()) { - ReqWrap* w = ContainerOf(&ReqWrap::req_wrap_queue_, q); - if (w->persistent().IsEmpty()) - continue; - ary->Set(i++, w->object()); - } + for (auto w : *env->req_wrap_queue()) + if (w->persistent().IsEmpty() == false) + ary->Set(i++, w->object()); args.GetReturnValue().Set(ary); } @@ -1506,13 +1503,11 @@ void GetActiveHandles(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Local ary = Array::New(env->isolate()); - QUEUE* q = nullptr; int i = 0; Local owner_sym = env->owner_string(); - QUEUE_FOREACH(q, env->handle_wrap_queue()) { - HandleWrap* w = ContainerOf(&HandleWrap::handle_wrap_queue_, q); + for (auto w : *env->handle_wrap_queue()) { if (w->persistent().IsEmpty() || (w->flags_ & HandleWrap::kUnref)) continue; Local object = w->object(); diff --git a/src/node_file.cc b/src/node_file.cc index b05e9cd55985ba..35fd7d54f1b148 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -6,7 +6,8 @@ #include "env.h" #include "env-inl.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "string_bytes.h" #include "util.h" diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index fe2013bb680247..55d5f84ff49858 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -7,7 +7,8 @@ #include "node.h" #include "node_buffer.h" #include "node_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "stream_wrap.h" #include "util-inl.h" #include "util.h" diff --git a/src/queue.h b/src/queue.h deleted file mode 100644 index 075d37fd0a11e7..00000000000000 --- a/src/queue.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (c) 2013, Ben Noordhuis - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef SRC_QUEUE_H_ -#define SRC_QUEUE_H_ - -typedef void *QUEUE[2]; - -/* Private macros. */ -#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) -#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) -#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) -#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) - -/* Public macros. */ -#define QUEUE_DATA(ptr, type, field) \ - ((type *) ((char *) (ptr) - ((char *) &((type *) 0)->field))) - -#define QUEUE_FOREACH(q, h) \ - for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) - -#define QUEUE_EMPTY(q) \ - ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) - -#define QUEUE_HEAD(q) \ - (QUEUE_NEXT(q)) - -#define QUEUE_INIT(q) \ - do { \ - QUEUE_NEXT(q) = (q); \ - QUEUE_PREV(q) = (q); \ - } \ - while (0) - -#define QUEUE_ADD(h, n) \ - do { \ - QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ - QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV(h) = QUEUE_PREV(n); \ - QUEUE_PREV_NEXT(h) = (h); \ - } \ - while (0) - -#define QUEUE_SPLIT(h, q, n) \ - do { \ - QUEUE_PREV(n) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(n) = (n); \ - QUEUE_NEXT(n) = (q); \ - QUEUE_PREV(h) = QUEUE_PREV(q); \ - QUEUE_PREV_NEXT(h) = (h); \ - QUEUE_PREV(q) = (n); \ - } \ - while (0) - -#define QUEUE_INSERT_HEAD(h, q) \ - do { \ - QUEUE_NEXT(q) = QUEUE_NEXT(h); \ - QUEUE_PREV(q) = (h); \ - QUEUE_NEXT_PREV(q) = (q); \ - QUEUE_NEXT(h) = (q); \ - } \ - while (0) - -#define QUEUE_INSERT_TAIL(h, q) \ - do { \ - QUEUE_NEXT(q) = (h); \ - QUEUE_PREV(q) = QUEUE_PREV(h); \ - QUEUE_PREV_NEXT(q) = (q); \ - QUEUE_PREV(h) = (q); \ - } \ - while (0) - -#define QUEUE_REMOVE(q) \ - do { \ - QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ - QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ - } \ - while (0) - -#endif /* SRC_QUEUE_H_ */ diff --git a/src/req-wrap-inl.h b/src/req-wrap-inl.h new file mode 100644 index 00000000000000..78c6735302b19d --- /dev/null +++ b/src/req-wrap-inl.h @@ -0,0 +1,41 @@ +#ifndef SRC_REQ_WRAP_INL_H_ +#define SRC_REQ_WRAP_INL_H_ + +#include "req-wrap.h" +#include "async-wrap.h" +#include "async-wrap-inl.h" +#include "env.h" +#include "env-inl.h" +#include "util.h" +#include "util-inl.h" + +namespace node { + +template +ReqWrap::ReqWrap(Environment* env, + v8::Handle object, + AsyncWrap::ProviderType provider) + : AsyncWrap(env, object, provider) { + if (env->in_domain()) + object->Set(env->domain_string(), env->domain_array()->Get(0)); + + // FIXME(bnoordhuis) The fact that a reinterpret_cast is needed is + // arguably a good indicator that there should be more than one queue. + env->req_wrap_queue()->PushBack(reinterpret_cast*>(this)); +} + +template +ReqWrap::~ReqWrap() { + CHECK_EQ(req_.data, this); // Assert that someone has called Dispatched(). + CHECK_EQ(false, persistent().IsEmpty()); + persistent().Reset(); +} + +template +void ReqWrap::Dispatched() { + req_.data = this; +} + +} // namespace node + +#endif // SRC_REQ_WRAP_INL_H_ diff --git a/src/req-wrap.h b/src/req-wrap.h new file mode 100644 index 00000000000000..27b51425d1f737 --- /dev/null +++ b/src/req-wrap.h @@ -0,0 +1,30 @@ +#ifndef SRC_REQ_WRAP_H_ +#define SRC_REQ_WRAP_H_ + +#include "async-wrap.h" +#include "env.h" +#include "util.h" +#include "v8.h" + +namespace node { + +template +class ReqWrap : public AsyncWrap { + public: + inline ReqWrap(Environment* env, + v8::Handle object, + AsyncWrap::ProviderType provider); + inline ~ReqWrap() override; + inline void Dispatched(); // Call this after the req has been dispatched. + + private: + friend class Environment; + ListNode req_wrap_queue_; + + public: + T req_; // Must be last. TODO(bnoordhuis) Make private. +}; + +} // namespace node + +#endif // SRC_REQ_WRAP_H_ diff --git a/src/req_wrap.h b/src/req_wrap.h deleted file mode 100644 index 6ec0251434f0ee..00000000000000 --- a/src/req_wrap.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef SRC_REQ_WRAP_H_ -#define SRC_REQ_WRAP_H_ - -#include "async-wrap.h" -#include "async-wrap-inl.h" -#include "env.h" -#include "env-inl.h" -#include "queue.h" -#include "util.h" - -namespace node { - -template -class ReqWrap : public AsyncWrap { - public: - ReqWrap(Environment* env, - v8::Handle object, - AsyncWrap::ProviderType provider) - : AsyncWrap(env, object, provider) { - if (env->in_domain()) - object->Set(env->domain_string(), env->domain_array()->Get(0)); - - QUEUE_INSERT_TAIL(env->req_wrap_queue(), &req_wrap_queue_); - } - - - ~ReqWrap() override { - QUEUE_REMOVE(&req_wrap_queue_); - // Assert that someone has called Dispatched() - CHECK_EQ(req_.data, this); - CHECK_EQ(false, persistent().IsEmpty()); - persistent().Reset(); - } - - // Call this after the req has been dispatched. - void Dispatched() { - req_.data = this; - } - - // TODO(bnoordhuis) Make these private. - QUEUE req_wrap_queue_; - T req_; // *must* be last, GetActiveRequests() in node.cc depends on it -}; - - -} // namespace node - - -#endif // SRC_REQ_WRAP_H_ diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index 515030a019e932..a9f89e47bb9813 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -5,7 +5,8 @@ #include "node_buffer.h" #include "node_counters.h" #include "pipe_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "tcp_wrap.h" #include "udp_wrap.h" #include "util.h" diff --git a/src/stream_wrap.h b/src/stream_wrap.h index d9dd93b24bb4bb..5148228112eb1e 100644 --- a/src/stream_wrap.h +++ b/src/stream_wrap.h @@ -3,7 +3,8 @@ #include "env.h" #include "handle_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "string_bytes.h" #include "v8.h" diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 910cf4280edf85..3f011422ef8837 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -5,7 +5,8 @@ #include "handle_wrap.h" #include "node_buffer.h" #include "node_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "stream_wrap.h" #include "util.h" #include "util-inl.h" diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index bee38e390a54b7..9aafe3925dc8e2 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -57,10 +57,6 @@ TLSCallbacks::TLSCallbacks(Environment* env, node::Wrap(object(), this); MakeWeak(this); - // Initialize queue for clearIn writes - QUEUE_INIT(&write_item_queue_); - QUEUE_INIT(&pending_write_items_); - // We've our own session callbacks SSL_CTX_sess_set_get_cb(sc_->ctx_, SSLWrap::GetSessionCallback); SSL_CTX_sess_set_new_cb(sc_->ctx_, SSLWrap::NewSessionCallback); @@ -87,47 +83,26 @@ TLSCallbacks::~TLSCallbacks() { MakePending(); // And destroy - while (!QUEUE_EMPTY(&pending_write_items_)) { - QUEUE* q = QUEUE_HEAD(&pending_write_items_); - QUEUE_REMOVE(q); - - WriteItem* wi = ContainerOf(&WriteItem::member_, q); + while (WriteItem* wi = pending_write_items_.PopFront()) delete wi; - } ClearError(); } void TLSCallbacks::MakePending() { - // Aliases - QUEUE* from = &write_item_queue_; - QUEUE* to = &pending_write_items_; - - if (QUEUE_EMPTY(from)) - return; - - // Add items to pending - QUEUE_ADD(to, from); - - // Empty original queue - QUEUE_INIT(from); + write_item_queue_.MoveBack(&pending_write_items_); } bool TLSCallbacks::InvokeQueued(int status) { - if (QUEUE_EMPTY(&pending_write_items_)) + if (pending_write_items_.IsEmpty()) return false; // Process old queue - QUEUE queue; - QUEUE* q = QUEUE_HEAD(&pending_write_items_); - QUEUE_SPLIT(&pending_write_items_, q, &queue); - while (QUEUE_EMPTY(&queue) == false) { - q = QUEUE_HEAD(&queue); - QUEUE_REMOVE(q); - - WriteItem* wi = ContainerOf(&WriteItem::member_, q); + WriteItemList queue; + pending_write_items_.MoveBack(&queue); + while (WriteItem* wi = queue.PopFront()) { wi->cb_(&wi->w_->req_, status); delete wi; } @@ -300,7 +275,7 @@ void TLSCallbacks::EncOut() { return; // Split-off queue - if (established_ && !QUEUE_EMPTY(&write_item_queue_)) + if (established_ && !write_item_queue_.IsEmpty()) MakePending(); // No data to write @@ -533,8 +508,7 @@ int TLSCallbacks::DoWrite(WriteWrap* w, } // Queue callback to execute it on next tick - WriteItem* wi = new WriteItem(w, cb); - QUEUE_INSERT_TAIL(&write_item_queue_, &wi->member_); + write_item_queue_.PushBack(new WriteItem(w, cb)); // Write queued data if (empty) { diff --git a/src/tls_wrap.h b/src/tls_wrap.h index a4ac764fe2da00..3815878d586c15 100644 --- a/src/tls_wrap.h +++ b/src/tls_wrap.h @@ -6,8 +6,8 @@ #include "async-wrap.h" #include "env.h" -#include "queue.h" #include "stream_wrap.h" +#include "util.h" #include "v8.h" #include @@ -75,7 +75,7 @@ class TLSCallbacks : public crypto::SSLWrap, WriteWrap* w_; uv_write_cb cb_; - QUEUE member_; + ListNode member_; }; TLSCallbacks(Environment* env, @@ -131,8 +131,9 @@ class TLSCallbacks : public crypto::SSLWrap, uv_write_t write_req_; size_t write_size_; size_t write_queue_size_; - QUEUE write_item_queue_; - QUEUE pending_write_items_; + typedef ListHead WriteItemList; + WriteItemList write_item_queue_; + WriteItemList pending_write_items_; bool started_; bool established_; bool shutdown_; diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 0570d352bcc95a..08c50d911f7482 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -5,7 +5,8 @@ #include "handle_wrap.h" #include "node_buffer.h" #include "node_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "stream_wrap.h" #include "util.h" #include "util-inl.h" diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index 6138dac50ceadb..d57809cb1b405f 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -3,7 +3,8 @@ #include "env-inl.h" #include "node_buffer.h" #include "handle_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "util.h" #include "util-inl.h" diff --git a/src/udp_wrap.h b/src/udp_wrap.h index d491209d932a32..0a33ae8cb22530 100644 --- a/src/udp_wrap.h +++ b/src/udp_wrap.h @@ -4,7 +4,8 @@ #include "async-wrap.h" #include "env.h" #include "handle_wrap.h" -#include "req_wrap.h" +#include "req-wrap.h" +#include "req-wrap-inl.h" #include "uv.h" #include "v8.h" diff --git a/src/util-inl.h b/src/util-inl.h index 6e962feffaf3e1..75bdb4784aaaf3 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -5,6 +5,108 @@ namespace node { +template +ListNode::ListNode() : prev_(this), next_(this) {} + +template +ListNode::~ListNode() { + Remove(); +} + +template +void ListNode::Remove() { + prev_->next_ = next_; + next_->prev_ = prev_; + prev_ = this; + next_ = this; +} + +template +bool ListNode::IsEmpty() const { + return prev_ == this; +} + +template +ListHead::Iterator::Iterator(ListNode* node) : node_(node) {} + +template +T* ListHead::Iterator::operator*() const { + return ContainerOf(M, node_); +} + +template +const typename ListHead::Iterator& +ListHead::Iterator::operator++() { + node_ = node_->next_; + return *this; +} + +template +bool ListHead::Iterator::operator!=(const Iterator& that) const { + return node_ != that.node_; +} + +template +ListHead::~ListHead() { + while (IsEmpty() == false) + head_.next_->Remove(); +} + +template +void ListHead::MoveBack(ListHead* that) { + if (IsEmpty()) + return; + ListNode* to = &that->head_; + head_.next_->prev_ = to->prev_; + to->prev_->next_ = head_.next_; + head_.prev_->next_ = to; + to->prev_ = head_.prev_; + head_.prev_ = &head_; + head_.next_ = &head_; +} + +template +void ListHead::PushBack(T* element) { + ListNode* that = &(element->*M); + head_.prev_->next_ = that; + that->prev_ = head_.prev_; + that->next_ = &head_; + head_.prev_ = that; +} + +template +void ListHead::PushFront(T* element) { + ListNode* that = &(element->*M); + head_.next_->prev_ = that; + that->prev_ = &head_; + that->next_ = head_.next_; + head_.next_ = that; +} + +template +bool ListHead::IsEmpty() const { + return head_.IsEmpty(); +} + +template +T* ListHead::PopFront() { + if (IsEmpty()) + return nullptr; + ListNode* node = head_.next_; + node->Remove(); + return ContainerOf(M, node); +} + +template +typename ListHead::Iterator ListHead::begin() const { + return Iterator(head_.next_); +} + +template +typename ListHead::Iterator ListHead::end() const { + return Iterator(const_cast*>(&head_)); +} + template ContainerOfHelper::ContainerOfHelper(Inner Outer::*field, Inner* pointer) diff --git a/src/util.h b/src/util.h index e0fa0fd0096bcc..5742252688111b 100644 --- a/src/util.h +++ b/src/util.h @@ -45,6 +45,69 @@ namespace node { #define UNREACHABLE() abort() +// TAILQ-style intrusive list node. +template +class ListNode; + +template +using ListNodeMember = ListNode T::*; + +// VS 2013 doesn't understand dependent templates. +#ifdef _MSC_VER +#define ListNodeMember(T) ListNodeMember +#else +#define ListNodeMember(T) ListNodeMember +#endif + +// TAILQ-style intrusive list head. +template +class ListHead; + +template +class ListNode { + public: + inline ListNode(); + inline ~ListNode(); + inline void Remove(); + inline bool IsEmpty() const; + + private: + template friend class ListHead; + ListNode* prev_; + ListNode* next_; + DISALLOW_COPY_AND_ASSIGN(ListNode); +}; + +template +class ListHead { + public: + class Iterator { + public: + inline T* operator*() const; + inline const Iterator& operator++(); + inline bool operator!=(const Iterator& that) const; + + private: + friend class ListHead; + inline explicit Iterator(ListNode* node); + ListNode* node_; + }; + + inline ListHead() = default; + inline ~ListHead(); + inline void MoveBack(ListHead* that); + inline void PushBack(T* element); + inline void PushFront(T* element); + inline bool IsEmpty() const; + inline T* PopFront(); + inline Iterator begin() const; + inline Iterator end() const; + + private: + ListNode head_; + DISALLOW_COPY_AND_ASSIGN(ListHead); +}; + // The helper is for doing safe downcasts from base types to derived types. template class ContainerOfHelper {