uv: upgrade to 28234d7
This commit is contained in:
parent
be2320d408
commit
145aa636b9
2
deps/uv/AUTHORS
vendored
2
deps/uv/AUTHORS
vendored
@ -29,3 +29,5 @@ Fedor Indutny <fedor.indutny@gmail.com>
|
|||||||
Saúl Ibarra Corretgé <saghul@gmail.com>
|
Saúl Ibarra Corretgé <saghul@gmail.com>
|
||||||
Felix Geisendörfer <felix@debuggable.com>
|
Felix Geisendörfer <felix@debuggable.com>
|
||||||
Yuki OKUMURA <mjt@cltn.org>
|
Yuki OKUMURA <mjt@cltn.org>
|
||||||
|
Roman Shtylman <shtylman@gmail.com>
|
||||||
|
Frank DENIS <github@pureftpd.org>
|
||||||
|
43
deps/uv/include/uv-private/uv-win.h
vendored
43
deps/uv/include/uv-private/uv-win.h
vendored
@ -104,6 +104,27 @@
|
|||||||
DWORD dwFlags);
|
DWORD dwFlags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef int (WSAAPI* LPFN_WSARECV)
|
||||||
|
(SOCKET socket,
|
||||||
|
LPWSABUF buffers,
|
||||||
|
DWORD buffer_count,
|
||||||
|
LPDWORD bytes,
|
||||||
|
LPDWORD flags,
|
||||||
|
LPWSAOVERLAPPED overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE
|
||||||
|
completion_routine);
|
||||||
|
|
||||||
|
typedef int (WSAAPI* LPFN_WSARECVFROM)
|
||||||
|
(SOCKET socket,
|
||||||
|
LPWSABUF buffers,
|
||||||
|
DWORD buffer_count,
|
||||||
|
LPDWORD bytes,
|
||||||
|
LPDWORD flags,
|
||||||
|
struct sockaddr* addr,
|
||||||
|
LPINT addr_len,
|
||||||
|
LPWSAOVERLAPPED overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* It should be possible to cast uv_buf_t[] to WSABUF[]
|
* It should be possible to cast uv_buf_t[] to WSABUF[]
|
||||||
@ -169,7 +190,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
|||||||
struct uv_req_s* next_req;
|
struct uv_req_s* next_req;
|
||||||
|
|
||||||
#define UV_WRITE_PRIVATE_FIELDS \
|
#define UV_WRITE_PRIVATE_FIELDS \
|
||||||
int ipc_header;
|
int ipc_header; \
|
||||||
|
uv_buf_t write_buffer; \
|
||||||
|
HANDLE event_handle; \
|
||||||
|
HANDLE wait_handle;
|
||||||
|
|
||||||
#define UV_CONNECT_PRIVATE_FIELDS \
|
#define UV_CONNECT_PRIVATE_FIELDS \
|
||||||
/* empty */
|
/* empty */
|
||||||
@ -194,7 +218,13 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
|||||||
HANDLE event_handle; \
|
HANDLE event_handle; \
|
||||||
HANDLE wait_handle; \
|
HANDLE wait_handle; \
|
||||||
struct uv_tcp_accept_s* next_pending; \
|
struct uv_tcp_accept_s* next_pending; \
|
||||||
} uv_tcp_accept_t;
|
} uv_tcp_accept_t; \
|
||||||
|
\
|
||||||
|
typedef struct uv_read_s { \
|
||||||
|
UV_REQ_FIELDS \
|
||||||
|
HANDLE event_handle; \
|
||||||
|
HANDLE wait_handle; \
|
||||||
|
} uv_read_t;
|
||||||
|
|
||||||
#define uv_stream_connection_fields \
|
#define uv_stream_connection_fields \
|
||||||
unsigned int write_reqs_pending; \
|
unsigned int write_reqs_pending; \
|
||||||
@ -205,7 +235,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
|||||||
|
|
||||||
#define UV_STREAM_PRIVATE_FIELDS \
|
#define UV_STREAM_PRIVATE_FIELDS \
|
||||||
unsigned int reqs_pending; \
|
unsigned int reqs_pending; \
|
||||||
uv_req_t read_req; \
|
uv_read_t read_req; \
|
||||||
union { \
|
union { \
|
||||||
struct { uv_stream_connection_fields }; \
|
struct { uv_stream_connection_fields }; \
|
||||||
struct { uv_stream_server_fields }; \
|
struct { uv_stream_server_fields }; \
|
||||||
@ -236,7 +266,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
|||||||
struct sockaddr_storage recv_from; \
|
struct sockaddr_storage recv_from; \
|
||||||
int recv_from_len; \
|
int recv_from_len; \
|
||||||
uv_udp_recv_cb recv_cb; \
|
uv_udp_recv_cb recv_cb; \
|
||||||
uv_alloc_cb alloc_cb;
|
uv_alloc_cb alloc_cb; \
|
||||||
|
LPFN_WSARECV func_wsarecv; \
|
||||||
|
LPFN_WSARECVFROM func_wsarecvfrom;
|
||||||
|
|
||||||
#define uv_pipe_server_fields \
|
#define uv_pipe_server_fields \
|
||||||
uv_pipe_accept_t accept_reqs[4]; \
|
uv_pipe_accept_t accept_reqs[4]; \
|
||||||
@ -247,7 +279,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
|||||||
uv_write_t ipc_header_write_req; \
|
uv_write_t ipc_header_write_req; \
|
||||||
int ipc_pid; \
|
int ipc_pid; \
|
||||||
uint64_t remaining_ipc_rawdata_bytes; \
|
uint64_t remaining_ipc_rawdata_bytes; \
|
||||||
WSAPROTOCOL_INFOW* pending_socket_info;
|
WSAPROTOCOL_INFOW* pending_socket_info; \
|
||||||
|
uv_write_t* non_overlapped_writes_tail;
|
||||||
|
|
||||||
#define UV_PIPE_PRIVATE_FIELDS \
|
#define UV_PIPE_PRIVATE_FIELDS \
|
||||||
HANDLE handle; \
|
HANDLE handle; \
|
||||||
|
2
deps/uv/include/uv.h
vendored
2
deps/uv/include/uv.h
vendored
@ -610,7 +610,7 @@ int uv_udp_send6(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[],
|
|||||||
int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb send_cb);
|
int bufcnt, struct sockaddr_in6 addr, uv_udp_send_cb send_cb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send data. If the socket has not previously been bound with `uv_udp_bind`
|
* Receive data. If the socket has not previously been bound with `uv_udp_bind`
|
||||||
* or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address)
|
* or `uv_udp_bind6`, it is bound to 0.0.0.0 (the "all interfaces" address)
|
||||||
* and a random port number.
|
* and a random port number.
|
||||||
*
|
*
|
||||||
|
11
deps/uv/src/ares/ares_init.c
vendored
11
deps/uv/src/ares/ares_init.c
vendored
@ -696,17 +696,20 @@ static int get_iphlpapi_dns_info (char *ret_buf, size_t ret_size)
|
|||||||
struct sockaddr_in6 *pIPv6Addr = ( struct sockaddr_in6 * ) pGenericAddr;
|
struct sockaddr_in6 *pIPv6Addr = ( struct sockaddr_in6 * ) pGenericAddr;
|
||||||
ares_inet_ntop( AF_INET6, &pIPv6Addr->sin6_addr, ret, ipv6_size - 1 ); /* -1 for comma */
|
ares_inet_ntop( AF_INET6, &pIPv6Addr->sin6_addr, ret, ipv6_size - 1 ); /* -1 for comma */
|
||||||
|
|
||||||
|
stringlen = strlen( ret );
|
||||||
|
|
||||||
|
/* Windows apparently always reports some IPv6 DNS servers that
|
||||||
|
prefixed with fec0:0:0:ffff. These ususally do not point to
|
||||||
|
working DNS servers, so we ignore them. */
|
||||||
|
if (strncmp(ret, "fec0:0:0:ffff:", 14) != 0) {
|
||||||
/* Append a comma to the end, THEN NULL. Should be OK because we
|
/* Append a comma to the end, THEN NULL. Should be OK because we
|
||||||
already tested the size at the top of the if statement. */
|
already tested the size at the top of the if statement. */
|
||||||
stringlen = strlen( ret );
|
|
||||||
ret[ stringlen ] = ',';
|
ret[ stringlen ] = ',';
|
||||||
ret[ stringlen + 1 ] = '\0';
|
ret[ stringlen + 1 ] = '\0';
|
||||||
ret += stringlen + 1;
|
ret += stringlen + 1;
|
||||||
left -= ret - ret_buf;
|
left -= ret - ret_buf;
|
||||||
++count;
|
++count;
|
||||||
|
}
|
||||||
/* NB on Windows this also returns stuff in the fec0::/10 range,
|
|
||||||
seems to be hard-coded somehow. Do we need to ignore them? */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
deps/uv/src/unix/linux.c
vendored
4
deps/uv/src/unix/linux.c
vendored
@ -144,6 +144,9 @@ static void uv__inotify_read(EV_P_ ev_io* w, int revents) {
|
|||||||
filename = e->len ? e->name : basename_r(handle->filename);
|
filename = e->len ? e->name : basename_r(handle->filename);
|
||||||
|
|
||||||
handle->cb(handle, filename, events, 0);
|
handle->cb(handle, filename, events, 0);
|
||||||
|
|
||||||
|
if (handle->fd == -1)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (handle->fd != -1); /* handle might've been closed by callback */
|
while (handle->fd != -1); /* handle might've been closed by callback */
|
||||||
@ -198,4 +201,5 @@ void uv__fs_event_destroy(uv_fs_event_t* handle) {
|
|||||||
uv__close(handle->fd);
|
uv__close(handle->fd);
|
||||||
handle->fd = -1;
|
handle->fd = -1;
|
||||||
free(handle->filename);
|
free(handle->filename);
|
||||||
|
handle->filename = NULL;
|
||||||
}
|
}
|
||||||
|
2
deps/uv/src/unix/stream.c
vendored
2
deps/uv/src/unix/stream.c
vendored
@ -209,8 +209,8 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
|||||||
if (uv__stream_open(streamClient, streamServer->accepted_fd,
|
if (uv__stream_open(streamClient, streamServer->accepted_fd,
|
||||||
UV_READABLE | UV_WRITABLE)) {
|
UV_READABLE | UV_WRITABLE)) {
|
||||||
/* TODO handle error */
|
/* TODO handle error */
|
||||||
streamServer->accepted_fd = -1;
|
|
||||||
uv__close(streamServer->accepted_fd);
|
uv__close(streamServer->accepted_fd);
|
||||||
|
streamServer->accepted_fd = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
deps/uv/src/win/internal.h
vendored
31
deps/uv/src/win/internal.h
vendored
@ -65,6 +65,7 @@ void uv_process_timers(uv_loop_t* loop);
|
|||||||
#define UV_HANDLE_ZERO_READ 0x40000
|
#define UV_HANDLE_ZERO_READ 0x40000
|
||||||
#define UV_HANDLE_TTY_RAW 0x80000
|
#define UV_HANDLE_TTY_RAW 0x80000
|
||||||
#define UV_HANDLE_EMULATE_IOCP 0x100000
|
#define UV_HANDLE_EMULATE_IOCP 0x100000
|
||||||
|
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x200000
|
||||||
|
|
||||||
void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
|
void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle);
|
||||||
void uv_process_endgames(uv_loop_t* loop);
|
void uv_process_endgames(uv_loop_t* loop);
|
||||||
@ -307,14 +308,40 @@ uv_err_code uv_translate_sys_error(int sys_errno);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialization for the windows and winsock api
|
* Winapi and ntapi utility functions
|
||||||
*/
|
*/
|
||||||
void uv_winapi_init();
|
void uv_winapi_init();
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Winsock utility functions
|
||||||
|
*/
|
||||||
void uv_winsock_init();
|
void uv_winsock_init();
|
||||||
|
|
||||||
int uv_ntstatus_to_winsock_error(NTSTATUS status);
|
int uv_ntstatus_to_winsock_error(NTSTATUS status);
|
||||||
|
|
||||||
|
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
|
||||||
|
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
|
||||||
|
|
||||||
/* Threads and synchronization */
|
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||||
|
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||||
|
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||||
|
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
|
||||||
|
int* addr_len, WSAOVERLAPPED *overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
|
||||||
|
|
||||||
|
/* Whether ipv6 is supported */
|
||||||
|
extern int uv_allow_ipv6;
|
||||||
|
|
||||||
|
/* Ip address used to bind to any port at any interface */
|
||||||
|
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||||
|
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Threads and synchronization
|
||||||
|
*/
|
||||||
typedef struct uv_once_s {
|
typedef struct uv_once_s {
|
||||||
unsigned char ran;
|
unsigned char ran;
|
||||||
/* The actual event handle must be aligned to sizeof(HANDLE), so in */
|
/* The actual event handle must be aligned to sizeof(HANDLE), so in */
|
||||||
|
290
deps/uv/src/win/pipe.c
vendored
290
deps/uv/src/win/pipe.c
vendored
@ -79,6 +79,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
|||||||
handle->remaining_ipc_rawdata_bytes = 0;
|
handle->remaining_ipc_rawdata_bytes = 0;
|
||||||
handle->pending_socket_info = NULL;
|
handle->pending_socket_info = NULL;
|
||||||
handle->ipc = ipc;
|
handle->ipc = ipc;
|
||||||
|
handle->non_overlapped_writes_tail = NULL;
|
||||||
|
|
||||||
uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
|
uv_req_init(loop, (uv_req_t*) &handle->ipc_header_write_req);
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
|||||||
|
|
||||||
static void uv_pipe_connection_init(uv_pipe_t* handle) {
|
static void uv_pipe_connection_init(uv_pipe_t* handle) {
|
||||||
uv_connection_init((uv_stream_t*) handle);
|
uv_connection_init((uv_stream_t*) handle);
|
||||||
|
handle->read_req.data = handle;
|
||||||
handle->eof_timer = NULL;
|
handle->eof_timer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,17 +151,37 @@ done:
|
|||||||
|
|
||||||
static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle,
|
static int uv_set_pipe_handle(uv_loop_t* loop, uv_pipe_t* handle,
|
||||||
HANDLE pipeHandle) {
|
HANDLE pipeHandle) {
|
||||||
|
NTSTATUS nt_status;
|
||||||
|
IO_STATUS_BLOCK io_status;
|
||||||
|
FILE_MODE_INFORMATION mode_info;
|
||||||
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
|
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
|
||||||
|
|
||||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
|
||||||
|
nt_status = pNtQueryInformationFile(pipeHandle,
|
||||||
|
&io_status,
|
||||||
|
&mode_info,
|
||||||
|
sizeof(mode_info),
|
||||||
|
FileModeInformation);
|
||||||
|
if (nt_status != STATUS_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
|
||||||
|
mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
|
||||||
|
/* Non-overlapped pipe. */
|
||||||
|
handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
|
||||||
|
} else {
|
||||||
|
/* Overlapped pipe. Try to associate with IOCP. */
|
||||||
if (CreateIoCompletionPort(pipeHandle,
|
if (CreateIoCompletionPort(pipeHandle,
|
||||||
loop->iocp,
|
loop->iocp,
|
||||||
(ULONG_PTR)handle,
|
(ULONG_PTR)handle,
|
||||||
0) == NULL) {
|
0) == NULL) {
|
||||||
return -1;
|
handle->flags |= UV_HANDLE_EMULATE_IOCP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -258,6 +280,17 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
|||||||
free(handle->pending_socket_info);
|
free(handle->pending_socket_info);
|
||||||
handle->pending_socket_info = NULL;
|
handle->pending_socket_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||||
|
if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
|
||||||
|
UnregisterWait(handle->read_req.wait_handle);
|
||||||
|
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
if (handle->read_req.event_handle) {
|
||||||
|
CloseHandle(handle->read_req.event_handle);
|
||||||
|
handle->read_req.event_handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember the state of this flag because the close callback is */
|
/* Remember the state of this flag because the close callback is */
|
||||||
@ -657,8 +690,99 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
|
||||||
|
int result;
|
||||||
|
DWORD bytes;
|
||||||
|
uv_read_t* req = (uv_read_t*) parameter;
|
||||||
|
uv_pipe_t* handle = (uv_pipe_t*) req->data;
|
||||||
|
uv_loop_t* loop = handle->loop;
|
||||||
|
|
||||||
|
assert(req != NULL);
|
||||||
|
assert(req->type == UV_READ);
|
||||||
|
assert(handle->type == UV_NAMED_PIPE);
|
||||||
|
|
||||||
|
result = ReadFile(handle->handle,
|
||||||
|
&uv_zero_,
|
||||||
|
0,
|
||||||
|
&bytes,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
POST_COMPLETION_FOR_REQ(loop, req);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
|
||||||
|
int result;
|
||||||
|
DWORD bytes;
|
||||||
|
uv_write_t* req = (uv_write_t*) parameter;
|
||||||
|
uv_pipe_t* handle = (uv_pipe_t*) req->handle;
|
||||||
|
uv_loop_t* loop = handle->loop;
|
||||||
|
|
||||||
|
assert(req != NULL);
|
||||||
|
assert(req->type == UV_WRITE);
|
||||||
|
assert(handle->type == UV_NAMED_PIPE);
|
||||||
|
assert(req->write_buffer.base);
|
||||||
|
|
||||||
|
result = WriteFile(handle->handle,
|
||||||
|
req->write_buffer.base,
|
||||||
|
req->write_buffer.len,
|
||||||
|
&bytes,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
|
}
|
||||||
|
|
||||||
|
POST_COMPLETION_FOR_REQ(loop, req);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
|
||||||
|
uv_read_t* req;
|
||||||
|
uv_tcp_t* handle;
|
||||||
|
|
||||||
|
req = (uv_read_t*) context;
|
||||||
|
assert(req != NULL);
|
||||||
|
handle = (uv_tcp_t*)req->data;
|
||||||
|
assert(handle != NULL);
|
||||||
|
assert(!timed_out);
|
||||||
|
|
||||||
|
if (!PostQueuedCompletionStatus(handle->loop->iocp,
|
||||||
|
req->overlapped.InternalHigh,
|
||||||
|
0,
|
||||||
|
&req->overlapped)) {
|
||||||
|
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
|
||||||
|
uv_write_t* req;
|
||||||
|
uv_tcp_t* handle;
|
||||||
|
|
||||||
|
req = (uv_write_t*) context;
|
||||||
|
assert(req != NULL);
|
||||||
|
handle = (uv_tcp_t*)req->handle;
|
||||||
|
assert(handle != NULL);
|
||||||
|
assert(!timed_out);
|
||||||
|
|
||||||
|
if (!PostQueuedCompletionStatus(handle->loop->iocp,
|
||||||
|
req->overlapped.InternalHigh,
|
||||||
|
0,
|
||||||
|
&req->overlapped)) {
|
||||||
|
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||||
uv_req_t* req;
|
uv_read_t* req;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
assert(handle->flags & UV_HANDLE_READING);
|
assert(handle->flags & UV_HANDLE_READING);
|
||||||
@ -667,7 +791,20 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
|||||||
assert(handle->handle != INVALID_HANDLE_VALUE);
|
assert(handle->handle != INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
req = &handle->read_req;
|
req = &handle->read_req;
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
|
||||||
|
if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
|
||||||
|
req,
|
||||||
|
WT_EXECUTELONGFUNCTION)) {
|
||||||
|
/* Make this req pending reporting an error. */
|
||||||
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||||
|
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||||
|
req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Do 0-read */
|
/* Do 0-read */
|
||||||
result = ReadFile(handle->handle,
|
result = ReadFile(handle->handle,
|
||||||
@ -678,17 +815,36 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
|||||||
|
|
||||||
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
||||||
/* Make this req pending reporting an error. */
|
/* Make this req pending reporting an error. */
|
||||||
SET_REQ_ERROR(req, WSAGetLastError());
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
uv_insert_pending_req(loop, req);
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||||
handle->reqs_pending++;
|
if (!req->event_handle) {
|
||||||
return;
|
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||||
|
if (!req->event_handle) {
|
||||||
|
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (req->wait_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||||
|
req->overlapped.hEvent, post_completion_read_wait, (void*) req,
|
||||||
|
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||||
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start the eof timer if there is one */
|
/* Start the eof timer if there is one */
|
||||||
eof_timer_start(handle);
|
eof_timer_start(handle);
|
||||||
|
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||||
|
handle->reqs_pending++;
|
||||||
|
return;
|
||||||
|
|
||||||
|
error:
|
||||||
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
}
|
}
|
||||||
@ -739,6 +895,54 @@ int uv_pipe_read2_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
|
||||||
|
uv_write_t* req) {
|
||||||
|
req->next_req = NULL;
|
||||||
|
if (handle->non_overlapped_writes_tail) {
|
||||||
|
req->next_req =
|
||||||
|
handle->non_overlapped_writes_tail->next_req;
|
||||||
|
handle->non_overlapped_writes_tail->next_req = (uv_req_t*)req;
|
||||||
|
handle->non_overlapped_writes_tail = req;
|
||||||
|
} else {
|
||||||
|
req->next_req = (uv_req_t*)req;
|
||||||
|
handle->non_overlapped_writes_tail = req;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
|
||||||
|
uv_write_t* req;
|
||||||
|
|
||||||
|
if (handle->non_overlapped_writes_tail) {
|
||||||
|
req = (uv_write_t*)handle->non_overlapped_writes_tail->next_req;
|
||||||
|
|
||||||
|
if (req == handle->non_overlapped_writes_tail) {
|
||||||
|
handle->non_overlapped_writes_tail = NULL;
|
||||||
|
} else {
|
||||||
|
handle->non_overlapped_writes_tail->next_req =
|
||||||
|
req->next_req;
|
||||||
|
}
|
||||||
|
|
||||||
|
return req;
|
||||||
|
} else {
|
||||||
|
/* queue empty */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
|
||||||
|
uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
|
||||||
|
if (req) {
|
||||||
|
if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
|
||||||
|
req,
|
||||||
|
WT_EXECUTELONGFUNCTION)) {
|
||||||
|
uv_fatal_error(GetLastError(), "QueueUserWorkItem");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
||||||
uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
|
uv_pipe_t* handle, uv_buf_t bufs[], int bufcnt,
|
||||||
uv_stream_t* send_handle, uv_write_cb cb) {
|
uv_stream_t* send_handle, uv_write_cb cb) {
|
||||||
@ -775,9 +979,12 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
|||||||
req->handle = (uv_stream_t*) handle;
|
req->handle = (uv_stream_t*) handle;
|
||||||
req->cb = cb;
|
req->cb = cb;
|
||||||
req->ipc_header = 0;
|
req->ipc_header = 0;
|
||||||
|
req->event_handle = NULL;
|
||||||
|
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||||
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
memset(&req->overlapped, 0, sizeof(req->overlapped));
|
||||||
|
|
||||||
if (handle->ipc) {
|
if (handle->ipc) {
|
||||||
|
assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||||
ipc_frame.header.flags = 0;
|
ipc_frame.header.flags = 0;
|
||||||
|
|
||||||
/* Use the IPC framing protocol. */
|
/* Use the IPC framing protocol. */
|
||||||
@ -847,6 +1054,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
|||||||
handle->write_queue_size += req->queued_bytes;
|
handle->write_queue_size += req->queued_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handle->write_reqs_pending == 0) {
|
||||||
|
uv_ref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
handle->write_reqs_pending++;
|
handle->write_reqs_pending++;
|
||||||
|
|
||||||
@ -856,6 +1067,17 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
|
||||||
|
req->write_buffer = bufs[0];
|
||||||
|
uv_insert_non_overlapped_write_req(handle, req);
|
||||||
|
if (handle->write_reqs_pending == 0) {
|
||||||
|
uv_queue_non_overlapped_write(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Request queued by the kernel. */
|
||||||
|
req->queued_bytes = uv_count_bufs(bufs, bufcnt);
|
||||||
|
handle->write_queue_size += req->queued_bytes;
|
||||||
|
} else {
|
||||||
result = WriteFile(handle->handle,
|
result = WriteFile(handle->handle,
|
||||||
bufs[0].base,
|
bufs[0].base,
|
||||||
bufs[0].len,
|
bufs[0].len,
|
||||||
@ -876,6 +1098,24 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req,
|
|||||||
handle->write_queue_size += req->queued_bytes;
|
handle->write_queue_size += req->queued_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||||
|
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||||
|
if (!req->event_handle) {
|
||||||
|
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||||
|
}
|
||||||
|
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||||
|
req->overlapped.hEvent, post_completion_write_wait, (void*) req,
|
||||||
|
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||||
|
uv__set_sys_error(loop, GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->write_reqs_pending == 0) {
|
||||||
|
uv_ref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
handle->write_reqs_pending++;
|
handle->write_reqs_pending++;
|
||||||
|
|
||||||
@ -999,7 +1239,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(bytes == sizeof(ipc_frame.header));
|
assert(bytes == sizeof(ipc_frame.header));
|
||||||
assert(ipc_frame.header.flags <= UV_IPC_UV_STREAM | UV_IPC_RAW_DATA);
|
assert(ipc_frame.header.flags <= (UV_IPC_UV_STREAM | UV_IPC_RAW_DATA));
|
||||||
|
|
||||||
if (ipc_frame.header.flags & UV_IPC_UV_STREAM) {
|
if (ipc_frame.header.flags & UV_IPC_UV_STREAM) {
|
||||||
assert(avail - sizeof(ipc_frame.header) >=
|
assert(avail - sizeof(ipc_frame.header) >=
|
||||||
@ -1094,6 +1334,17 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
|||||||
|
|
||||||
handle->write_queue_size -= req->queued_bytes;
|
handle->write_queue_size -= req->queued_bytes;
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||||
|
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||||
|
UnregisterWait(req->wait_handle);
|
||||||
|
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
if (req->event_handle) {
|
||||||
|
CloseHandle(req->event_handle);
|
||||||
|
req->event_handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (req->ipc_header) {
|
if (req->ipc_header) {
|
||||||
if (req == &handle->ipc_header_write_req) {
|
if (req == &handle->ipc_header_write_req) {
|
||||||
req->type = UV_UNKNOWN_REQ;
|
req->type = UV_UNKNOWN_REQ;
|
||||||
@ -1112,6 +1363,17 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle->write_reqs_pending--;
|
handle->write_reqs_pending--;
|
||||||
|
|
||||||
|
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
|
||||||
|
handle->non_overlapped_writes_tail) {
|
||||||
|
assert(handle->write_reqs_pending > 0);
|
||||||
|
uv_queue_non_overlapped_write(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->write_reqs_pending == 0) {
|
||||||
|
uv_unref(loop);
|
||||||
|
}
|
||||||
|
|
||||||
if (handle->write_reqs_pending == 0 &&
|
if (handle->write_reqs_pending == 0 &&
|
||||||
handle->flags & UV_HANDLE_SHUTTING) {
|
handle->flags & UV_HANDLE_SHUTTING) {
|
||||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||||
@ -1277,11 +1539,7 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
|
|||||||
|
|
||||||
|
|
||||||
void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
||||||
HANDLE os_handle;
|
HANDLE os_handle = (HANDLE)_get_osfhandle(file);
|
||||||
|
|
||||||
/* Special-case stdin with ipc. */
|
|
||||||
if (file == 0 && pipe->ipc) {
|
|
||||||
os_handle = (HANDLE)_get_osfhandle(file);
|
|
||||||
|
|
||||||
if (os_handle == INVALID_HANDLE_VALUE ||
|
if (os_handle == INVALID_HANDLE_VALUE ||
|
||||||
uv_set_pipe_handle(pipe->loop, pipe, os_handle) == -1) {
|
uv_set_pipe_handle(pipe->loop, pipe, os_handle) == -1) {
|
||||||
@ -1289,9 +1547,11 @@ void uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uv_pipe_connection_init(pipe);
|
uv_pipe_connection_init(pipe);
|
||||||
|
pipe->handle = os_handle;
|
||||||
|
|
||||||
|
if (pipe->ipc) {
|
||||||
|
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||||
pipe->ipc_pid = uv_parent_pid();
|
pipe->ipc_pid = uv_parent_pid();
|
||||||
assert(pipe->ipc_pid != -1);
|
assert(pipe->ipc_pid != -1);
|
||||||
|
|
||||||
pipe->handle = os_handle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
deps/uv/src/win/stream.c
vendored
2
deps/uv/src/win/stream.c
vendored
@ -43,6 +43,8 @@ void uv_connection_init(uv_stream_t* handle) {
|
|||||||
handle->write_reqs_pending = 0;
|
handle->write_reqs_pending = 0;
|
||||||
|
|
||||||
uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
|
uv_req_init(handle->loop, (uv_req_t*) &(handle->read_req));
|
||||||
|
handle->read_req.event_handle = NULL;
|
||||||
|
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||||
handle->read_req.type = UV_READ;
|
handle->read_req.type = UV_READ;
|
||||||
handle->read_req.data = handle;
|
handle->read_req.data = handle;
|
||||||
}
|
}
|
||||||
|
7
deps/uv/src/win/tcp.c
vendored
7
deps/uv/src/win/tcp.c
vendored
@ -316,6 +316,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
|||||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||||
SET_REQ_ERROR(req, GetLastError());
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
uv_insert_pending_req(loop, (uv_req_t*)req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
|
handle->reqs_pending++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -335,7 +336,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
|||||||
|
|
||||||
|
|
||||||
static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||||
uv_req_t* req;
|
uv_read_t* req;
|
||||||
uv_buf_t buf;
|
uv_buf_t buf;
|
||||||
int result;
|
int result;
|
||||||
DWORD bytes, flags;
|
DWORD bytes, flags;
|
||||||
@ -375,7 +376,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
|||||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||||
req->overlapped.InternalHigh = bytes;
|
req->overlapped.InternalHigh = bytes;
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||||
/* The req will be processed with IOCP. */
|
/* The req will be processed with IOCP. */
|
||||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||||
@ -383,7 +384,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
|||||||
} else {
|
} else {
|
||||||
/* Make this req pending reporting an error. */
|
/* Make this req pending reporting an error. */
|
||||||
SET_REQ_ERROR(req, WSAGetLastError());
|
SET_REQ_ERROR(req, WSAGetLastError());
|
||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
deps/uv/src/win/tty.c
vendored
10
deps/uv/src/win/tty.c
vendored
@ -239,7 +239,7 @@ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
|
|||||||
|
|
||||||
|
|
||||||
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
|
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
|
||||||
uv_req_t* req;
|
uv_read_t* req;
|
||||||
BOOL r;
|
BOOL r;
|
||||||
|
|
||||||
assert(handle->flags & UV_HANDLE_READING);
|
assert(handle->flags & UV_HANDLE_READING);
|
||||||
@ -261,7 +261,7 @@ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
|
|||||||
if (!r) {
|
if (!r) {
|
||||||
handle->read_raw_wait = NULL;
|
handle->read_raw_wait = NULL;
|
||||||
SET_REQ_ERROR(req, GetLastError());
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||||
@ -309,7 +309,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
|||||||
|
|
||||||
|
|
||||||
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
||||||
uv_req_t* req;
|
uv_read_t* req;
|
||||||
BOOL r;
|
BOOL r;
|
||||||
|
|
||||||
assert(handle->flags & UV_HANDLE_READING);
|
assert(handle->flags & UV_HANDLE_READING);
|
||||||
@ -337,7 +337,7 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
|||||||
if (!r) {
|
if (!r) {
|
||||||
handle->read_line_handle = NULL;
|
handle->read_line_handle = NULL;
|
||||||
SET_REQ_ERROR(req, GetLastError());
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,7 +347,7 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
|||||||
WT_EXECUTELONGFUNCTION);
|
WT_EXECUTELONGFUNCTION);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
SET_REQ_ERROR(req, GetLastError());
|
SET_REQ_ERROR(req, GetLastError());
|
||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, (uv_req_t*)req);
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
70
deps/uv/src/win/udp.c
vendored
70
deps/uv/src/win/udp.c
vendored
@ -24,9 +24,8 @@
|
|||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "../uv-common.h"
|
#include "../uv-common.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*
|
/*
|
||||||
* Threshold of active udp streams for which to preallocate udp read buffers.
|
* Threshold of active udp streams for which to preallocate udp read buffers.
|
||||||
*/
|
*/
|
||||||
@ -34,7 +33,6 @@ const unsigned int uv_active_udp_streams_threshold = 0;
|
|||||||
|
|
||||||
/* A zero-size buffer for use by uv_udp_read */
|
/* A zero-size buffer for use by uv_udp_read */
|
||||||
static char uv_zero_[] = "";
|
static char uv_zero_[] = "";
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Counter to keep track of active udp streams */
|
/* Counter to keep track of active udp streams */
|
||||||
static unsigned int active_udp_streams = 0;
|
static unsigned int active_udp_streams = 0;
|
||||||
@ -63,6 +61,8 @@ int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name,
|
|||||||
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle,
|
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle,
|
||||||
SOCKET socket) {
|
SOCKET socket) {
|
||||||
DWORD yes = 1;
|
DWORD yes = 1;
|
||||||
|
WSAPROTOCOL_INFOW info;
|
||||||
|
int opt_len;
|
||||||
|
|
||||||
assert(handle->socket == INVALID_SOCKET);
|
assert(handle->socket == INVALID_SOCKET);
|
||||||
|
|
||||||
@ -89,15 +89,34 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pSetFileCompletionNotificationModes) {
|
if (pSetFileCompletionNotificationModes) {
|
||||||
|
/* All know windowses that support SetFileCompletionNotificationModes */
|
||||||
|
/* have a bug that makes it impossible to use this function in */
|
||||||
|
/* conjunction with datagram sockets. We can work around that but only */
|
||||||
|
/* if the user is using the default UDP driver (AFD) and has no other */
|
||||||
|
/* LSPs stacked on top. Here we check whether that is the case. */
|
||||||
|
opt_len = (int) sizeof info;
|
||||||
|
if (!getsockopt(socket,
|
||||||
|
SOL_SOCKET,
|
||||||
|
SO_PROTOCOL_INFOW,
|
||||||
|
(char*) &info,
|
||||||
|
&opt_len) == SOCKET_ERROR) {
|
||||||
|
uv__set_sys_error(loop, GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.ProtocolChain.ChainLen == 1) {
|
||||||
if (pSetFileCompletionNotificationModes((HANDLE)socket,
|
if (pSetFileCompletionNotificationModes((HANDLE)socket,
|
||||||
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
||||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
||||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||||
|
handle->func_wsarecv = uv_wsarecv_workaround;
|
||||||
|
handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
|
||||||
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
||||||
uv__set_sys_error(loop, GetLastError());
|
uv__set_sys_error(loop, GetLastError());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle->socket = socket;
|
handle->socket = socket;
|
||||||
|
|
||||||
@ -111,6 +130,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
|
|||||||
handle->reqs_pending = 0;
|
handle->reqs_pending = 0;
|
||||||
handle->loop = loop;
|
handle->loop = loop;
|
||||||
handle->flags = 0;
|
handle->flags = 0;
|
||||||
|
handle->func_wsarecv = WSARecv;
|
||||||
|
handle->func_wsarecvfrom = WSARecvFrom;
|
||||||
|
|
||||||
uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
|
uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
|
||||||
handle->recv_req.type = UV_UDP_RECV;
|
handle->recv_req.type = UV_UDP_RECV;
|
||||||
@ -248,10 +269,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|||||||
* Preallocate a read buffer if the number of active streams is below
|
* Preallocate a read buffer if the number of active streams is below
|
||||||
* the threshold.
|
* the threshold.
|
||||||
*/
|
*/
|
||||||
#if 0
|
|
||||||
if (active_udp_streams < uv_active_udp_streams_threshold) {
|
if (active_udp_streams < uv_active_udp_streams_threshold) {
|
||||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||||
#endif
|
|
||||||
handle->recv_buffer = handle->alloc_cb((uv_handle_t*) handle, 65536);
|
handle->recv_buffer = handle->alloc_cb((uv_handle_t*) handle, 65536);
|
||||||
assert(handle->recv_buffer.len > 0);
|
assert(handle->recv_buffer.len > 0);
|
||||||
|
|
||||||
@ -260,7 +280,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|||||||
handle->recv_from_len = sizeof handle->recv_from;
|
handle->recv_from_len = sizeof handle->recv_from;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
|
||||||
result = WSARecvFrom(handle->socket,
|
result = handle->func_wsarecvfrom(handle->socket,
|
||||||
(WSABUF*) &buf,
|
(WSABUF*) &buf,
|
||||||
1,
|
1,
|
||||||
&bytes,
|
&bytes,
|
||||||
@ -286,15 +306,15 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|||||||
uv_insert_pending_req(loop, req);
|
uv_insert_pending_req(loop, req);
|
||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
}
|
}
|
||||||
#if 0
|
|
||||||
} else {
|
} else {
|
||||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||||
|
|
||||||
buf.base = (char*) uv_zero_;
|
buf.base = (char*) uv_zero_;
|
||||||
buf.len = 0;
|
buf.len = 0;
|
||||||
flags = MSG_PARTIAL;
|
flags = MSG_PEEK;
|
||||||
|
|
||||||
result = WSARecv(handle->socket,
|
result = handle->func_wsarecv(handle->socket,
|
||||||
(WSABUF*) &buf,
|
(WSABUF*) &buf,
|
||||||
1,
|
1,
|
||||||
&bytes,
|
&bytes,
|
||||||
@ -319,7 +339,6 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
|||||||
handle->reqs_pending++;
|
handle->reqs_pending++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -448,34 +467,27 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|||||||
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
||||||
|
|
||||||
if (!REQ_SUCCESS(req) &&
|
if (!REQ_SUCCESS(req) &&
|
||||||
GET_REQ_STATUS(req) != STATUS_RECEIVE_EXPEDITED) {
|
GET_REQ_SOCK_ERROR(req) != WSAEMSGSIZE) {
|
||||||
/* An error occurred doing the read. */
|
/* An error occurred doing the read. */
|
||||||
if ((handle->flags & UV_HANDLE_READING)) {
|
if (handle->flags & UV_HANDLE_READING) {
|
||||||
uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
|
uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req));
|
||||||
uv_udp_recv_stop(handle);
|
uv_udp_recv_stop(handle);
|
||||||
#if 0
|
|
||||||
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
|
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
|
||||||
uv_buf_init(NULL, 0) : handle->recv_buffer;
|
uv_buf_init(NULL, 0) : handle->recv_buffer;
|
||||||
#else
|
|
||||||
buf = handle->recv_buffer;
|
|
||||||
#endif
|
|
||||||
handle->recv_cb(handle, -1, buf, NULL, 0);
|
handle->recv_cb(handle, -1, buf, NULL, 0);
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
|
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
|
||||||
#endif
|
|
||||||
/* Successful read */
|
/* Successful read */
|
||||||
partial = (GET_REQ_STATUS(req) == STATUS_RECEIVE_EXPEDITED);
|
partial = !REQ_SUCCESS(req);
|
||||||
handle->recv_cb(handle,
|
handle->recv_cb(handle,
|
||||||
req->overlapped.InternalHigh,
|
req->overlapped.InternalHigh,
|
||||||
handle->recv_buffer,
|
handle->recv_buffer,
|
||||||
(struct sockaddr*) &handle->recv_from,
|
(struct sockaddr*) &handle->recv_from,
|
||||||
partial ? UV_UDP_PARTIAL : 0);
|
partial ? UV_UDP_PARTIAL : 0);
|
||||||
#if 0
|
} else if (handle->flags & UV_HANDLE_READING) {
|
||||||
} else {
|
|
||||||
DWORD bytes, err, flags;
|
DWORD bytes, err, flags;
|
||||||
struct sockaddr_storage from;
|
struct sockaddr_storage from;
|
||||||
int from_len;
|
int from_len;
|
||||||
@ -487,7 +499,8 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|||||||
|
|
||||||
memset(&from, 0, sizeof from);
|
memset(&from, 0, sizeof from);
|
||||||
from_len = sizeof from;
|
from_len = sizeof from;
|
||||||
flags = MSG_PARTIAL;
|
|
||||||
|
flags = 0;
|
||||||
|
|
||||||
if (WSARecvFrom(handle->socket,
|
if (WSARecvFrom(handle->socket,
|
||||||
(WSABUF*)&buf,
|
(WSABUF*)&buf,
|
||||||
@ -500,14 +513,18 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|||||||
NULL) != SOCKET_ERROR) {
|
NULL) != SOCKET_ERROR) {
|
||||||
|
|
||||||
/* Message received */
|
/* Message received */
|
||||||
|
handle->recv_cb(handle, bytes, buf, (struct sockaddr*) &from, 0);
|
||||||
|
} else {
|
||||||
|
err = WSAGetLastError();
|
||||||
|
if (err == WSAEMSGSIZE) {
|
||||||
|
/* Message truncated */
|
||||||
handle->recv_cb(handle,
|
handle->recv_cb(handle,
|
||||||
bytes,
|
bytes,
|
||||||
buf,
|
buf,
|
||||||
(struct sockaddr*) &from,
|
(struct sockaddr*) &from,
|
||||||
(flags & MSG_PARTIAL) ? UV_UDP_PARTIAL : 0);
|
UV_UDP_PARTIAL);
|
||||||
} else {
|
} if (err == WSAEWOULDBLOCK) {
|
||||||
err = WSAGetLastError();
|
/* Kernel buffer empty */
|
||||||
if (err == WSAEWOULDBLOCK) {
|
|
||||||
uv__set_sys_error(loop, WSAEWOULDBLOCK);
|
uv__set_sys_error(loop, WSAEWOULDBLOCK);
|
||||||
handle->recv_cb(handle, 0, buf, NULL, 0);
|
handle->recv_cb(handle, 0, buf, NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -517,7 +534,6 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
/* Post another read if still reading and not closing. */
|
/* Post another read if still reading and not closing. */
|
||||||
|
8
deps/uv/src/win/winapi.c
vendored
8
deps/uv/src/win/winapi.c
vendored
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
|
|
||||||
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||||
|
sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||||
sNtQueryInformationFile pNtQueryInformationFile;
|
sNtQueryInformationFile pNtQueryInformationFile;
|
||||||
sNtSetInformationFile pNtSetInformationFile;
|
sNtSetInformationFile pNtSetInformationFile;
|
||||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||||
@ -57,6 +58,13 @@ void uv_winapi_init() {
|
|||||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
|
||||||
|
ntdll_module,
|
||||||
|
"NtDeviceIoControlFile");
|
||||||
|
if (pNtDeviceIoControlFile == NULL) {
|
||||||
|
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||||
|
}
|
||||||
|
|
||||||
pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
|
pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
|
||||||
ntdll_module,
|
ntdll_module,
|
||||||
"NtSetInformationFile");
|
"NtSetInformationFile");
|
||||||
|
25
deps/uv/src/win/winapi.h
vendored
25
deps/uv/src/win/winapi.h
vendored
@ -4137,6 +4137,13 @@ typedef struct _FILE_BASIC_INFORMATION {
|
|||||||
DWORD FileAttributes;
|
DWORD FileAttributes;
|
||||||
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
|
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _FILE_MODE_INFORMATION {
|
||||||
|
ULONG Mode;
|
||||||
|
} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
|
||||||
|
|
||||||
|
#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
|
||||||
|
#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
|
||||||
|
|
||||||
typedef enum _FILE_INFORMATION_CLASS {
|
typedef enum _FILE_INFORMATION_CLASS {
|
||||||
FileDirectoryInformation = 1,
|
FileDirectoryInformation = 1,
|
||||||
FileFullDirectoryInformation,
|
FileFullDirectoryInformation,
|
||||||
@ -4270,9 +4277,26 @@ typedef enum _FILE_INFORMATION_CLASS {
|
|||||||
FILE_SPECIAL_ACCESS)
|
FILE_SPECIAL_ACCESS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||||
|
(PVOID ApcContext,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
ULONG Reserved);
|
||||||
|
|
||||||
typedef ULONG (NTAPI *sRtlNtStatusToDosError)
|
typedef ULONG (NTAPI *sRtlNtStatusToDosError)
|
||||||
(NTSTATUS Status);
|
(NTSTATUS Status);
|
||||||
|
|
||||||
|
typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
|
||||||
|
(HANDLE FileHandle,
|
||||||
|
HANDLE Event,
|
||||||
|
PIO_APC_ROUTINE ApcRoutine,
|
||||||
|
PVOID ApcContext,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
ULONG IoControlCode,
|
||||||
|
PVOID InputBuffer,
|
||||||
|
ULONG InputBufferLength,
|
||||||
|
PVOID OutputBuffer,
|
||||||
|
ULONG OutputBufferLength);
|
||||||
|
|
||||||
typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
|
typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
|
||||||
(HANDLE FileHandle,
|
(HANDLE FileHandle,
|
||||||
PIO_STATUS_BLOCK IoStatusBlock,
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
@ -4325,6 +4349,7 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
|
|||||||
|
|
||||||
/* Ntapi function pointers */
|
/* Ntapi function pointers */
|
||||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||||
|
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||||
extern sNtQueryInformationFile pNtQueryInformationFile;
|
extern sNtQueryInformationFile pNtQueryInformationFile;
|
||||||
extern sNtSetInformationFile pNtSetInformationFile;
|
extern sNtSetInformationFile pNtSetInformationFile;
|
||||||
|
|
||||||
|
207
deps/uv/src/win/winsock.c
vendored
207
deps/uv/src/win/winsock.c
vendored
@ -216,3 +216,210 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function provides a workaround for a bug in the winsock implementation
|
||||||
|
* of WSARecv. The problem is that when SetFileCompletionNotificationModes is
|
||||||
|
* used to avoid IOCP notifications of completed reads, WSARecv does not
|
||||||
|
* reliably indicate whether we can expect a completion package to be posted
|
||||||
|
* when the receive buffer is smaller than the received datagram.
|
||||||
|
*
|
||||||
|
* However it is desirable to use SetFileCompletionNotificationModes because
|
||||||
|
* it yields a massive performance increase.
|
||||||
|
*
|
||||||
|
* This function provides a workaround for that bug, but it only works for the
|
||||||
|
* specific case that we need it for. E.g. it assumes that the "avoid iocp"
|
||||||
|
* bit has been set, and supports only overlapped operation. It also requires
|
||||||
|
* the user to use the default msafd driver, doesn't work when other LSPs are
|
||||||
|
* stacked on top of it.
|
||||||
|
*/
|
||||||
|
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
|
||||||
|
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
|
||||||
|
NTSTATUS status;
|
||||||
|
void* apc_context;
|
||||||
|
IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
||||||
|
AFD_RECV_INFO info;
|
||||||
|
DWORD error;
|
||||||
|
|
||||||
|
if (overlapped == NULL || completion_routine != NULL) {
|
||||||
|
WSASetLastError(WSAEINVAL);
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.BufferArray = buffers;
|
||||||
|
info.BufferCount = buffer_count;
|
||||||
|
info.AfdFlags = AFD_OVERLAPPED;
|
||||||
|
info.TdiFlags = TDI_RECEIVE_NORMAL;
|
||||||
|
|
||||||
|
if (*flags & MSG_PEEK) {
|
||||||
|
info.TdiFlags |= TDI_RECEIVE_PEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*flags & MSG_PARTIAL) {
|
||||||
|
info.TdiFlags |= TDI_RECEIVE_PARTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((intptr_t) overlapped->hEvent & 1)) {
|
||||||
|
apc_context = (void*) overlapped;
|
||||||
|
} else {
|
||||||
|
apc_context = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iosb->Status = STATUS_PENDING;
|
||||||
|
iosb->Pointer = 0;
|
||||||
|
|
||||||
|
status = pNtDeviceIoControlFile((HANDLE) socket,
|
||||||
|
overlapped->hEvent,
|
||||||
|
NULL,
|
||||||
|
apc_context,
|
||||||
|
iosb,
|
||||||
|
IOCTL_AFD_RECEIVE,
|
||||||
|
&info,
|
||||||
|
sizeof(info),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
*flags = 0;
|
||||||
|
*bytes = (DWORD) iosb->Information;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case STATUS_SUCCESS:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_PENDING:
|
||||||
|
error = WSA_IO_PENDING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_BUFFER_OVERFLOW:
|
||||||
|
error = WSAEMSGSIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_EXPEDITED:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_OOB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_PARTIAL_EXPEDITED:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_PARTIAL | MSG_OOB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_PARTIAL:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_PARTIAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = uv_ntstatus_to_winsock_error(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WSASetLastError(error);
|
||||||
|
|
||||||
|
if (error == ERROR_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* See description of uv_wsarecv_workaround. */
|
||||||
|
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
|
||||||
|
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
|
||||||
|
int* addr_len, WSAOVERLAPPED *overlapped,
|
||||||
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
|
||||||
|
NTSTATUS status;
|
||||||
|
void* apc_context;
|
||||||
|
IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
|
||||||
|
AFD_RECV_DATAGRAM_INFO info;
|
||||||
|
DWORD error;
|
||||||
|
|
||||||
|
if (overlapped == NULL || addr == NULL || addr_len == NULL ||
|
||||||
|
completion_routine != NULL) {
|
||||||
|
WSASetLastError(WSAEINVAL);
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.BufferArray = buffers;
|
||||||
|
info.BufferCount = buffer_count;
|
||||||
|
info.AfdFlags = AFD_OVERLAPPED;
|
||||||
|
info.TdiFlags = TDI_RECEIVE_NORMAL;
|
||||||
|
info.Address = addr;
|
||||||
|
info.AddressLength = addr_len;
|
||||||
|
|
||||||
|
if (*flags & MSG_PEEK) {
|
||||||
|
info.TdiFlags |= TDI_RECEIVE_PEEK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*flags & MSG_PARTIAL) {
|
||||||
|
info.TdiFlags |= TDI_RECEIVE_PARTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!((intptr_t) overlapped->hEvent & 1)) {
|
||||||
|
apc_context = (void*) overlapped;
|
||||||
|
} else {
|
||||||
|
apc_context = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
iosb->Status = STATUS_PENDING;
|
||||||
|
iosb->Pointer = 0;
|
||||||
|
|
||||||
|
status = pNtDeviceIoControlFile((HANDLE) socket,
|
||||||
|
overlapped->hEvent,
|
||||||
|
NULL,
|
||||||
|
apc_context,
|
||||||
|
iosb,
|
||||||
|
IOCTL_AFD_RECEIVE_DATAGRAM,
|
||||||
|
&info,
|
||||||
|
sizeof(info),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
*flags = 0;
|
||||||
|
*bytes = (DWORD) iosb->Information;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case STATUS_SUCCESS:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_PENDING:
|
||||||
|
error = WSA_IO_PENDING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_BUFFER_OVERFLOW:
|
||||||
|
error = WSAEMSGSIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_EXPEDITED:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_OOB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_PARTIAL_EXPEDITED:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_PARTIAL | MSG_OOB;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATUS_RECEIVE_PARTIAL:
|
||||||
|
error = ERROR_SUCCESS;
|
||||||
|
*flags = MSG_PARTIAL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = uv_ntstatus_to_winsock_error(status);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WSASetLastError(error);
|
||||||
|
|
||||||
|
if (error == ERROR_SUCCESS) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
66
deps/uv/src/win/winsock.h
vendored
66
deps/uv/src/win/winsock.h
vendored
@ -39,14 +39,66 @@
|
|||||||
#define IPV6_V6ONLY 27
|
#define IPV6_V6ONLY 27
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Whether ipv6 is supported */
|
/*
|
||||||
extern int uv_allow_ipv6;
|
* TDI defines that are only in the DDK.
|
||||||
|
* We only need receive flags so far.
|
||||||
|
*/
|
||||||
|
#ifndef TDI_RECEIVE_NORMAL
|
||||||
|
#define TDI_RECEIVE_BROADCAST 0x00000004
|
||||||
|
#define TDI_RECEIVE_MULTICAST 0x00000008
|
||||||
|
#define TDI_RECEIVE_PARTIAL 0x00000010
|
||||||
|
#define TDI_RECEIVE_NORMAL 0x00000020
|
||||||
|
#define TDI_RECEIVE_EXPEDITED 0x00000040
|
||||||
|
#define TDI_RECEIVE_PEEK 0x00000080
|
||||||
|
#define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
|
||||||
|
#define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
|
||||||
|
#define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
|
||||||
|
#define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
|
||||||
|
#define TDI_RECEIVE_CONTROL_INFO 0x00001000
|
||||||
|
#define TDI_RECEIVE_FORCE_INDICATION 0x00002000
|
||||||
|
#define TDI_RECEIVE_NO_PUSH 0x00004000
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
|
/*
|
||||||
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
|
* The "Auxiliary Function Driver" is the windows kernel-mode driver that does
|
||||||
|
* TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
|
||||||
|
* Having these definitions allows us to bypass winsock and make an AFD kernel
|
||||||
|
* call directly, avoiding a bug in winsock's recvfrom implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Ip address used to bind to any port at any interface */
|
#define AFD_NO_FAST_IO 0x00000001
|
||||||
extern struct sockaddr_in uv_addr_ip4_any_;
|
#define AFD_OVERLAPPED 0x00000002
|
||||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
#define AFD_IMMEDIATE 0x00000004
|
||||||
|
|
||||||
|
typedef struct _AFD_RECV_DATAGRAM_INFO {
|
||||||
|
LPWSABUF BufferArray;
|
||||||
|
ULONG BufferCount;
|
||||||
|
ULONG AfdFlags;
|
||||||
|
ULONG TdiFlags;
|
||||||
|
struct sockaddr* Address;
|
||||||
|
int* AddressLength;
|
||||||
|
} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
|
||||||
|
|
||||||
|
typedef struct _AFD_RECV_INFO {
|
||||||
|
LPWSABUF BufferArray;
|
||||||
|
ULONG BufferCount;
|
||||||
|
ULONG AfdFlags;
|
||||||
|
ULONG TdiFlags;
|
||||||
|
} AFD_RECV_INFO, *PAFD_RECV_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
#define _AFD_CONTROL_CODE(operation, method) \
|
||||||
|
((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
|
||||||
|
|
||||||
|
#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
|
||||||
|
|
||||||
|
#define AFD_RECEIVE 5
|
||||||
|
#define AFD_RECEIVE_DATAGRAM 6
|
||||||
|
|
||||||
|
#define IOCTL_AFD_RECEIVE \
|
||||||
|
_AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
|
||||||
|
|
||||||
|
#define IOCTL_AFD_RECEIVE_DATAGRAM \
|
||||||
|
_AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
|
||||||
|
|
||||||
#endif /* UV_WIN_WINSOCK_H_ */
|
#endif /* UV_WIN_WINSOCK_H_ */
|
||||||
|
101
deps/uv/test/run-tests.c
vendored
101
deps/uv/test/run-tests.c
vendored
@ -55,6 +55,11 @@ static uv_write_t conn_notify_req;
|
|||||||
static int close_cb_called;
|
static int close_cb_called;
|
||||||
static int connection_accepted;
|
static int connection_accepted;
|
||||||
|
|
||||||
|
static uv_pipe_t stdin_pipe;
|
||||||
|
static uv_pipe_t stdout_pipe;
|
||||||
|
static int on_pipe_read_called;
|
||||||
|
static int after_write_called;
|
||||||
|
|
||||||
|
|
||||||
static void close_cb(uv_handle_t* handle) {
|
static void close_cb(uv_handle_t* handle) {
|
||||||
close_cb_called++;
|
close_cb_called++;
|
||||||
@ -148,6 +153,98 @@ static int ipc_helper() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void on_pipe_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
|
||||||
|
ASSERT(nread > 0);
|
||||||
|
ASSERT(memcmp("hello world\n", buf.base, nread) == 0);
|
||||||
|
on_pipe_read_called++;
|
||||||
|
|
||||||
|
free(buf.base);
|
||||||
|
|
||||||
|
uv_close((uv_handle_t*)&stdin_pipe, close_cb);
|
||||||
|
uv_close((uv_handle_t*)&stdout_pipe, close_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uv_buf_t on_pipe_read_alloc(uv_handle_t* handle,
|
||||||
|
size_t suggested_size) {
|
||||||
|
uv_buf_t buf;
|
||||||
|
buf.base = (char*)malloc(suggested_size);
|
||||||
|
buf.len = suggested_size;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void after_pipe_write(uv_write_t* req, int status) {
|
||||||
|
ASSERT(status == 0);
|
||||||
|
after_write_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int stdio_over_pipes_helper() {
|
||||||
|
/* Write several buffers to test that the write order is preserved. */
|
||||||
|
char* buffers[] = {
|
||||||
|
"he",
|
||||||
|
"ll",
|
||||||
|
"o ",
|
||||||
|
"wo",
|
||||||
|
"rl",
|
||||||
|
"d",
|
||||||
|
"\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
uv_write_t write_req[COUNTOF(buffers)];
|
||||||
|
uv_buf_t buf[COUNTOF(buffers)];
|
||||||
|
int r, i;
|
||||||
|
uv_loop_t* loop = uv_default_loop();
|
||||||
|
|
||||||
|
ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
|
||||||
|
ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
|
||||||
|
|
||||||
|
r = uv_pipe_init(loop, &stdin_pipe, 0);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
r = uv_pipe_init(loop, &stdout_pipe, 0);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
uv_pipe_open(&stdin_pipe, 0);
|
||||||
|
uv_pipe_open(&stdout_pipe, 1);
|
||||||
|
|
||||||
|
/* Unref both stdio handles to make sure that all writes complete. */
|
||||||
|
uv_unref(loop);
|
||||||
|
uv_unref(loop);
|
||||||
|
|
||||||
|
for (i = 0; i < COUNTOF(buffers); i++) {
|
||||||
|
buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < COUNTOF(buffers); i++) {
|
||||||
|
r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1,
|
||||||
|
after_pipe_write);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_run(loop);
|
||||||
|
|
||||||
|
ASSERT(after_write_called == 7);
|
||||||
|
ASSERT(on_pipe_read_called == 0);
|
||||||
|
ASSERT(close_cb_called == 0);
|
||||||
|
|
||||||
|
uv_ref(loop);
|
||||||
|
uv_ref(loop);
|
||||||
|
|
||||||
|
r = uv_read_start((uv_stream_t*)&stdin_pipe, on_pipe_read_alloc,
|
||||||
|
on_pipe_read);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
uv_run(loop);
|
||||||
|
|
||||||
|
ASSERT(after_write_called == 7);
|
||||||
|
ASSERT(on_pipe_read_called == 1);
|
||||||
|
ASSERT(close_cb_called == 2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int maybe_run_test(int argc, char **argv) {
|
static int maybe_run_test(int argc, char **argv) {
|
||||||
if (strcmp(argv[1], "--list") == 0) {
|
if (strcmp(argv[1], "--list") == 0) {
|
||||||
print_tests(stdout);
|
print_tests(stdout);
|
||||||
@ -158,6 +255,10 @@ static int maybe_run_test(int argc, char **argv) {
|
|||||||
return ipc_helper();
|
return ipc_helper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) {
|
||||||
|
return stdio_over_pipes_helper();
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(argv[1], "spawn_helper1") == 0) {
|
if (strcmp(argv[1], "spawn_helper1") == 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
2
deps/uv/test/task.h
vendored
2
deps/uv/test/task.h
vendored
@ -38,6 +38,8 @@
|
|||||||
# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
|
# define TEST_PIPENAME_2 "/tmp/uv-test-sock2"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define COUNTOF(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TCP = 0,
|
TCP = 0,
|
||||||
PIPE
|
PIPE
|
||||||
|
2
deps/uv/test/test-list.h
vendored
2
deps/uv/test/test-list.h
vendored
@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
TEST_DECLARE (tty)
|
TEST_DECLARE (tty)
|
||||||
|
TEST_DECLARE (stdio_over_pipes)
|
||||||
TEST_DECLARE (ipc)
|
TEST_DECLARE (ipc)
|
||||||
TEST_DECLARE (tcp_ping_pong)
|
TEST_DECLARE (tcp_ping_pong)
|
||||||
TEST_DECLARE (tcp_ping_pong_v6)
|
TEST_DECLARE (tcp_ping_pong_v6)
|
||||||
@ -117,6 +118,7 @@ HELPER_DECLARE (pipe_echo_server)
|
|||||||
|
|
||||||
TASK_LIST_START
|
TASK_LIST_START
|
||||||
TEST_ENTRY (tty)
|
TEST_ENTRY (tty)
|
||||||
|
TEST_ENTRY (stdio_over_pipes)
|
||||||
TEST_ENTRY (ipc)
|
TEST_ENTRY (ipc)
|
||||||
|
|
||||||
|
|
||||||
|
154
deps/uv/test/test-stdio-over-pipes.c
vendored
Normal file
154
deps/uv/test/test-stdio-over-pipes.c
vendored
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "uv.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
|
||||||
|
static char exepath[1024];
|
||||||
|
static size_t exepath_size = 1024;
|
||||||
|
static char* args[3];
|
||||||
|
static uv_process_options_t options;
|
||||||
|
static int close_cb_called;
|
||||||
|
static int exit_cb_called;
|
||||||
|
static int on_read_cb_called;
|
||||||
|
static int after_write_cb_called;
|
||||||
|
uv_pipe_t out, in;
|
||||||
|
static uv_loop_t* loop;
|
||||||
|
#define OUTPUT_SIZE 1024
|
||||||
|
static char output[OUTPUT_SIZE];
|
||||||
|
static int output_used;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uv_write_t req;
|
||||||
|
uv_buf_t buf;
|
||||||
|
} write_req_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void close_cb(uv_handle_t* handle) {
|
||||||
|
printf("close_cb\n");
|
||||||
|
close_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void exit_cb(uv_process_t* process, int exit_status, int term_signal) {
|
||||||
|
printf("exit_cb\n");
|
||||||
|
exit_cb_called++;
|
||||||
|
ASSERT(exit_status == 0);
|
||||||
|
ASSERT(term_signal == 0);
|
||||||
|
uv_close((uv_handle_t*)process, close_cb);
|
||||||
|
uv_close((uv_handle_t*)&in, close_cb);
|
||||||
|
uv_close((uv_handle_t*)&out, close_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void init_process_options(char* test, uv_exit_cb exit_cb) {
|
||||||
|
int r = uv_exepath(exepath, &exepath_size);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
exepath[exepath_size] = '\0';
|
||||||
|
args[0] = exepath;
|
||||||
|
args[1] = test;
|
||||||
|
args[2] = NULL;
|
||||||
|
options.file = exepath;
|
||||||
|
options.args = args;
|
||||||
|
options.exit_cb = exit_cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uv_buf_t on_alloc(uv_handle_t* handle, size_t suggested_size) {
|
||||||
|
uv_buf_t buf;
|
||||||
|
buf.base = output + output_used;
|
||||||
|
buf.len = OUTPUT_SIZE - output_used;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void after_write(uv_write_t* req, int status) {
|
||||||
|
write_req_t* wr;
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
uv_err_t err = uv_last_error(loop);
|
||||||
|
fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
wr = (write_req_t*) req;
|
||||||
|
|
||||||
|
/* Free the read/write buffer and the request */
|
||||||
|
free(wr);
|
||||||
|
|
||||||
|
after_write_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
|
||||||
|
write_req_t* write_req;
|
||||||
|
int r;
|
||||||
|
uv_err_t err = uv_last_error(uv_default_loop());
|
||||||
|
|
||||||
|
ASSERT(nread > 0 || err.code == UV_EOF);
|
||||||
|
|
||||||
|
if (nread > 0) {
|
||||||
|
output_used += nread;
|
||||||
|
if (output_used == 12) {
|
||||||
|
ASSERT(memcmp("hello world\n", output, 12) == 0);
|
||||||
|
write_req = (write_req_t*)malloc(sizeof(*write_req));
|
||||||
|
write_req->buf = uv_buf_init(output, output_used);
|
||||||
|
r = uv_write(&write_req->req, (uv_stream_t*)&in, &write_req->buf, 1, after_write);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on_read_cb_called++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_IMPL(stdio_over_pipes) {
|
||||||
|
int r;
|
||||||
|
uv_process_t process;
|
||||||
|
loop = uv_default_loop();
|
||||||
|
|
||||||
|
init_process_options("stdio_over_pipes_helper", exit_cb);
|
||||||
|
|
||||||
|
uv_pipe_init(loop, &out, 0);
|
||||||
|
options.stdout_stream = &out;
|
||||||
|
uv_pipe_init(loop, &in, 0);
|
||||||
|
options.stdin_stream = ∈
|
||||||
|
|
||||||
|
r = uv_spawn(loop, &process, options);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
r = uv_run(uv_default_loop());
|
||||||
|
ASSERT(r == 0);
|
||||||
|
|
||||||
|
ASSERT(on_read_cb_called > 1);
|
||||||
|
ASSERT(after_write_cb_called == 1);
|
||||||
|
ASSERT(exit_cb_called == 1);
|
||||||
|
ASSERT(close_cb_called == 3);
|
||||||
|
ASSERT(memcmp("hello world\n", output, 12) == 0);
|
||||||
|
ASSERT(output_used == 12);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
1
deps/uv/uv.gyp
vendored
1
deps/uv/uv.gyp
vendored
@ -286,6 +286,7 @@
|
|||||||
'test/test-ref.c',
|
'test/test-ref.c',
|
||||||
'test/test-shutdown-eof.c',
|
'test/test-shutdown-eof.c',
|
||||||
'test/test-spawn.c',
|
'test/test-spawn.c',
|
||||||
|
'test/test-stdio-over-pipes.c',
|
||||||
'test/test-tcp-bind-error.c',
|
'test/test-tcp-bind-error.c',
|
||||||
'test/test-tcp-bind6-error.c',
|
'test/test-tcp-bind6-error.c',
|
||||||
'test/test-tcp-close.c',
|
'test/test-tcp-close.c',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user