LIBS: updated libuv
parent
9bf04b25b6
commit
da64203c43
|
@ -377,6 +377,12 @@ typedef struct {
|
|||
OVERLAPPED overlapped; \
|
||||
size_t queued_bytes; \
|
||||
} io; \
|
||||
/* in v2, we can move these to the UV_CONNECT_PRIVATE_FIELDS */ \
|
||||
struct { \
|
||||
ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\
|
||||
HANDLE pipeHandle; \
|
||||
DWORD duplex_flags; \
|
||||
} connect; \
|
||||
} u; \
|
||||
struct uv_req_s* next_req;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ extern char** environ;
|
|||
# include <sanitizer/linux_syscall_hooks.h>
|
||||
#endif
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop);
|
||||
static void uv__run_pending(uv_loop_t* loop);
|
||||
|
||||
/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
|
||||
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
|
||||
|
@ -160,6 +160,15 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
|||
|
||||
case UV_FS_EVENT:
|
||||
uv__fs_event_close((uv_fs_event_t*)handle);
|
||||
#if defined(__sun)
|
||||
/*
|
||||
* On Solaris and illumos, we will not be able to dissociate the watcher
|
||||
* for an event which is pending delivery, so we cannot always call
|
||||
* uv__make_close_pending() straight away. The backend will call the
|
||||
* function once the event has cleared.
|
||||
*/
|
||||
return;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case UV_POLL:
|
||||
|
@ -372,7 +381,7 @@ int uv_loop_alive(const uv_loop_t* loop) {
|
|||
int uv_run(uv_loop_t* loop, uv_run_mode mode) {
|
||||
int timeout;
|
||||
int r;
|
||||
int ran_pending;
|
||||
int can_sleep;
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (!r)
|
||||
|
@ -381,16 +390,25 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
|
|||
while (r != 0 && loop->stop_flag == 0) {
|
||||
uv__update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
ran_pending = uv__run_pending(loop);
|
||||
|
||||
can_sleep =
|
||||
QUEUE_EMPTY(&loop->pending_queue) && QUEUE_EMPTY(&loop->idle_handles);
|
||||
|
||||
uv__run_pending(loop);
|
||||
uv__run_idle(loop);
|
||||
uv__run_prepare(loop);
|
||||
|
||||
timeout = 0;
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv__backend_timeout(loop);
|
||||
|
||||
uv__io_poll(loop, timeout);
|
||||
|
||||
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
||||
* times to avoid loop starvation.*/
|
||||
for (r = 0; r < 8 && !QUEUE_EMPTY(&loop->pending_queue); r++)
|
||||
uv__run_pending(loop);
|
||||
|
||||
/* Run one final update on the provider_idle_time in case uv__io_poll
|
||||
* returned because the timeout expired, but no events were received. This
|
||||
* call will be ignored if the provider_entry_time was either never set (if
|
||||
|
@ -654,28 +672,23 @@ int uv__cloexec(int fd, int set) {
|
|||
|
||||
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
struct cmsghdr* cmsg;
|
||||
#if defined(__ANDROID__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__linux__)
|
||||
ssize_t rc;
|
||||
rc = recvmsg(fd, msg, flags | MSG_CMSG_CLOEXEC);
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
return rc;
|
||||
#else
|
||||
struct cmsghdr* cmsg;
|
||||
int* pfd;
|
||||
int* end;
|
||||
#if defined(__linux__)
|
||||
static int no_msg_cmsg_cloexec;
|
||||
if (0 == uv__load_relaxed(&no_msg_cmsg_cloexec)) {
|
||||
rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
|
||||
if (rc != -1)
|
||||
return rc;
|
||||
if (errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
uv__store_relaxed(&no_msg_cmsg_cloexec, 1);
|
||||
} else {
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
}
|
||||
#else
|
||||
ssize_t rc;
|
||||
rc = recvmsg(fd, msg, flags);
|
||||
#endif
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
if (msg->msg_controllen == 0)
|
||||
|
@ -688,6 +701,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
|||
pfd += 1)
|
||||
uv__cloexec(*pfd, 1);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -780,14 +794,11 @@ int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
|
|||
}
|
||||
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop) {
|
||||
static void uv__run_pending(uv_loop_t* loop) {
|
||||
QUEUE* q;
|
||||
QUEUE pq;
|
||||
uv__io_t* w;
|
||||
|
||||
if (QUEUE_EMPTY(&loop->pending_queue))
|
||||
return 0;
|
||||
|
||||
QUEUE_MOVE(&loop->pending_queue, &pq);
|
||||
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
|
@ -797,8 +808,6 @@ static int uv__run_pending(uv_loop_t* loop) {
|
|||
w = QUEUE_DATA(q, uv__io_t, pending_queue);
|
||||
w->cb(loop, w, POLLOUT);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1181,7 +1181,8 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
|
|||
defined(_AIX71) || \
|
||||
defined(__sun) || \
|
||||
defined(__HAIKU__) || \
|
||||
defined(__GNU__)
|
||||
defined(__GNU__) || \
|
||||
defined(__OpenBSD__)
|
||||
struct timespec ts[2];
|
||||
ts[0] = uv__fs_to_timespec(req->atime);
|
||||
ts[1] = uv__fs_to_timespec(req->mtime);
|
||||
|
|
|
@ -540,16 +540,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
|||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
||||
const char* filename, unsigned int flags) {
|
||||
static int os390_regfileint(uv_fs_event_t* handle, char* path) {
|
||||
uv__os390_epoll* ep;
|
||||
_RFIS reg_struct;
|
||||
char* path;
|
||||
int rc;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
ep = handle->loop->ep;
|
||||
assert(ep->msg_queue != -1);
|
||||
|
||||
|
@ -558,19 +553,38 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
|||
reg_struct.__rfis_type = 1;
|
||||
memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle));
|
||||
|
||||
path = uv__strdup(filename);
|
||||
if (path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), ®_struct);
|
||||
if (rc != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
||||
const char* filename, unsigned int flags) {
|
||||
char* path;
|
||||
int rc;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
path = uv__strdup(filename);
|
||||
if (path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
rc = os390_regfileint(handle, path);
|
||||
if (rc != 0) {
|
||||
uv__free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
handle->path = path;
|
||||
handle->cb = cb;
|
||||
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -603,6 +617,10 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
|||
abort();
|
||||
|
||||
uv__handle_stop(handle);
|
||||
if (handle->path != NULL) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -628,7 +646,15 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
|
|||
events = 0;
|
||||
if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
|
||||
events = UV_CHANGE;
|
||||
else if (msg.__rfim_event == _RFIM_RENAME)
|
||||
else if (msg.__rfim_event == _RFIM_RENAME || msg.__rfim_event == _RFIM_UNLINK)
|
||||
events = UV_RENAME;
|
||||
else if (msg.__rfim_event == 156)
|
||||
/* TODO(gabylb): zos - this event should not happen, need to investigate.
|
||||
*
|
||||
* This event seems to occur when the watched file is [re]moved, or an
|
||||
* editor (like vim) renames then creates the file on save (for vim, that's
|
||||
* when backupcopy=no|auto).
|
||||
*/
|
||||
events = UV_RENAME;
|
||||
else
|
||||
/* Some event that we are not interested in. */
|
||||
|
@ -639,6 +665,14 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
|
|||
*/
|
||||
__a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
|
||||
handle = *(uv_fs_event_t**)(msg.__rfim_utok);
|
||||
assert(handle != NULL);
|
||||
/* The file is implicitly unregistered when the change notification is
|
||||
* sent, only one notification is sent per registration. So we need to
|
||||
* re-register interest in a file after each change notification we
|
||||
* receive.
|
||||
*/
|
||||
if (handle->path != NULL)
|
||||
os390_regfileint(handle, handle->path);
|
||||
handle->cb(handle, uv__basename_r(handle->path), events, 0);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -671,27 +671,25 @@ static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
|
|||
if (options->env != NULL)
|
||||
env = options->env;
|
||||
|
||||
/* If options->file contains a slash, posix_spawn/posix_spawnp behave
|
||||
* the same, and don't involve PATH resolution at all. Otherwise, if
|
||||
* options->file does not include a slash, but no custom environment is
|
||||
* to be used, the environment used for path resolution as well for the
|
||||
* child process is that of the parent process, so posix_spawnp is the
|
||||
* way to go. */
|
||||
if (strchr(options->file, '/') != NULL || options->env == NULL) {
|
||||
/* If options->file contains a slash, posix_spawn/posix_spawnp should behave
|
||||
* the same, and do not involve PATH resolution at all. The libc
|
||||
* `posix_spawnp` provided by Apple is buggy (since 10.15), so we now emulate it
|
||||
* here, per https://github.com/libuv/libuv/pull/3583. */
|
||||
if (strchr(options->file, '/') != NULL) {
|
||||
do
|
||||
err = posix_spawnp(pid, options->file, actions, attrs, options->args, env);
|
||||
err = posix_spawn(pid, options->file, actions, attrs, options->args, env);
|
||||
while (err == EINTR);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Look for the definition of PATH in the provided env */
|
||||
path = uv__spawn_find_path_in_env(options->env);
|
||||
path = uv__spawn_find_path_in_env(env);
|
||||
|
||||
/* The following resolution logic (execvpe emulation) is copied from
|
||||
* https://git.musl-libc.org/cgit/musl/tree/src/process/execvp.c
|
||||
* and adapted to work for our specific usage */
|
||||
|
||||
/* If no path was provided in options->env, use the default value
|
||||
/* If no path was provided in env, use the default value
|
||||
* to look for the executable */
|
||||
if (path == NULL)
|
||||
path = _PATH_DEFPATH;
|
||||
|
|
|
@ -154,7 +154,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
|||
sigset_t set;
|
||||
uint64_t base;
|
||||
uint64_t diff;
|
||||
uint64_t idle_poll;
|
||||
unsigned int nfds;
|
||||
unsigned int i;
|
||||
int saved_errno;
|
||||
|
@ -424,7 +423,7 @@ void uv_loadavg(double avg[3]) {
|
|||
#if defined(PORT_SOURCE_FILE)
|
||||
|
||||
static int uv__fs_event_rearm(uv_fs_event_t *handle) {
|
||||
if (handle->fd == -1)
|
||||
if (handle->fd == PORT_DELETED)
|
||||
return UV_EBADF;
|
||||
|
||||
if (port_associate(handle->loop->fs_fd,
|
||||
|
@ -475,6 +474,12 @@ static void uv__fs_event_read(uv_loop_t* loop,
|
|||
handle = (uv_fs_event_t*) pe.portev_user;
|
||||
assert((r == 0) && "unexpected port_get() error");
|
||||
|
||||
if (uv__is_closing(handle)) {
|
||||
uv__handle_stop(handle);
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
break;
|
||||
}
|
||||
|
||||
events = 0;
|
||||
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
|
||||
events |= UV_CHANGE;
|
||||
|
@ -542,12 +547,14 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
|||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
static int uv__fs_event_stop(uv_fs_event_t* handle) {
|
||||
int ret = 0;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
|
||||
port_dissociate(handle->loop->fs_fd,
|
||||
if (handle->fd == PORT_LOADED) {
|
||||
ret = port_dissociate(handle->loop->fs_fd,
|
||||
PORT_SOURCE_FILE,
|
||||
(uintptr_t) &handle->fo);
|
||||
}
|
||||
|
@ -556,13 +563,28 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
|||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
handle->fo.fo_name = NULL;
|
||||
uv__handle_stop(handle);
|
||||
if (ret == 0)
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
(void) uv__fs_event_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
/*
|
||||
* If we were unable to dissociate the port here, then it is most likely
|
||||
* that there is a pending queued event. When this happens, we don't want
|
||||
* to complete the close as it will free the underlying memory for the
|
||||
* handle, causing a use-after-free problem when the event is processed.
|
||||
* We defer the final cleanup until after the event is consumed in
|
||||
* uv__fs_event_read().
|
||||
*/
|
||||
if (uv__fs_event_stop(handle) == 0)
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
#else /* !defined(PORT_SOURCE_FILE) */
|
||||
|
|
|
@ -592,7 +592,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
|||
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
DWORD timeout;
|
||||
int r;
|
||||
int ran_pending;
|
||||
int can_sleep;
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (!r)
|
||||
|
@ -602,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
|||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
|
||||
ran_pending = uv__process_reqs(loop);
|
||||
can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
|
||||
|
||||
uv__process_reqs(loop);
|
||||
uv__idle_invoke(loop);
|
||||
uv__prepare_invoke(loop);
|
||||
|
||||
timeout = 0;
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
|
@ -615,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
|||
else
|
||||
uv__poll_wine(loop, timeout);
|
||||
|
||||
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
|
||||
* times to avoid loop starvation.*/
|
||||
for (r = 0; r < 8 && loop->pending_reqs_tail != NULL; r++)
|
||||
uv__process_reqs(loop);
|
||||
|
||||
/* Run one final update on the provider_idle_time in case uv__poll*
|
||||
* returned because the timeout expired, but no events were received. This
|
||||
* call will be ignored if the provider_entry_time was either never set (if
|
||||
|
|
|
@ -121,14 +121,10 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
|
|||
|
||||
|
||||
static void uv__pipe_connection_init(uv_pipe_t* handle) {
|
||||
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
|
||||
uv__connection_init((uv_stream_t*) handle);
|
||||
handle->read_req.data = handle;
|
||||
handle->pipe.conn.eof_timer = NULL;
|
||||
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
|
||||
handle->pipe.conn.readfile_thread_handle = NULL;
|
||||
InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -393,6 +389,8 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
|||
unsigned int client_flags;
|
||||
int err;
|
||||
|
||||
uv__pipe_connection_init(parent_pipe);
|
||||
|
||||
server_pipe = INVALID_HANDLE_VALUE;
|
||||
client_pipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
|
@ -427,7 +425,6 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
|||
goto error;
|
||||
}
|
||||
|
||||
uv__pipe_connection_init(parent_pipe);
|
||||
parent_pipe->handle = server_pipe;
|
||||
*child_pipe_ptr = client_pipe;
|
||||
|
||||
|
@ -462,7 +459,9 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
|
|||
DWORD current_mode = 0;
|
||||
DWORD err = 0;
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER)
|
||||
assert(handle->flags & UV_HANDLE_CONNECTION);
|
||||
assert(!(handle->flags & UV_HANDLE_PIPESERVER));
|
||||
if (handle->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EINVAL;
|
||||
if (handle->handle != INVALID_HANDLE_VALUE)
|
||||
return UV_EBUSY;
|
||||
|
@ -478,18 +477,17 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
|
|||
*/
|
||||
if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL,
|
||||
NULL, NULL, 0)) {
|
||||
return -1;
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (current_mode & PIPE_NOWAIT) {
|
||||
SetLastError(ERROR_ACCESS_DENIED);
|
||||
return -1;
|
||||
return UV_EACCES;
|
||||
}
|
||||
} else {
|
||||
/* If this returns ERROR_INVALID_PARAMETER we probably opened
|
||||
* something that is not a pipe. */
|
||||
if (err == ERROR_INVALID_PARAMETER) {
|
||||
SetLastError(WSAENOTSOCK);
|
||||
return UV_ENOTSOCK;
|
||||
}
|
||||
return -1;
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,13 +498,15 @@ static int uv__set_pipe_handle(uv_loop_t* loop,
|
|||
sizeof(mode_info),
|
||||
FileModeInformation);
|
||||
if (nt_status != STATUS_SUCCESS) {
|
||||
return -1;
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
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;
|
||||
handle->pipe.conn.readfile_thread_handle = NULL;
|
||||
InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock);
|
||||
} else {
|
||||
/* Overlapped pipe. Try to associate with IOCP. */
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
|
@ -815,7 +815,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
|||
assert(loop);
|
||||
|
||||
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait
|
||||
* for the pipe to become available with WaitNamedPipe. */
|
||||
* up to 30 seconds for the pipe to become available with WaitNamedPipe. */
|
||||
while (WaitNamedPipeW(handle->name, 30000)) {
|
||||
/* The pipe is now available, try to connect. */
|
||||
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
|
||||
|
@ -825,9 +825,10 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
|||
SwitchToThread();
|
||||
}
|
||||
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE &&
|
||||
!uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_SUCCESS(req);
|
||||
req->u.connect.pipeHandle = pipeHandle;
|
||||
req->u.connect.duplex_flags = duplex_flags;
|
||||
} else {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
}
|
||||
|
@ -849,6 +850,18 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
|||
UV_REQ_INIT(req, UV_CONNECT);
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->cb = cb;
|
||||
req->u.connect.pipeHandle = INVALID_HANDLE_VALUE;
|
||||
req->u.connect.duplex_flags = 0;
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
goto error;
|
||||
}
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
err = ERROR_PIPE_BUSY;
|
||||
goto error;
|
||||
}
|
||||
uv__pipe_connection_init(handle);
|
||||
|
||||
/* Convert name to UTF16. */
|
||||
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
|
||||
|
@ -888,17 +901,8 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
|||
goto error;
|
||||
}
|
||||
|
||||
assert(pipeHandle != INVALID_HANDLE_VALUE);
|
||||
|
||||
if (uv__set_pipe_handle(loop,
|
||||
(uv_pipe_t*) req->handle,
|
||||
pipeHandle,
|
||||
-1,
|
||||
duplex_flags)) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
req->u.connect.pipeHandle = pipeHandle;
|
||||
req->u.connect.duplex_flags = duplex_flags;
|
||||
SET_REQ_SUCCESS(req);
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
|
@ -937,7 +941,7 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
|
|||
/* Cancel asynchronous read. */
|
||||
r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped);
|
||||
assert(r || GetLastError() == ERROR_NOT_FOUND);
|
||||
|
||||
(void) r;
|
||||
} else {
|
||||
/* Cancel synchronous read (which is happening in the thread pool). */
|
||||
HANDLE thread;
|
||||
|
@ -1099,6 +1103,7 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
|||
|
||||
} else {
|
||||
pipe_client = (uv_pipe_t*) client;
|
||||
uv__pipe_connection_init(pipe_client);
|
||||
|
||||
/* Find a connection instance that has been connected, but not yet
|
||||
* accepted. */
|
||||
|
@ -1110,7 +1115,6 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
|||
}
|
||||
|
||||
/* Initialize the client handle and copy the pipeHandle to the client */
|
||||
uv__pipe_connection_init(pipe_client);
|
||||
pipe_client->handle = req->pipeHandle;
|
||||
pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
|
||||
|
@ -2140,22 +2144,28 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
|||
|
||||
void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_connect_t* req) {
|
||||
HANDLE pipeHandle;
|
||||
DWORD duplex_flags;
|
||||
int err;
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
if (req->cb) {
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
uv__pipe_connection_init(handle);
|
||||
} else {
|
||||
err = GET_REQ_ERROR(req);
|
||||
}
|
||||
req->cb(req, uv_translate_sys_error(err));
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
pipeHandle = req->u.connect.pipeHandle;
|
||||
duplex_flags = req->u.connect.duplex_flags;
|
||||
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
|
||||
if (err)
|
||||
CloseHandle(pipeHandle);
|
||||
} else {
|
||||
err = uv_translate_sys_error(GET_REQ_ERROR(req));
|
||||
}
|
||||
|
||||
if (req->cb)
|
||||
req->cb(req, err);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
|
||||
|
@ -2200,7 +2210,8 @@ static void eof_timer_init(uv_pipe_t* pipe) {
|
|||
pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
|
||||
|
||||
r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
|
||||
assert(r == 0); /* timers can't fail */
|
||||
assert(r == 0); /* timers can't fail */
|
||||
(void) r;
|
||||
pipe->pipe.conn.eof_timer->data = pipe;
|
||||
uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
|
||||
}
|
||||
|
@ -2280,10 +2291,16 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
|||
IO_STATUS_BLOCK io_status;
|
||||
FILE_ACCESS_INFORMATION access;
|
||||
DWORD duplex_flags = 0;
|
||||
int err;
|
||||
|
||||
if (os_handle == INVALID_HANDLE_VALUE)
|
||||
return UV_EBADF;
|
||||
if (pipe->flags & UV_HANDLE_PIPESERVER)
|
||||
return UV_EINVAL;
|
||||
if (pipe->flags & UV_HANDLE_CONNECTION)
|
||||
return UV_EBUSY;
|
||||
|
||||
uv__pipe_connection_init(pipe);
|
||||
uv__once_init();
|
||||
/* In order to avoid closing a stdio file descriptor 0-2, duplicate the
|
||||
* underlying OS handle and forget about the original fd.
|
||||
|
@ -2300,6 +2317,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
|||
FALSE,
|
||||
DUPLICATE_SAME_ACCESS))
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
assert(os_handle != INVALID_HANDLE_VALUE);
|
||||
file = -1;
|
||||
}
|
||||
|
||||
|
@ -2327,17 +2345,17 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
|||
if (access.AccessFlags & FILE_READ_DATA)
|
||||
duplex_flags |= UV_HANDLE_READABLE;
|
||||
|
||||
if (os_handle == INVALID_HANDLE_VALUE ||
|
||||
uv__set_pipe_handle(pipe->loop,
|
||||
pipe,
|
||||
os_handle,
|
||||
file,
|
||||
duplex_flags) == -1) {
|
||||
return UV_EINVAL;
|
||||
err = uv__set_pipe_handle(pipe->loop,
|
||||
pipe,
|
||||
os_handle,
|
||||
file,
|
||||
duplex_flags);
|
||||
if (err) {
|
||||
if (file == -1)
|
||||
CloseHandle(os_handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
uv__pipe_connection_init(pipe);
|
||||
|
||||
if (pipe->ipc) {
|
||||
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
|
||||
|
@ -2361,6 +2379,51 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size)
|
|||
uv__once_init();
|
||||
name_info = NULL;
|
||||
|
||||
if (handle->name != NULL) {
|
||||
/* The user might try to query the name before we are connected,
|
||||
* and this is just easier to return the cached value if we have it. */
|
||||
name_buf = handle->name;
|
||||
name_len = wcslen(name_buf);
|
||||
|
||||
/* check how much space we need */
|
||||
addrlen = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
name_buf,
|
||||
name_len,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!addrlen) {
|
||||
*size = 0;
|
||||
err = uv_translate_sys_error(GetLastError());
|
||||
return err;
|
||||
} else if (addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
err = UV_ENOBUFS;
|
||||
goto error;
|
||||
}
|
||||
|
||||
addrlen = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
name_buf,
|
||||
name_len,
|
||||
buffer,
|
||||
addrlen,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!addrlen) {
|
||||
*size = 0;
|
||||
err = uv_translate_sys_error(GetLastError());
|
||||
return err;
|
||||
}
|
||||
|
||||
*size = addrlen;
|
||||
buffer[addrlen] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (handle->handle == INVALID_HANDLE_VALUE) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
|
@ -2498,6 +2561,11 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
|
|||
if (handle->handle != INVALID_HANDLE_VALUE)
|
||||
return uv__pipe_getname(handle, buffer, size);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
if (handle->name != NULL)
|
||||
return uv__pipe_getname(handle, buffer, size);
|
||||
}
|
||||
|
||||
return UV_EBADF;
|
||||
}
|
||||
|
||||
|
|
|
@ -138,13 +138,13 @@ INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
|
|||
} while (0)
|
||||
|
||||
|
||||
INLINE static int uv__process_reqs(uv_loop_t* loop) {
|
||||
INLINE static void uv__process_reqs(uv_loop_t* loop) {
|
||||
uv_req_t* req;
|
||||
uv_req_t* first;
|
||||
uv_req_t* next;
|
||||
|
||||
if (loop->pending_reqs_tail == NULL)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
first = loop->pending_reqs_tail->next_req;
|
||||
next = first;
|
||||
|
@ -214,8 +214,6 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) {
|
|||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* UV_WIN_REQ_INL_H_ */
|
||||
|
|
|
@ -1411,7 +1411,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
|
|||
int writing;
|
||||
|
||||
socket = tcp->socket;
|
||||
reading = tcp->flags & UV_HANDLE_READING;
|
||||
reading = tcp->flags & UV_HANDLE_READ_PENDING;
|
||||
writing = tcp->stream.conn.write_reqs_pending > 0;
|
||||
if (!reading && !writing)
|
||||
return;
|
||||
|
@ -1458,10 +1458,10 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
|
|||
|
||||
void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
if (tcp->flags & UV_HANDLE_CONNECTION) {
|
||||
uv__tcp_try_cancel_reqs(tcp);
|
||||
if (tcp->flags & UV_HANDLE_READING) {
|
||||
uv_read_stop((uv_stream_t*) tcp);
|
||||
}
|
||||
uv__tcp_try_cancel_reqs(tcp);
|
||||
} else {
|
||||
if (tcp->tcp.serv.accept_reqs != NULL) {
|
||||
/* First close the incoming sockets to cancel the accept operations before
|
||||
|
|
|
@ -1087,7 +1087,7 @@ int uv__udp_disconnect(uv_udp_t* handle) {
|
|||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
err = connect(handle->socket, &addr, sizeof(addr));
|
||||
err = connect(handle->socket, (struct sockaddr*) &addr, sizeof(addr));
|
||||
if (err)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
|
|
Loading…
Reference in New Issue