Abstract out HandleWrap class
authorRyan Dahl <ry@tinyclouds.org>
Mon, 18 Jul 2011 11:22:16 +0000 (04:22 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Mon, 18 Jul 2011 11:22:16 +0000 (04:22 -0700)
src/handle_wrap.cc [new file with mode: 0644]
src/handle_wrap.h [new file with mode: 0644]
src/stream_wrap.cc
src/stream_wrap.h
src/tcp_wrap.cc
src/timer_wrap.cc
wscript

diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc
new file mode 100644 (file)
index 0000000..c34c1c2
--- /dev/null
@@ -0,0 +1,89 @@
+#include <node.h>
+#include <handle_wrap.h>
+
+namespace node {
+
+using v8::Object;
+using v8::Handle;
+using v8::Local;
+using v8::Persistent;
+using v8::Value;
+using v8::HandleScope;
+using v8::FunctionTemplate;
+using v8::String;
+using v8::Function;
+using v8::TryCatch;
+using v8::Context;
+using v8::Arguments;
+using v8::Integer;
+
+
+#define UNWRAP \
+  assert(!args.Holder().IsEmpty()); \
+  assert(args.Holder()->InternalFieldCount() > 0); \
+  HandleWrap* wrap =  \
+      static_cast<HandleWrap*>(args.Holder()->GetPointerFromInternalField(0)); \
+  if (!wrap) { \
+    SetErrno(UV_EBADF); \
+    return scope.Close(Integer::New(-1)); \
+  }
+
+
+void HandleWrap::Initialize(Handle<Object> target) {
+  /* Doesn't do anything at the moment. */
+}
+
+
+Handle<Value> HandleWrap::Close(const Arguments& args) {
+  HandleScope scope;
+
+  UNWRAP
+
+  assert(!wrap->object_.IsEmpty());
+  int r = uv_close(wrap->handle__, OnClose);
+
+  wrap->StateChange();
+
+  if (r) {
+    SetErrno(uv_last_error().code);
+
+    wrap->object_->SetPointerInInternalField(0, NULL);
+    wrap->object_.Dispose();
+    wrap->object_.Clear();
+  }
+  return scope.Close(Integer::New(r));
+}
+
+
+HandleWrap::HandleWrap(Handle<Object> object, uv_handle_t* h) {
+  handle__ = h;
+  h->data = this;
+
+  HandleScope scope;
+  assert(object_.IsEmpty());
+  assert(object->InternalFieldCount() > 0);
+  object_ = v8::Persistent<v8::Object>::New(object);
+  object_->SetPointerInInternalField(0, this);
+}
+
+
+HandleWrap::~HandleWrap() {
+  assert(object_.IsEmpty());
+}
+
+
+void HandleWrap::OnClose(uv_handle_t* handle) {
+  HandleWrap* wrap = static_cast<HandleWrap*>(handle->data);
+
+  // The wrap object should still be there.
+  assert(wrap->object_.IsEmpty() == false);
+
+  wrap->object_->SetPointerInInternalField(0, NULL);
+  wrap->object_.Dispose();
+  wrap->object_.Clear();
+
+  delete wrap;
+}
+
+
+}  // namespace node
diff --git a/src/handle_wrap.h b/src/handle_wrap.h
new file mode 100644 (file)
index 0000000..2c51799
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef HANDLE_WRAP_H_
+#define HANDLE_WRAP_H_
+
+namespace node {
+
+class HandleWrap {
+  public:
+    static void Initialize(v8::Handle<v8::Object> target);
+    static v8::Handle<v8::Value> Close(const v8::Arguments& args);
+
+  protected:
+    HandleWrap(v8::Handle<v8::Object> object, uv_handle_t* handle);
+    virtual ~HandleWrap();
+
+    virtual void StateChange() {}
+
+    v8::Persistent<v8::Object> object_;
+
+  private:
+    static void OnClose(uv_handle_t* handle);
+    // Using double underscore due to handle_ member in tcp_wrap. Probably
+    // tcp_wrap should rename it's member to 'handle'.
+    uv_handle_t* handle__;
+};
+
+
+}  // namespace node
+
+
+#endif  // HANDLE_WRAP_H_
index df509c4..3da51d9 100644 (file)
@@ -1,5 +1,6 @@
 #include <node.h>
 #include <node_buffer.h>
+#include <handle_wrap.h>
 #include <stream_wrap.h>
 #include <req_wrap.h>
 
@@ -43,10 +44,10 @@ typedef class ReqWrap<uv_write_t> WriteWrap;
 
 static size_t slab_used;
 static uv_stream_t* handle_that_last_alloced;
-Persistent<String> slab_sym;
-Persistent<String> buffer_sym;
-Persistent<String> write_queue_size_sym;
-bool initialized;
+static Persistent<String> slab_sym;
+static Persistent<String> buffer_sym;
+static Persistent<String> write_queue_size_sym;
+static bool initialized;
 
 
 void StreamWrap::Initialize(Handle<Object> target) {
@@ -58,6 +59,8 @@ void StreamWrap::Initialize(Handle<Object> target) {
 
   HandleScope scope;
 
+  HandleWrap::Initialize(target);
+
   slab_sym = Persistent<String>::New(String::NewSymbol("slab"));
   buffer_sym = Persistent<String>::New(String::NewSymbol("buffer"));
   write_queue_size_sym =
@@ -65,40 +68,15 @@ void StreamWrap::Initialize(Handle<Object> target) {
 }
 
 
-StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream) {
-  HandleScope scope;
-
+StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream)
+    : HandleWrap(object, (uv_handle_t*)stream) {
   stream_ = stream;
   stream->data = this;
 
-  assert(object_.IsEmpty());
-  assert(object->InternalFieldCount() > 0);
-  object_ = v8::Persistent<v8::Object>::New(object);
-  object_->SetPointerInInternalField(0, this);
-
   UpdateWriteQueueSize();
 }
 
 
-StreamWrap::~StreamWrap() {
-  assert(object_.IsEmpty());
-}
-
-
-// Free the C++ object on the close callback.
-void StreamWrap::OnClose(uv_handle_t* handle) {
-  StreamWrap* wrap = static_cast<StreamWrap*>(handle->data);
-
-  // The wrap object should still be there.
-  assert(wrap->object_.IsEmpty() == false);
-
-  wrap->object_->SetPointerInInternalField(0, NULL);
-  wrap->object_.Dispose();
-  wrap->object_.Clear();
-  delete wrap;
-}
-
-
 void StreamWrap::UpdateWriteQueueSize() {
   object_->Set(write_queue_size_sym, Integer::New(stream_->write_queue_size));
 }
@@ -224,25 +202,6 @@ void StreamWrap::OnRead(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
   }
 }
 
-// TODO: share me?
-Handle<Value> StreamWrap::Close(const Arguments& args) {
-  HandleScope scope;
-
-  UNWRAP
-
-  assert(!wrap->object_.IsEmpty());
-  int r = uv_close((uv_handle_t*) wrap->stream_, OnClose);
-
-  if (r) {
-    SetErrno(uv_last_error().code);
-
-    wrap->object_->SetPointerInInternalField(0, NULL);
-    wrap->object_.Dispose();
-    wrap->object_.Clear();
-  }
-  return scope.Close(Integer::New(r));
-}
-
 
 Handle<Value> StreamWrap::Write(const Arguments& args) {
   HandleScope scope;
index fb233a4..d1b442f 100644 (file)
@@ -1,9 +1,13 @@
 #ifndef STREAM_WRAP_H_
 #define STREAM_WRAP_H_
 
+#include <v8.h>
+#include <node.h>
+#include <handle_wrap.h>
+
 namespace node {
 
-class StreamWrap {
+class StreamWrap : public HandleWrap {
  public:
   static void Initialize(v8::Handle<v8::Object> target);
 
@@ -12,13 +16,11 @@ class StreamWrap {
   static v8::Handle<v8::Value> ReadStart(const v8::Arguments& args);
   static v8::Handle<v8::Value> ReadStop(const v8::Arguments& args);
   static v8::Handle<v8::Value> Shutdown(const v8::Arguments& args);
-  static v8::Handle<v8::Value> Close(const v8::Arguments& args);
 
  protected:
   StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
-  ~StreamWrap();
-
-  v8::Persistent<v8::Object> object_;
+  virtual ~StreamWrap() { }
+  void StateChange() { }
 
  private:
   void UpdateWriteQueueSize();
@@ -29,7 +31,6 @@ class StreamWrap {
   static uv_buf_t OnAlloc(uv_stream_t* handle, size_t suggested_size);
   static void OnRead(uv_stream_t* handle, ssize_t nread, uv_buf_t buf);
   static void AfterShutdown(uv_shutdown_t* req, int status);
-  static void OnClose(uv_handle_t* handle);
 
   size_t slab_offset_;
   uv_stream_t* stream_;
index cbeb4a3..fd4552c 100644 (file)
@@ -1,6 +1,7 @@
 #include <node.h>
 #include <node_buffer.h>
 #include <req_wrap.h>
+#include <handle_wrap.h>
 #include <stream_wrap.h>
 
 // Temporary hack: libuv should provide uv_inet_pton and uv_inet_ntop.
@@ -75,10 +76,11 @@ static Persistent<String> port_symbol;
 typedef class ReqWrap<uv_connect_t> ConnectWrap;
 
 
-class TCPWrap : StreamWrap {
+class TCPWrap : public StreamWrap {
  public:
 
   static void Initialize(Handle<Object> target) {
+    HandleWrap::Initialize(target);
     StreamWrap::Initialize(target);
 
     HandleScope scope;
@@ -88,11 +90,12 @@ class TCPWrap : StreamWrap {
 
     t->InstanceTemplate()->SetInternalFieldCount(1);
 
+    NODE_SET_PROTOTYPE_METHOD(t, "close", HandleWrap::Close);
+
     NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
     NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
     NODE_SET_PROTOTYPE_METHOD(t, "write", StreamWrap::Write);
     NODE_SET_PROTOTYPE_METHOD(t, "shutdown", StreamWrap::Shutdown);
-    NODE_SET_PROTOTYPE_METHOD(t, "close", StreamWrap::Close);
 
     NODE_SET_PROTOTYPE_METHOD(t, "bind", Bind);
     NODE_SET_PROTOTYPE_METHOD(t, "listen", Listen);
index 87ccbe2..3d45946 100644 (file)
@@ -1,4 +1,5 @@
 #include <node.h>
+#include <handle_wrap.h>
 
 // Rules:
 //
@@ -48,21 +49,24 @@ using v8::Arguments;
 using v8::Integer;
 
 
-class TimerWrap {
+class TimerWrap : public HandleWrap {
  public:
   static void Initialize(Handle<Object> target) {
     HandleScope scope;
 
+    HandleWrap::Initialize(target);
+
     Local<FunctionTemplate> constructor = FunctionTemplate::New(New);
     constructor->InstanceTemplate()->SetInternalFieldCount(1);
     constructor->SetClassName(String::NewSymbol("Timer"));
 
+    NODE_SET_PROTOTYPE_METHOD(constructor, "close", HandleWrap::Close);
+
     NODE_SET_PROTOTYPE_METHOD(constructor, "start", Start);
     NODE_SET_PROTOTYPE_METHOD(constructor, "stop", Stop);
     NODE_SET_PROTOTYPE_METHOD(constructor, "setRepeat", SetRepeat);
     NODE_SET_PROTOTYPE_METHOD(constructor, "getRepeat", GetRepeat);
     NODE_SET_PROTOTYPE_METHOD(constructor, "again", Again);
-    NODE_SET_PROTOTYPE_METHOD(constructor, "close", Close);
 
     target->Set(String::NewSymbol("Timer"), constructor->GetFunction());
   }
@@ -81,16 +85,11 @@ class TimerWrap {
     return scope.Close(args.This());
   }
 
-  TimerWrap(Handle<Object> object) {
+  TimerWrap(Handle<Object> object)
+      : HandleWrap(object, (uv_handle_t*) &handle_) {
     active_ = false;
     int r = uv_timer_init(&handle_);
     handle_.data = this;
-    assert(r == 0); // How do we proxy this error up to javascript?
-                    // Suggestion: uv_timer_init() returns void.
-    assert(object_.IsEmpty());
-    assert(object->InternalFieldCount() > 0);
-    object_ = v8::Persistent<v8::Object>::New(object);
-    object_->SetPointerInInternalField(0, this);
 
     // uv_timer_init adds a loop reference. (That is, it calls uv_ref.) This
     // is not the behavior we want in Node. Timers should not increase the
@@ -100,7 +99,6 @@ class TimerWrap {
 
   ~TimerWrap() {
     if (!active_) uv_ref();
-    assert(object_.IsEmpty());
   }
 
   void StateChange() {
@@ -118,12 +116,6 @@ class TimerWrap {
     }
   }
 
-  // Free the C++ object on the close callback.
-  static void OnClose(uv_handle_t* handle) {
-    TimerWrap* wrap = static_cast<TimerWrap*>(handle->data);
-    delete wrap;
-  }
-
   static Handle<Value> Start(const Arguments& args) {
     HandleScope scope;
 
@@ -194,26 +186,6 @@ class TimerWrap {
     return scope.Close(Integer::New(repeat));
   }
 
-  // TODO: share me?
-  static Handle<Value> Close(const Arguments& args) {
-    HandleScope scope;
-
-    UNWRAP
-
-    int r = uv_close((uv_handle_t*) &wrap->handle_, OnClose);
-
-    if (r) SetErrno(uv_last_error().code);
-
-    wrap->StateChange();
-
-    assert(!wrap->object_.IsEmpty());
-    wrap->object_->SetPointerInInternalField(0, NULL);
-    wrap->object_.Dispose();
-    wrap->object_.Clear();
-
-    return scope.Close(Integer::New(r));
-  }
-
   static void OnTimeout(uv_timer_t* handle, int status) {
     HandleScope scope;
 
@@ -227,7 +199,6 @@ class TimerWrap {
   }
 
   uv_timer_t handle_;
-  Persistent<Object> object_;
   // This member is set false initially. When the timer is turned
   // on uv_ref is called. When the timer is turned off uv_unref is
   // called. Used to mirror libev semantics.
diff --git a/wscript b/wscript
index 7212a6a..65ee411 100644 (file)
--- a/wscript
+++ b/wscript
@@ -846,6 +846,7 @@ def build(bld):
     src/node_dtrace.cc
     src/node_string.cc
     src/timer_wrap.cc
+    src/handle_wrap.cc
     src/stream_wrap.cc
     src/tcp_wrap.cc
     src/pipe_wrap.cc