Browse Source

src: switch from QUEUE to intrusive list

This commit also breaks up req_wrap.h into req-wrap.h and req-wrap-inl.h
to work around a circular dependency issue in env.h.

PR-URL: https://github.com/iojs/io.js/pull/667
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
v1.8.0-commit
Ben Noordhuis 10 years ago
parent
commit
38dc0cd8f4
  1. 3
      node.gyp
  2. 3
      src/async-wrap.h
  3. 2
      src/base-object-inl.h
  4. 3
      src/base-object.h
  5. 3
      src/cares_wrap.cc
  6. 23
      src/debug-agent.cc
  7. 57
      src/debug-agent.h
  8. 12
      src/env-inl.h
  9. 21
      src/env.h
  10. 4
      src/handle_wrap.cc
  11. 9
      src/handle_wrap.h
  12. 17
      src/node.cc
  13. 3
      src/node_file.cc
  14. 3
      src/pipe_wrap.cc
  15. 41
      src/req-wrap-inl.h
  16. 30
      src/req-wrap.h
  17. 49
      src/req_wrap.h
  18. 3
      src/stream_wrap.cc
  19. 3
      src/stream_wrap.h
  20. 3
      src/tcp_wrap.cc
  21. 42
      src/tls_wrap.cc
  22. 9
      src/tls_wrap.h
  23. 3
      src/tty_wrap.cc
  24. 3
      src/udp_wrap.cc
  25. 3
      src/udp_wrap.h

3
node.gyp

@ -149,7 +149,8 @@
'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',

3
src/async-wrap.h

@ -2,7 +2,6 @@
#define SRC_ASYNC_WRAP_H_
#include "base-object.h"
#include "env.h"
#include "v8.h"
namespace node {
@ -31,6 +30,8 @@ namespace node {
V(WRITEWRAP) \
V(ZLIB)
class Environment;
class AsyncWrap : public BaseObject {
public:
enum ProviderType {

2
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"

3
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<v8::Object> handle);

3
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"

23
src/debug-agent.cc

@ -29,7 +29,6 @@
#include "v8-debug.h"
#include "util.h"
#include "util-inl.h"
#include "queue.h"
#include <string.h>
@ -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<Object> 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<Value> 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_);
}

57
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 <string.h>
@ -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<AgentMessage> member;
private:
uint16_t* data_;
int length_;
};
class Agent {
public:
@ -100,37 +125,11 @@ class Agent {
uv_loop_t child_loop_;
v8::Persistent<v8::Object> api_;
QUEUE messages_;
ListHead<AgentMessage, &AgentMessage::member> 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

12
src/env-inl.h

@ -175,9 +175,6 @@ inline Environment::Environment(v8::Local<v8::Context> 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) {

21
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 <stdint.h>
@ -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<HandleCleanup> 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<HandleWrap, &HandleWrap::handle_wrap_queue_> HandleWrapQueue;
typedef ListHead<ReqWrap<uv_req_t>, &ReqWrap<uv_req_t>::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<HandleCleanup,
&HandleCleanup::handle_cleanup_queue_> handle_cleanup_queue_;
int handle_cleanup_waiting_;
v8::Persistent<v8::External> external_;

4
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_);
}

9
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<v8::Value>&);
static void OnClose(uv_handle_t* handle);
QUEUE handle_wrap_queue_;
ListNode<HandleWrap> 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'.

17
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<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Array> ary = Array::New(args.GetIsolate());
QUEUE* q = nullptr;
int i = 0;
QUEUE_FOREACH(q, env->req_wrap_queue()) {
ReqWrap<uv_req_t>* w = ContainerOf(&ReqWrap<uv_req_t>::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<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Local<Array> ary = Array::New(env->isolate());
QUEUE* q = nullptr;
int i = 0;
Local<String> 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> object = w->object();

3
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"

3
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"

41
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 <typename T>
ReqWrap<T>::ReqWrap(Environment* env,
v8::Handle<v8::Object> 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<ReqWrap<uv_req_t>*>(this));
}
template <typename T>
ReqWrap<T>::~ReqWrap() {
CHECK_EQ(req_.data, this); // Assert that someone has called Dispatched().
CHECK_EQ(false, persistent().IsEmpty());
persistent().Reset();
}
template <typename T>
void ReqWrap<T>::Dispatched() {
req_.data = this;
}
} // namespace node
#endif // SRC_REQ_WRAP_INL_H_

30
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 <typename T>
class ReqWrap : public AsyncWrap {
public:
inline ReqWrap(Environment* env,
v8::Handle<v8::Object> object,
AsyncWrap::ProviderType provider);
inline ~ReqWrap() override;
inline void Dispatched(); // Call this after the req has been dispatched.
private:
friend class Environment;
ListNode<ReqWrap> req_wrap_queue_;
public:
T req_; // Must be last. TODO(bnoordhuis) Make private.
};
} // namespace node
#endif // SRC_REQ_WRAP_H_

49
src/req_wrap.h

@ -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 <typename T>
class ReqWrap : public AsyncWrap {
public:
ReqWrap(Environment* env,
v8::Handle<v8::Object> 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_

3
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"

3
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"

3
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"

42
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<TLSCallbacks>::GetSessionCallback);
SSL_CTX_sess_set_new_cb(sc_->ctx_, SSLWrap<TLSCallbacks>::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) {

9
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 <openssl/ssl.h>
@ -75,7 +75,7 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
WriteWrap* w_;
uv_write_cb cb_;
QUEUE member_;
ListNode<WriteItem> member_;
};
TLSCallbacks(Environment* env,
@ -131,8 +131,9 @@ class TLSCallbacks : public crypto::SSLWrap<TLSCallbacks>,
uv_write_t write_req_;
size_t write_size_;
size_t write_queue_size_;
QUEUE write_item_queue_;
QUEUE pending_write_items_;
typedef ListHead<WriteItem, &WriteItem::member_> WriteItemList;
WriteItemList write_item_queue_;
WriteItemList pending_write_items_;
bool started_;
bool established_;
bool shutdown_;

3
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"

3
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"

3
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"

Loading…
Cancel
Save