|
|
@ -59,10 +59,14 @@ namespace node { |
|
|
|
return scope.Close(Integer::New(-1)); \ |
|
|
|
} |
|
|
|
|
|
|
|
#define SLAB_SIZE (1024 * 1024) |
|
|
|
#define MIN(a, b) ((a) < (b) ? (a) : (b)) |
|
|
|
|
|
|
|
// TODO share with tcp_wrap.cc
|
|
|
|
Persistent<String> address_symbol; |
|
|
|
Persistent<String> port_symbol; |
|
|
|
Persistent<String> buffer_sym; |
|
|
|
static Persistent<String> udp_slab_sym; |
|
|
|
|
|
|
|
void AddressToJS(Handle<Object> info, |
|
|
|
const sockaddr* addr, |
|
|
@ -70,6 +74,12 @@ void AddressToJS(Handle<Object> info, |
|
|
|
|
|
|
|
typedef ReqWrap<uv_udp_send_t> SendWrap; |
|
|
|
|
|
|
|
|
|
|
|
static size_t slab_used; |
|
|
|
size_t slab_offset_; |
|
|
|
static uv_handle_t* handle_that_last_alloced; |
|
|
|
|
|
|
|
|
|
|
|
class UDPWrap: public HandleWrap { |
|
|
|
public: |
|
|
|
static void Initialize(Handle<Object> target); |
|
|
@ -83,6 +93,8 @@ public: |
|
|
|
static Handle<Value> GetSockName(const Arguments& args); |
|
|
|
|
|
|
|
private: |
|
|
|
static inline char* NewSlab(v8::Handle<v8::Object> global, v8::Handle<v8::Object> wrap_obj); |
|
|
|
|
|
|
|
UDPWrap(Handle<Object> object); |
|
|
|
virtual ~UDPWrap(); |
|
|
|
|
|
|
@ -118,6 +130,7 @@ void UDPWrap::Initialize(Handle<Object> target) { |
|
|
|
|
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
udp_slab_sym = Persistent<String>::New(String::NewSymbol("udpslab")); |
|
|
|
buffer_sym = NODE_PSYMBOL("buffer"); |
|
|
|
port_symbol = NODE_PSYMBOL("port"); |
|
|
|
address_symbol = NODE_PSYMBOL("address"); |
|
|
@ -149,7 +162,6 @@ Handle<Value> UDPWrap::New(const Arguments& args) { |
|
|
|
return scope.Close(args.This()); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> UDPWrap::DoBind(const Arguments& args, int family) { |
|
|
|
HandleScope scope; |
|
|
|
int r; |
|
|
@ -332,13 +344,44 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) { |
|
|
|
|
|
|
|
|
|
|
|
uv_buf_t UDPWrap::OnAlloc(uv_handle_t* handle, size_t suggested_size) { |
|
|
|
// FIXME switch to slab allocation, share with stream_wrap.cc
|
|
|
|
return uv_buf_init(new char[suggested_size], suggested_size); |
|
|
|
} |
|
|
|
HandleScope scope; |
|
|
|
|
|
|
|
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data); |
|
|
|
|
|
|
|
char* slab = NULL; |
|
|
|
|
|
|
|
Handle<Object> global = Context::GetCurrent()->Global(); |
|
|
|
Local<Value> slab_v = global->GetHiddenValue(udp_slab_sym); |
|
|
|
|
|
|
|
if (slab_v.IsEmpty()) { |
|
|
|
// No slab currently. Create a new one.
|
|
|
|
slab = NewSlab(global, wrap->object_); |
|
|
|
} else { |
|
|
|
// Use existing slab.
|
|
|
|
Local<Object> slab_obj = slab_v->ToObject(); |
|
|
|
slab = Buffer::Data(slab_obj); |
|
|
|
assert(Buffer::Length(slab_obj) == SLAB_SIZE); |
|
|
|
assert(SLAB_SIZE >= slab_used); |
|
|
|
|
|
|
|
// If less than 64kb is remaining on the slab allocate a new one.
|
|
|
|
if (SLAB_SIZE - slab_used < 64 * 1024) { |
|
|
|
slab = NewSlab(global, wrap->object_); |
|
|
|
} else { |
|
|
|
wrap->object_->SetHiddenValue(udp_slab_sym, slab_obj); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
uv_buf_t buf; |
|
|
|
buf.base = slab + slab_used; |
|
|
|
buf.len = MIN(SLAB_SIZE - slab_used, suggested_size); |
|
|
|
|
|
|
|
slab_offset_ = slab_used; |
|
|
|
slab_used += buf.len; |
|
|
|
|
|
|
|
handle_that_last_alloced = reinterpret_cast<uv_handle_t*>(handle); |
|
|
|
|
|
|
|
return buf; |
|
|
|
|
|
|
|
static void ReleaseMemory(char* data, void* arg) { |
|
|
|
delete[] data; // data == buf.base
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -348,7 +391,6 @@ void UDPWrap::OnRecv(uv_udp_t* handle, |
|
|
|
struct sockaddr* addr, |
|
|
|
unsigned flags) { |
|
|
|
if (nread == 0) { |
|
|
|
ReleaseMemory(buf.base, NULL); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
@ -365,18 +407,26 @@ void UDPWrap::OnRecv(uv_udp_t* handle, |
|
|
|
|
|
|
|
if (nread == -1) { |
|
|
|
SetErrno(uv_last_error(uv_default_loop())); |
|
|
|
ReleaseMemory(buf.base, NULL); |
|
|
|
} |
|
|
|
else { |
|
|
|
Local<Object> rinfo = Object::New(); |
|
|
|
AddressToJS(rinfo, addr, sizeof *addr); |
|
|
|
argv[2] = Buffer::New(buf.base, nread, ReleaseMemory, NULL)->handle_; |
|
|
|
argv[2] = Buffer::New(buf.base, nread, NULL, NULL)->handle_; |
|
|
|
argv[3] = rinfo; |
|
|
|
} |
|
|
|
|
|
|
|
MakeCallback(wrap->object_, "onmessage", ARRAY_SIZE(argv), argv); |
|
|
|
} |
|
|
|
|
|
|
|
inline char* UDPWrap::NewSlab(Handle<Object> global, |
|
|
|
Handle<Object> wrap_obj) { |
|
|
|
Buffer* b = Buffer::New(SLAB_SIZE); |
|
|
|
global->SetHiddenValue(udp_slab_sym, b->handle_); |
|
|
|
assert(Buffer::Length(b) == SLAB_SIZE); |
|
|
|
slab_used = 0; |
|
|
|
wrap_obj->SetHiddenValue(udp_slab_sym, b->handle_); |
|
|
|
return Buffer::Data(b); |
|
|
|
} |
|
|
|
|
|
|
|
void AddressToJS(Handle<Object> info, |
|
|
|
const sockaddr* addr, |
|
|
|