stream_wrap: introduce StreamWrapCallbacks
StreamWrapCallbacks is a helper class for incepting into uv_stream_t* management process.
This commit is contained in:
parent
6978e998ee
commit
4c48a39c65
@ -56,23 +56,6 @@ using v8::String;
|
|||||||
using v8::TryCatch;
|
using v8::TryCatch;
|
||||||
using v8::Value;
|
using v8::Value;
|
||||||
|
|
||||||
typedef class ReqWrap<uv_shutdown_t> ShutdownWrap;
|
|
||||||
|
|
||||||
class WriteWrap: public ReqWrap<uv_write_t> {
|
|
||||||
public:
|
|
||||||
void* operator new(size_t size, char* storage) { return storage; }
|
|
||||||
|
|
||||||
// This is just to keep the compiler happy. It should never be called, since
|
|
||||||
// we don't use exceptions in node.
|
|
||||||
void operator delete(void* ptr, char* storage) { assert(0); }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// People should not be using the non-placement new and delete operator on a
|
|
||||||
// WriteWrap. Ensure this never happens.
|
|
||||||
void* operator new (size_t size) { assert(0); };
|
|
||||||
void operator delete(void* ptr) { assert(0); };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Persistent<String> buffer_sym;
|
static Persistent<String> buffer_sym;
|
||||||
static Persistent<String> bytes_sym;
|
static Persistent<String> bytes_sym;
|
||||||
@ -110,8 +93,10 @@ void StreamWrap::Initialize(Handle<Object> target) {
|
|||||||
|
|
||||||
|
|
||||||
StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream)
|
StreamWrap::StreamWrap(Handle<Object> object, uv_stream_t* stream)
|
||||||
: HandleWrap(object, reinterpret_cast<uv_handle_t*>(stream)) {
|
: HandleWrap(object, reinterpret_cast<uv_handle_t*>(stream)),
|
||||||
|
default_callbacks_(this) {
|
||||||
stream_ = stream;
|
stream_ = stream;
|
||||||
|
callbacks_ = &default_callbacks_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -173,8 +158,8 @@ Handle<Value> StreamWrap::ReadStop(const Arguments& args) {
|
|||||||
uv_buf_t StreamWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) {
|
uv_buf_t StreamWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) {
|
||||||
StreamWrap* wrap = static_cast<StreamWrap*>(handle->data);
|
StreamWrap* wrap = static_cast<StreamWrap*>(handle->data);
|
||||||
assert(wrap->stream_ == reinterpret_cast<uv_stream_t*>(handle));
|
assert(wrap->stream_ == reinterpret_cast<uv_stream_t*>(handle));
|
||||||
char* buf = slab_allocator->Allocate(wrap->object_, suggested_size);
|
|
||||||
return uv_buf_init(buf, suggested_size);
|
return wrap->callbacks_->DoAlloc(handle, suggested_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -200,8 +185,10 @@ static Local<Object> AcceptHandle(uv_stream_t* pipe) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
|
void StreamWrap::OnReadCommon(uv_stream_t* handle,
|
||||||
uv_buf_t buf, uv_handle_type pending) {
|
ssize_t nread,
|
||||||
|
uv_buf_t buf,
|
||||||
|
uv_handle_type pending) {
|
||||||
HandleScope scope(node_isolate);
|
HandleScope scope(node_isolate);
|
||||||
|
|
||||||
StreamWrap* wrap = static_cast<StreamWrap*>(handle->data);
|
StreamWrap* wrap = static_cast<StreamWrap*>(handle->data);
|
||||||
@ -210,56 +197,16 @@ void StreamWrap::OnReadCommon(uv_stream_t* handle, ssize_t nread,
|
|||||||
// uv_close() on the handle.
|
// uv_close() on the handle.
|
||||||
assert(wrap->object_.IsEmpty() == false);
|
assert(wrap->object_.IsEmpty() == false);
|
||||||
|
|
||||||
if (nread < 0) {
|
if (nread > 0) {
|
||||||
// If libuv reports an error or EOF it *may* give us a buffer back. In that
|
if (wrap->stream_->type == UV_TCP) {
|
||||||
// case, return the space to the slab.
|
NODE_COUNT_NET_BYTES_RECV(nread);
|
||||||
if (buf.base != NULL) {
|
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
||||||
slab_allocator->Shrink(wrap->object_, buf.base, 0);
|
NODE_COUNT_PIPE_BYTES_RECV(nread);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetErrno(uv_last_error(uv_default_loop()));
|
|
||||||
MakeCallback(wrap->object_, onread_sym, 0, NULL);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(buf.base != NULL);
|
assert(buf.base != NULL);
|
||||||
Local<Object> slab = slab_allocator->Shrink(wrap->object_,
|
wrap->callbacks_->DoRead(handle, nread, buf, pending);
|
||||||
buf.base,
|
|
||||||
nread);
|
|
||||||
|
|
||||||
if (nread == 0) return;
|
|
||||||
assert(static_cast<size_t>(nread) <= buf.len);
|
|
||||||
|
|
||||||
int argc = 3;
|
|
||||||
Local<Value> argv[4] = {
|
|
||||||
slab,
|
|
||||||
Integer::NewFromUnsigned(buf.base - Buffer::Data(slab), node_isolate),
|
|
||||||
Integer::NewFromUnsigned(nread, node_isolate)
|
|
||||||
};
|
|
||||||
|
|
||||||
Local<Object> pending_obj;
|
|
||||||
if (pending == UV_TCP) {
|
|
||||||
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(handle);
|
|
||||||
} else if (pending == UV_NAMED_PIPE) {
|
|
||||||
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(handle);
|
|
||||||
} else if (pending == UV_UDP) {
|
|
||||||
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(handle);
|
|
||||||
} else {
|
|
||||||
assert(pending == UV_UNKNOWN_HANDLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pending_obj.IsEmpty()) {
|
|
||||||
argv[3] = pending_obj;
|
|
||||||
argc++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wrap->stream_->type == UV_TCP) {
|
|
||||||
NODE_COUNT_NET_BYTES_RECV(nread);
|
|
||||||
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
|
||||||
NODE_COUNT_PIPE_BYTES_RECV(nread);
|
|
||||||
}
|
|
||||||
|
|
||||||
MakeCallback(wrap->object_, onread_sym, argc, argv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -294,37 +241,29 @@ Handle<Value> StreamWrap::WriteBuffer(const Arguments& args) {
|
|||||||
assert(args.Length() >= 1 && Buffer::HasInstance(args[0]));
|
assert(args.Length() >= 1 && Buffer::HasInstance(args[0]));
|
||||||
size_t length = Buffer::Length(args[0]);
|
size_t length = Buffer::Length(args[0]);
|
||||||
char* storage = new char[sizeof(WriteWrap)];
|
char* storage = new char[sizeof(WriteWrap)];
|
||||||
WriteWrap* req_wrap = new (storage) WriteWrap();
|
WriteWrap* req_wrap = new (storage) WriteWrap(wrap);
|
||||||
|
|
||||||
req_wrap->object_->SetHiddenValue(buffer_sym, args[0]);
|
req_wrap->object_->SetHiddenValue(buffer_sym, args[0]);
|
||||||
|
|
||||||
uv_buf_t buf;
|
uv_buf_t buf;
|
||||||
WriteBuffer(args[0], &buf);
|
WriteBuffer(args[0], &buf);
|
||||||
|
|
||||||
int r = uv_write(&req_wrap->req_,
|
int r = wrap->callbacks_->DoWrite(req_wrap,
|
||||||
wrap->stream_,
|
&buf,
|
||||||
&buf,
|
1,
|
||||||
1,
|
NULL,
|
||||||
StreamWrap::AfterWrite);
|
StreamWrap::AfterWrite);
|
||||||
|
|
||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
req_wrap->object_->Set(bytes_sym,
|
req_wrap->object_->Set(bytes_sym,
|
||||||
Integer::NewFromUnsigned(length, node_isolate));
|
Integer::NewFromUnsigned(length, node_isolate));
|
||||||
|
|
||||||
wrap->UpdateWriteQueueSize();
|
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(uv_default_loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
req_wrap->~WriteWrap();
|
req_wrap->~WriteWrap();
|
||||||
delete[] storage;
|
delete[] storage;
|
||||||
return scope.Close(v8::Null(node_isolate));
|
return scope.Close(v8::Null(node_isolate));
|
||||||
} else {
|
} else {
|
||||||
if (wrap->stream_->type == UV_TCP) {
|
|
||||||
NODE_COUNT_NET_BYTES_SENT(length);
|
|
||||||
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
|
||||||
NODE_COUNT_PIPE_BYTES_SENT(length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,7 +298,7 @@ Handle<Value> StreamWrap::WriteStringImpl(const Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char* storage = new char[sizeof(WriteWrap) + storage_size + 15];
|
char* storage = new char[sizeof(WriteWrap) + storage_size + 15];
|
||||||
WriteWrap* req_wrap = new (storage) WriteWrap();
|
WriteWrap* req_wrap = new (storage) WriteWrap(wrap);
|
||||||
|
|
||||||
char* data = reinterpret_cast<char*>(ROUND_UP(
|
char* data = reinterpret_cast<char*>(ROUND_UP(
|
||||||
reinterpret_cast<uintptr_t>(storage) + sizeof(WriteWrap), 16));
|
reinterpret_cast<uintptr_t>(storage) + sizeof(WriteWrap), 16));
|
||||||
@ -378,12 +317,11 @@ Handle<Value> StreamWrap::WriteStringImpl(const Arguments& args) {
|
|||||||
reinterpret_cast<uv_pipe_t*>(wrap->stream_)->ipc;
|
reinterpret_cast<uv_pipe_t*>(wrap->stream_)->ipc;
|
||||||
|
|
||||||
if (!ipc_pipe) {
|
if (!ipc_pipe) {
|
||||||
r = uv_write(&req_wrap->req_,
|
r = wrap->callbacks_->DoWrite(req_wrap,
|
||||||
wrap->stream_,
|
&buf,
|
||||||
&buf,
|
1,
|
||||||
1,
|
NULL,
|
||||||
StreamWrap::AfterWrite);
|
StreamWrap::AfterWrite);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
uv_handle_t* send_handle = NULL;
|
uv_handle_t* send_handle = NULL;
|
||||||
|
|
||||||
@ -403,31 +341,22 @@ Handle<Value> StreamWrap::WriteStringImpl(const Arguments& args) {
|
|||||||
req_wrap->object_->Set(handle_sym, send_handle_obj);
|
req_wrap->object_->Set(handle_sym, send_handle_obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = uv_write2(&req_wrap->req_,
|
r = wrap->callbacks_->DoWrite(req_wrap,
|
||||||
wrap->stream_,
|
&buf,
|
||||||
&buf,
|
1,
|
||||||
1,
|
reinterpret_cast<uv_stream_t*>(send_handle),
|
||||||
reinterpret_cast<uv_stream_t*>(send_handle),
|
StreamWrap::AfterWrite);
|
||||||
StreamWrap::AfterWrite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
req_wrap->object_->Set(bytes_sym, Number::New((uint32_t) data_size));
|
req_wrap->object_->Set(bytes_sym, Number::New((uint32_t) data_size));
|
||||||
|
|
||||||
wrap->UpdateWriteQueueSize();
|
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(uv_default_loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
req_wrap->~WriteWrap();
|
req_wrap->~WriteWrap();
|
||||||
delete[] storage;
|
delete[] storage;
|
||||||
return scope.Close(v8::Null(node_isolate));
|
return scope.Close(v8::Null(node_isolate));
|
||||||
} else {
|
} else {
|
||||||
if (wrap->stream_->type == UV_TCP) {
|
|
||||||
NODE_COUNT_NET_BYTES_SENT(buf.len);
|
|
||||||
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
|
||||||
NODE_COUNT_PIPE_BYTES_SENT(buf.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -483,7 +412,7 @@ Handle<Value> StreamWrap::Writev(const Arguments& args) {
|
|||||||
|
|
||||||
storage_size += sizeof(WriteWrap);
|
storage_size += sizeof(WriteWrap);
|
||||||
char* storage = new char[storage_size];
|
char* storage = new char[storage_size];
|
||||||
WriteWrap* req_wrap = new (storage) WriteWrap();
|
WriteWrap* req_wrap = new (storage) WriteWrap(wrap);
|
||||||
|
|
||||||
uint32_t bytes = 0;
|
uint32_t bytes = 0;
|
||||||
size_t offset = sizeof(WriteWrap);
|
size_t offset = sizeof(WriteWrap);
|
||||||
@ -513,11 +442,11 @@ Handle<Value> StreamWrap::Writev(const Arguments& args) {
|
|||||||
bytes += str_size;
|
bytes += str_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int r = uv_write(&req_wrap->req_,
|
int r = wrap->callbacks_->DoWrite(req_wrap,
|
||||||
wrap->stream_,
|
bufs,
|
||||||
bufs,
|
count,
|
||||||
count,
|
NULL,
|
||||||
StreamWrap::AfterWrite);
|
StreamWrap::AfterWrite);
|
||||||
|
|
||||||
// Deallocate space
|
// Deallocate space
|
||||||
if (bufs != bufs_)
|
if (bufs != bufs_)
|
||||||
@ -526,20 +455,12 @@ Handle<Value> StreamWrap::Writev(const Arguments& args) {
|
|||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
req_wrap->object_->Set(bytes_sym, Number::New(bytes));
|
req_wrap->object_->Set(bytes_sym, Number::New(bytes));
|
||||||
|
|
||||||
wrap->UpdateWriteQueueSize();
|
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
SetErrno(uv_last_error(uv_default_loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
req_wrap->~WriteWrap();
|
req_wrap->~WriteWrap();
|
||||||
delete[] storage;
|
delete[] storage;
|
||||||
return scope.Close(v8::Null(node_isolate));
|
return scope.Close(v8::Null(node_isolate));
|
||||||
} else {
|
} else {
|
||||||
if (wrap->stream_->type == UV_TCP) {
|
|
||||||
NODE_COUNT_NET_BYTES_SENT(bytes);
|
|
||||||
} else if (wrap->stream_->type == UV_NAMED_PIPE) {
|
|
||||||
NODE_COUNT_PIPE_BYTES_SENT(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return scope.Close(req_wrap->object_);
|
return scope.Close(req_wrap->object_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,8 +482,8 @@ Handle<Value> StreamWrap::WriteUcs2String(const Arguments& args) {
|
|||||||
|
|
||||||
|
|
||||||
void StreamWrap::AfterWrite(uv_write_t* req, int status) {
|
void StreamWrap::AfterWrite(uv_write_t* req, int status) {
|
||||||
WriteWrap* req_wrap = (WriteWrap*) req->data;
|
WriteWrap* req_wrap = container_of(req, WriteWrap, req_);
|
||||||
StreamWrap* wrap = (StreamWrap*) req->handle->data;
|
StreamWrap* wrap = req_wrap->wrap_;
|
||||||
|
|
||||||
HandleScope scope(node_isolate);
|
HandleScope scope(node_isolate);
|
||||||
|
|
||||||
@ -579,7 +500,7 @@ void StreamWrap::AfterWrite(uv_write_t* req, int status) {
|
|||||||
SetErrno(uv_last_error(uv_default_loop()));
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
wrap->UpdateWriteQueueSize();
|
wrap->callbacks_->AfterWrite(req_wrap);
|
||||||
|
|
||||||
Local<Value> argv[] = {
|
Local<Value> argv[] = {
|
||||||
Integer::New(status, node_isolate),
|
Integer::New(status, node_isolate),
|
||||||
@ -601,7 +522,7 @@ Handle<Value> StreamWrap::Shutdown(const Arguments& args) {
|
|||||||
|
|
||||||
ShutdownWrap* req_wrap = new ShutdownWrap();
|
ShutdownWrap* req_wrap = new ShutdownWrap();
|
||||||
|
|
||||||
int r = uv_shutdown(&req_wrap->req_, wrap->stream_, AfterShutdown);
|
int r = wrap->callbacks_->DoShutdown(req_wrap, AfterShutdown);
|
||||||
|
|
||||||
req_wrap->Dispatched();
|
req_wrap->Dispatched();
|
||||||
|
|
||||||
@ -641,4 +562,103 @@ void StreamWrap::AfterShutdown(uv_shutdown_t* req, int status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int StreamWrapCallbacks::DoWrite(WriteWrap* w,
|
||||||
|
uv_buf_t* bufs,
|
||||||
|
size_t count,
|
||||||
|
uv_stream_t* send_handle,
|
||||||
|
uv_write_cb cb) {
|
||||||
|
int r;
|
||||||
|
if (send_handle == NULL) {
|
||||||
|
r = uv_write(&w->req_, wrap_->stream_, bufs, count, cb);
|
||||||
|
} else {
|
||||||
|
r = uv_write2(&w->req_, wrap_->stream_, bufs, count, send_handle, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!r) {
|
||||||
|
size_t bytes = 0;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
bytes += bufs[i].len;
|
||||||
|
if (wrap_->stream_->type == UV_TCP) {
|
||||||
|
NODE_COUNT_NET_BYTES_SENT(bytes);
|
||||||
|
} else if (wrap_->stream_->type == UV_NAMED_PIPE) {
|
||||||
|
NODE_COUNT_PIPE_BYTES_SENT(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap_->UpdateWriteQueueSize();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StreamWrapCallbacks::AfterWrite(WriteWrap* w) {
|
||||||
|
wrap_->UpdateWriteQueueSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uv_buf_t StreamWrapCallbacks::DoAlloc(uv_handle_t* handle,
|
||||||
|
size_t suggested_size) {
|
||||||
|
char* buf = slab_allocator->Allocate(wrap_->object_, suggested_size);
|
||||||
|
return uv_buf_init(buf, suggested_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StreamWrapCallbacks::DoRead(uv_stream_t* handle,
|
||||||
|
ssize_t nread,
|
||||||
|
uv_buf_t buf,
|
||||||
|
uv_handle_type pending) {
|
||||||
|
HandleScope scope(node_isolate);
|
||||||
|
|
||||||
|
if (nread < 0) {
|
||||||
|
// If libuv reports an error or EOF it *may* give us a buffer back. In that
|
||||||
|
// case, return the space to the slab.
|
||||||
|
if (buf.base != NULL)
|
||||||
|
slab_allocator->Shrink(Self(), buf.base, 0);
|
||||||
|
|
||||||
|
SetErrno(uv_last_error(uv_default_loop()));
|
||||||
|
MakeCallback(Self(), onread_sym, 0, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Local<Object> slab = slab_allocator->Shrink(wrap_->object_, buf.base, nread);
|
||||||
|
|
||||||
|
if (nread == 0) return;
|
||||||
|
assert(static_cast<size_t>(nread) <= buf.len);
|
||||||
|
|
||||||
|
int argc = 3;
|
||||||
|
Local<Value> argv[4] = {
|
||||||
|
slab,
|
||||||
|
Integer::NewFromUnsigned(buf.base - Buffer::Data(slab), node_isolate),
|
||||||
|
Integer::NewFromUnsigned(nread, node_isolate)
|
||||||
|
};
|
||||||
|
|
||||||
|
Local<Object> pending_obj;
|
||||||
|
if (pending == UV_TCP) {
|
||||||
|
pending_obj = AcceptHandle<TCPWrap, uv_tcp_t>(handle);
|
||||||
|
} else if (pending == UV_NAMED_PIPE) {
|
||||||
|
pending_obj = AcceptHandle<PipeWrap, uv_pipe_t>(handle);
|
||||||
|
} else if (pending == UV_UDP) {
|
||||||
|
pending_obj = AcceptHandle<UDPWrap, uv_udp_t>(handle);
|
||||||
|
} else {
|
||||||
|
assert(pending == UV_UNKNOWN_HANDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pending_obj.IsEmpty()) {
|
||||||
|
argv[3] = pending_obj;
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
MakeCallback(wrap_->object_, onread_sym, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int StreamWrapCallbacks::DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb) {
|
||||||
|
return uv_shutdown(&req_wrap->req_, wrap_->stream_, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Object> StreamWrapCallbacks::Self() {
|
||||||
|
return wrap_->object_;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,18 +25,83 @@
|
|||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "handle_wrap.h"
|
#include "handle_wrap.h"
|
||||||
|
#include "req_wrap.h"
|
||||||
#include "string_bytes.h"
|
#include "string_bytes.h"
|
||||||
|
|
||||||
namespace node {
|
namespace node {
|
||||||
|
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
class WriteWrap;
|
class StreamWrap;
|
||||||
|
|
||||||
|
typedef class ReqWrap<uv_shutdown_t> ShutdownWrap;
|
||||||
|
|
||||||
|
class WriteWrap: public ReqWrap<uv_write_t> {
|
||||||
|
public:
|
||||||
|
explicit WriteWrap(StreamWrap* wrap) {
|
||||||
|
wrap_ = wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* operator new(size_t size, char* storage) { return storage; }
|
||||||
|
|
||||||
|
// This is just to keep the compiler happy. It should never be called, since
|
||||||
|
// we don't use exceptions in node.
|
||||||
|
void operator delete(void* ptr, char* storage) { assert(0); }
|
||||||
|
|
||||||
|
StreamWrap* wrap_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// People should not be using the non-placement new and delete operator on a
|
||||||
|
// WriteWrap. Ensure this never happens.
|
||||||
|
void* operator new(size_t size) { assert(0); };
|
||||||
|
void operator delete(void* ptr) { assert(0); };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Overridable callbacks' types
|
||||||
|
class StreamWrapCallbacks {
|
||||||
|
public:
|
||||||
|
explicit StreamWrapCallbacks(StreamWrap* wrap) : wrap_(wrap) {
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit StreamWrapCallbacks(StreamWrapCallbacks* old) : wrap_(old->wrap_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~StreamWrapCallbacks() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int DoWrite(WriteWrap* w,
|
||||||
|
uv_buf_t* bufs,
|
||||||
|
size_t count,
|
||||||
|
uv_stream_t* send_handle,
|
||||||
|
uv_write_cb cb);
|
||||||
|
virtual void AfterWrite(WriteWrap* w);
|
||||||
|
virtual uv_buf_t DoAlloc(uv_handle_t* handle, size_t suggested_size);
|
||||||
|
virtual void DoRead(uv_stream_t* handle,
|
||||||
|
ssize_t nread,
|
||||||
|
uv_buf_t buf,
|
||||||
|
uv_handle_type pending);
|
||||||
|
virtual int DoShutdown(ShutdownWrap* req_wrap, uv_shutdown_cb cb);
|
||||||
|
|
||||||
|
v8::Handle<v8::Object> Self();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
StreamWrap* wrap_;
|
||||||
|
};
|
||||||
|
|
||||||
class StreamWrap : public HandleWrap {
|
class StreamWrap : public HandleWrap {
|
||||||
public:
|
public:
|
||||||
uv_stream_t* GetStream() { return stream_; }
|
uv_stream_t* GetStream() { return stream_; }
|
||||||
|
|
||||||
|
void OverrideCallbacks(StreamWrapCallbacks* callbacks) {
|
||||||
|
StreamWrapCallbacks* old = callbacks_;
|
||||||
|
callbacks_ = callbacks;
|
||||||
|
if (old != &default_callbacks_)
|
||||||
|
delete old;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamWrapCallbacks* GetCallbacks() {
|
||||||
|
return callbacks_;
|
||||||
|
}
|
||||||
|
|
||||||
static void Initialize(v8::Handle<v8::Object> target);
|
static void Initialize(v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
static v8::Handle<v8::Value> GetFD(v8::Local<v8::String>,
|
static v8::Handle<v8::Value> GetFD(v8::Local<v8::String>,
|
||||||
@ -53,10 +118,19 @@ class StreamWrap : public HandleWrap {
|
|||||||
static v8::Handle<v8::Value> WriteUtf8String(const v8::Arguments& args);
|
static v8::Handle<v8::Value> WriteUtf8String(const v8::Arguments& args);
|
||||||
static v8::Handle<v8::Value> WriteUcs2String(const v8::Arguments& args);
|
static v8::Handle<v8::Value> WriteUcs2String(const v8::Arguments& args);
|
||||||
|
|
||||||
|
// Overridable callbacks
|
||||||
|
StreamWrapCallbacks* callbacks_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static size_t WriteBuffer(v8::Handle<v8::Value> val, uv_buf_t* buf);
|
static size_t WriteBuffer(v8::Handle<v8::Value> val, uv_buf_t* buf);
|
||||||
|
|
||||||
StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
|
StreamWrap(v8::Handle<v8::Object> object, uv_stream_t* stream);
|
||||||
|
~StreamWrap() {
|
||||||
|
if (callbacks_ != &default_callbacks_) {
|
||||||
|
delete callbacks_;
|
||||||
|
callbacks_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
void StateChange() { }
|
void StateChange() { }
|
||||||
void UpdateWriteQueueSize();
|
void UpdateWriteQueueSize();
|
||||||
|
|
||||||
@ -79,6 +153,9 @@ class StreamWrap : public HandleWrap {
|
|||||||
|
|
||||||
size_t slab_offset_;
|
size_t slab_offset_;
|
||||||
uv_stream_t* stream_;
|
uv_stream_t* stream_;
|
||||||
|
|
||||||
|
StreamWrapCallbacks default_callbacks_;
|
||||||
|
friend class StreamWrapCallbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user