forked from cory/tildefriends
libuv 1.44.2
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3934 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
52
deps/libuv/src/strtok.c
vendored
Normal file
52
deps/libuv/src/strtok.c
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
/* Copyright libuv project 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 <stdlib.h>
|
||||
#include "strtok.h"
|
||||
|
||||
char* uv__strtok(char* str, const char* sep, char** itr) {
|
||||
const char* sep_itr;
|
||||
char* tmp;
|
||||
char* start;
|
||||
|
||||
if (str == NULL)
|
||||
start = tmp = *itr;
|
||||
else
|
||||
start = tmp = str;
|
||||
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
|
||||
while (*tmp != '\0') {
|
||||
sep_itr = sep;
|
||||
while (*sep_itr != '\0') {
|
||||
if (*tmp == *sep_itr) {
|
||||
*itr = tmp + 1;
|
||||
*tmp = '\0';
|
||||
return start;
|
||||
}
|
||||
sep_itr++;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
*itr = NULL;
|
||||
return start;
|
||||
}
|
27
deps/libuv/src/strtok.h
vendored
Normal file
27
deps/libuv/src/strtok.h
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/* Copyright libuv project 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.
|
||||
*/
|
||||
|
||||
#ifndef UV_STRTOK_H_
|
||||
#define UV_STRTOK_H_
|
||||
|
||||
char* uv__strtok(char* str, const char* sep, char** itr);
|
||||
|
||||
#endif /* UV_STRTOK_H_ */
|
15
deps/libuv/src/unix/atomic-ops.h
vendored
15
deps/libuv/src/unix/atomic-ops.h
vendored
@ -37,12 +37,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(__MVS__)
|
||||
unsigned int op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
(unsigned int*) ptr, *ptr, &op4))
|
||||
return oldval;
|
||||
else
|
||||
return op4;
|
||||
/* Use hand-rolled assembly because codegen from builtin __plo_CSST results in
|
||||
* a runtime bug.
|
||||
*/
|
||||
__asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :);
|
||||
return oldval;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
|
||||
#else
|
||||
@ -55,7 +54,9 @@ UV_UNUSED(static void cpu_relax(void)) {
|
||||
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
|
||||
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||
__asm__ __volatile__ ("yield" ::: "memory");
|
||||
#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
|
||||
#elif (defined(__ppc__) || defined(__ppc64__)) && defined(__APPLE__)
|
||||
__asm volatile ("" : : : "memory");
|
||||
#elif !defined(__APPLE__) && (defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__))
|
||||
__asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
|
||||
#endif
|
||||
}
|
||||
|
110
deps/libuv/src/unix/core.c
vendored
110
deps/libuv/src/unix/core.c
vendored
@ -20,6 +20,7 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "strtok.h"
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdio.h> /* printf */
|
||||
@ -80,7 +81,8 @@ extern char** environ;
|
||||
#endif
|
||||
|
||||
#if defined(__MVS__)
|
||||
#include <sys/ioctl.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include "zos-sys-info.h"
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
@ -93,7 +95,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));
|
||||
@ -159,6 +161,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) || defined(__MVS__)
|
||||
/*
|
||||
* On Solaris, illumos, and z/OS 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:
|
||||
@ -371,7 +382,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)
|
||||
@ -380,16 +391,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
|
||||
@ -653,28 +673,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)
|
||||
@ -687,6 +702,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
pfd += 1)
|
||||
uv__cloexec(*pfd, 1);
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -779,14 +795,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)) {
|
||||
@ -796,8 +809,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;
|
||||
}
|
||||
|
||||
|
||||
@ -1162,24 +1173,17 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
size_t name_size;
|
||||
size_t homedir_size;
|
||||
size_t shell_size;
|
||||
long initsize;
|
||||
int r;
|
||||
|
||||
if (pwd == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if (initsize <= 0)
|
||||
bufsize = 4096;
|
||||
else
|
||||
bufsize = (size_t) initsize;
|
||||
|
||||
uid = geteuid();
|
||||
buf = NULL;
|
||||
|
||||
for (;;) {
|
||||
uv__free(buf);
|
||||
/* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
|
||||
* is frequently 1024 or 4096, so we can just use that directly. The pwent
|
||||
* will not usually be large. */
|
||||
for (bufsize = 2000;; bufsize *= 2) {
|
||||
buf = uv__malloc(bufsize);
|
||||
|
||||
if (buf == NULL)
|
||||
@ -1189,21 +1193,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
r = getpwuid_r(uid, &pw, buf, bufsize, &result);
|
||||
while (r == EINTR);
|
||||
|
||||
if (r != 0 || result == NULL)
|
||||
uv__free(buf);
|
||||
|
||||
if (r != ERANGE)
|
||||
break;
|
||||
|
||||
bufsize *= 2;
|
||||
}
|
||||
|
||||
if (r != 0) {
|
||||
uv__free(buf);
|
||||
if (r != 0)
|
||||
return UV__ERR(r);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
uv__free(buf);
|
||||
if (result == NULL)
|
||||
return UV_ENOENT;
|
||||
}
|
||||
|
||||
/* Allocate memory for the username, shell, and home directory */
|
||||
name_size = strlen(pw.pw_name) + 1;
|
||||
@ -1556,6 +1557,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
char* cloned_path;
|
||||
char* path_env;
|
||||
char* token;
|
||||
char* itr;
|
||||
|
||||
if (buf == NULL || buflen == NULL || *buflen == 0)
|
||||
return UV_EINVAL;
|
||||
@ -1597,7 +1599,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
if (cloned_path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
token = strtok(cloned_path, ":");
|
||||
token = uv__strtok(cloned_path, ":", &itr);
|
||||
while (token != NULL) {
|
||||
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
|
||||
if (realpath(trypath, abspath) == abspath) {
|
||||
@ -1616,7 +1618,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
token = strtok(NULL, ":");
|
||||
token = uv__strtok(NULL, ":", &itr);
|
||||
}
|
||||
uv__free(cloned_path);
|
||||
|
||||
@ -1646,7 +1648,13 @@ unsigned int uv_available_parallelism(void) {
|
||||
|
||||
return (unsigned) rc;
|
||||
#elif defined(__MVS__)
|
||||
return 1; /* TODO(bnoordhuis) Read from CSD_NUMBER_ONLINE_CPUS? */
|
||||
int rc;
|
||||
|
||||
rc = __get_num_online_cpus();
|
||||
if (rc < 1)
|
||||
rc = 1;
|
||||
|
||||
return (unsigned) rc;
|
||||
#else /* __linux__ */
|
||||
long rc;
|
||||
|
||||
|
3
deps/libuv/src/unix/fs.c
vendored
3
deps/libuv/src/unix/fs.c
vendored
@ -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);
|
||||
|
1
deps/libuv/src/unix/internal.h
vendored
1
deps/libuv/src/unix/internal.h
vendored
@ -277,7 +277,6 @@ void uv__tcp_close(uv_tcp_t* handle);
|
||||
size_t uv__thread_stack_size(void);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
uv_handle_type uv__handle_type(int fd);
|
||||
FILE* uv__open_file(const char* path);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__search_path(const char* prog, char* buf, size_t* buflen);
|
||||
|
2
deps/libuv/src/unix/kqueue.c
vendored
2
deps/libuv/src/unix/kqueue.c
vendored
@ -456,7 +456,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].ident == fd)
|
||||
if ((int) events[i].ident == fd && events[i].filter != EVFILT_PROC)
|
||||
events[i].ident = -1;
|
||||
}
|
||||
|
||||
|
36
deps/libuv/src/unix/os390-syscalls.c
vendored
36
deps/libuv/src/unix/os390-syscalls.c
vendored
@ -284,6 +284,8 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
nmsgsfds_t size;
|
||||
struct pollfd* pfds;
|
||||
int pollret;
|
||||
int pollfdret;
|
||||
int pollmsgret;
|
||||
int reventcount;
|
||||
int nevents;
|
||||
struct pollfd msg_fd;
|
||||
@ -304,24 +306,24 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lst->size > 0)
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
else
|
||||
_SET_FDS_MSGS(size, 0, 0);
|
||||
assert(lst->size > 0);
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
pfds = lst->items;
|
||||
pollret = poll(pfds, size, timeout);
|
||||
if (pollret <= 0)
|
||||
return pollret;
|
||||
|
||||
assert(lst->size > 0);
|
||||
|
||||
pollret = _NFDS(pollret) + _NMSGS(pollret);
|
||||
pollfdret = _NFDS(pollret);
|
||||
pollmsgret = _NMSGS(pollret);
|
||||
|
||||
reventcount = 0;
|
||||
nevents = 0;
|
||||
msg_fd = pfds[lst->size - 1];
|
||||
msg_fd = pfds[lst->size - 1]; /* message queue is always last entry */
|
||||
maxevents = maxevents - pollmsgret; /* allow spot for message queue */
|
||||
for (i = 0;
|
||||
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
|
||||
i < lst->size - 1 &&
|
||||
nevents < maxevents &&
|
||||
reventcount < pollfdret; ++i) {
|
||||
struct epoll_event ev;
|
||||
struct pollfd* pfd;
|
||||
|
||||
@ -332,18 +334,18 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
ev.fd = pfd->fd;
|
||||
ev.events = pfd->revents;
|
||||
ev.is_msg = 0;
|
||||
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
|
||||
reventcount += 2;
|
||||
else if (pfd->revents & (POLLIN | POLLOUT))
|
||||
++reventcount;
|
||||
|
||||
pfd->revents = 0;
|
||||
reventcount++;
|
||||
events[nevents++] = ev;
|
||||
}
|
||||
|
||||
if (msg_fd.revents != 0 && msg_fd.fd != -1)
|
||||
if (i == lst->size)
|
||||
events[nevents - 1].is_msg = 1;
|
||||
if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
|
||||
struct epoll_event ev;
|
||||
ev.fd = msg_fd.fd;
|
||||
ev.events = msg_fd.revents;
|
||||
ev.is_msg = 1;
|
||||
events[nevents++] = ev;
|
||||
}
|
||||
|
||||
return nevents;
|
||||
}
|
||||
|
297
deps/libuv/src/unix/os390.c
vendored
297
deps/libuv/src/unix/os390.c
vendored
@ -278,7 +278,9 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
__net_ifconf6header_t ifc;
|
||||
__net_ifconf6entry_t* ifr;
|
||||
__net_ifconf6entry_t* p;
|
||||
__net_ifconf6entry_t flg;
|
||||
unsigned int i;
|
||||
int count_names;
|
||||
unsigned char netmask[16] = {0};
|
||||
|
||||
*count = 0;
|
||||
/* Assume maximum buffer size allowable */
|
||||
@ -287,24 +289,33 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
ifc.__nif6h_version = 1;
|
||||
ifc.__nif6h_buflen = maxsize;
|
||||
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
|
||||
ifc.__nif6h_buffer = uv__calloc(1, maxsize);
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
|
||||
if (ifc.__nif6h_buffer == NULL) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
ifc.__nif6h_version = 1;
|
||||
ifc.__nif6h_buflen = maxsize;
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
|
||||
/* This will error on a system that does not support IPv6. However, we want
|
||||
* to treat this as there being 0 interfaces so we can continue to get IPv4
|
||||
* interfaces in uv_interface_addresses(). So return 0 instead of the error.
|
||||
*/
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
||||
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
||||
p = ifr;
|
||||
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
|
||||
|
||||
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
|
||||
p->__nif6e_addr.sin6_family == AF_INET))
|
||||
if (!(p->__nif6e_addr.sin6_family == AF_INET6))
|
||||
continue;
|
||||
|
||||
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
|
||||
@ -313,21 +324,28 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
++(*count);
|
||||
}
|
||||
|
||||
if ((*count) == 0) {
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
|
||||
*addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t));
|
||||
if (!(*addresses)) {
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
count_names = 0;
|
||||
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
||||
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
||||
p = ifr;
|
||||
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
|
||||
|
||||
if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
|
||||
p->__nif6e_addr.sin6_family == AF_INET))
|
||||
if (!(p->__nif6e_addr.sin6_family == AF_INET6))
|
||||
continue;
|
||||
|
||||
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
|
||||
@ -335,20 +353,41 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
|
||||
/* All conditions above must match count loop */
|
||||
|
||||
address->name = uv__strdup(p->__nif6e_name);
|
||||
i = 0;
|
||||
/* Ignore EBCDIC space (0x40) padding in name */
|
||||
while (i < ARRAY_SIZE(p->__nif6e_name) &&
|
||||
p->__nif6e_name[i] != 0x40 &&
|
||||
p->__nif6e_name[i] != 0)
|
||||
++i;
|
||||
address->name = uv__malloc(i + 1);
|
||||
if (address->name == NULL) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
memcpy(address->name, p->__nif6e_name, i);
|
||||
address->name[i] = '\0';
|
||||
__e2a_s(address->name);
|
||||
count_names++;
|
||||
|
||||
if (p->__nif6e_addr.sin6_family == AF_INET6)
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
|
||||
else
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
|
||||
|
||||
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
|
||||
for (i = 0; i < (p->__nif6e_prefixlen / 8); i++)
|
||||
netmask[i] = 0xFF;
|
||||
|
||||
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
if (p->__nif6e_prefixlen % 8)
|
||||
netmask[i] = 0xFF << (8 - (p->__nif6e_prefixlen % 8));
|
||||
|
||||
address->netmask.netmask6.sin6_len = p->__nif6e_prefixlen;
|
||||
memcpy(&(address->netmask.netmask6.sin6_addr), netmask, 16);
|
||||
address->netmask.netmask6.sin6_family = AF_INET6;
|
||||
|
||||
address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
|
||||
address++;
|
||||
}
|
||||
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
@ -362,14 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifreq flg;
|
||||
struct ifreq* ifr;
|
||||
struct ifreq* p;
|
||||
uv_interface_address_t* addresses_v6;
|
||||
int count_v6;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
int count_names;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
/* get the ipv6 addresses first */
|
||||
uv_interface_address_t* addresses_v6;
|
||||
uv__interface_addresses_v6(&addresses_v6, &count_v6);
|
||||
if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
|
||||
return rc;
|
||||
|
||||
/* now get the ipv4 addresses */
|
||||
|
||||
@ -377,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
maxsize = 16384;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (0 > sockfd)
|
||||
if (0 > sockfd) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
ifc.ifc_req = uv__calloc(1, maxsize);
|
||||
|
||||
if (ifc.ifc_req == NULL) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
ifc.ifc_len = maxsize;
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@ -403,6 +461,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@ -413,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
if (*count == 0 && count_v6 == 0) {
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc((*count + count_v6) *
|
||||
*addresses = uv__calloc(1, (*count + count_v6) *
|
||||
sizeof(uv_interface_address_t));
|
||||
|
||||
if (!(*addresses)) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
/* copy over the ipv6 addresses */
|
||||
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
|
||||
address += count_v6;
|
||||
*count += count_v6;
|
||||
uv__free(addresses_v6);
|
||||
/* copy over the ipv6 addresses if any are found */
|
||||
if (count_v6) {
|
||||
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
|
||||
address += count_v6;
|
||||
*count += count_v6;
|
||||
/* free ipv6 addresses, but keep address names */
|
||||
uv__free(addresses_v6);
|
||||
}
|
||||
|
||||
count_names = *count;
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
@ -446,6 +515,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
@ -455,22 +526,43 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
/* All conditions above must match count loop */
|
||||
|
||||
address->name = uv__strdup(p->ifr_name);
|
||||
i = 0;
|
||||
/* Ignore EBCDIC space (0x40) padding in name */
|
||||
while (i < ARRAY_SIZE(p->ifr_name) &&
|
||||
p->ifr_name[i] != 0x40 &&
|
||||
p->ifr_name[i] != 0)
|
||||
++i;
|
||||
address->name = uv__malloc(i + 1);
|
||||
if (address->name == NULL) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
memcpy(address->name, p->ifr_name, i);
|
||||
address->name[i] = '\0';
|
||||
__e2a_s(address->name);
|
||||
count_names++;
|
||||
|
||||
if (p->ifr_addr.sa_family == AF_INET6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
address->netmask.netmask4.sin_family = AF_INET;
|
||||
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
address++;
|
||||
}
|
||||
|
||||
#undef ADDR_SIZE
|
||||
#undef MAX
|
||||
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
@ -529,27 +621,17 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
uv_fs_event_stop(handle);
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
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,17 +640,10 @@ 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);
|
||||
|
||||
uv__handle_start(handle);
|
||||
handle->path = path;
|
||||
handle->cb = cb;
|
||||
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
@ -576,7 +651,33 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(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) {
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__fs_event_stop(uv_fs_event_t* handle) {
|
||||
uv__os390_epoll* ep;
|
||||
_RFIS reg_struct;
|
||||
int rc;
|
||||
@ -602,12 +703,40 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
if (rc != 0 && errno != EALREADY && errno != ENOENT)
|
||||
abort();
|
||||
|
||||
if (handle->path != NULL) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
|
||||
if (rc != 0 && errno == EALREADY)
|
||||
return -1;
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
uv__fs_event_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv__fs_event_close(uv_fs_event_t* handle) {
|
||||
/*
|
||||
* If we were unable to unregister file interest here, then it is most likely
|
||||
* that there is a pending queued change notification. 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
|
||||
* os390_message_queue_handler().
|
||||
*/
|
||||
if (uv__fs_event_stop(handle) == 0)
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
|
||||
static int os390_message_queue_handler(uv__os390_epoll* ep) {
|
||||
uv_fs_event_t* handle;
|
||||
int msglen;
|
||||
@ -628,7 +757,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 +776,26 @@ 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);
|
||||
|
||||
assert((handle->flags & UV_HANDLE_CLOSED) == 0);
|
||||
if (uv__is_closing(handle)) {
|
||||
uv__handle_stop(handle);
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
return 0;
|
||||
} else if (handle->path == NULL) {
|
||||
/* _RFIS_UNREG returned EALREADY. */
|
||||
uv__handle_stop(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
assert(handle->path != NULL);
|
||||
os390_regfileint(handle, handle->path);
|
||||
handle->cb(handle, uv__basename_r(handle->path), events, 0);
|
||||
return 1;
|
||||
}
|
||||
@ -650,6 +807,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
uv__os390_epoll* ep;
|
||||
int have_signals;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
@ -712,6 +870,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
count = 48; /* Benchmarks suggest this gives the best throughput. */
|
||||
real_timeout = timeout;
|
||||
int nevents = 0;
|
||||
have_signals = 0;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
@ -796,6 +955,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
ep = loop->ep;
|
||||
if (pe->is_msg) {
|
||||
os390_message_queue_handler(ep);
|
||||
nevents++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -825,19 +985,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
pe->events |= w->pevents & (POLLIN | POLLOUT);
|
||||
|
||||
if (pe->events != 0) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->events);
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
* because those are implemented in terms of signal watchers.
|
||||
*/
|
||||
if (w == &loop->signal_io_watcher) {
|
||||
have_signals = 1;
|
||||
} else {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
w->cb(loop, w, pe->events);
|
||||
}
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
|
||||
if (have_signals != 0) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
|
||||
}
|
||||
|
||||
loop->watchers[loop->nwatchers] = NULL;
|
||||
loop->watchers[loop->nwatchers + 1] = NULL;
|
||||
|
||||
if (have_signals != 0)
|
||||
return; /* Event loop should cycle now so don't poll again. */
|
||||
|
||||
if (nevents != 0) {
|
||||
if (nfds == ARRAY_SIZE(events) && --count != 0) {
|
||||
/* Poll for more events but don't block this time. */
|
||||
@ -872,6 +1048,5 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
*/
|
||||
loop->ep = NULL;
|
||||
|
||||
uv__platform_loop_delete(loop);
|
||||
return uv__platform_loop_init(loop);
|
||||
}
|
||||
|
6
deps/libuv/src/unix/pipe.c
vendored
6
deps/libuv/src/unix/pipe.c
vendored
@ -51,7 +51,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
/* Already bound? */
|
||||
if (uv__stream_fd(handle) >= 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_closing(handle)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
/* Make a copy of the file name, it outlives this function's scope. */
|
||||
pipe_fname = uv__strdup(name);
|
||||
if (pipe_fname == NULL)
|
||||
@ -319,7 +321,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
||||
if (handle->accepted_fd == -1)
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
else
|
||||
return uv__handle_type(handle->accepted_fd);
|
||||
return uv_guess_handle(handle->accepted_fd);
|
||||
}
|
||||
|
||||
|
||||
|
40
deps/libuv/src/unix/process.c
vendored
40
deps/libuv/src/unix/process.c
vendored
@ -35,7 +35,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
#if defined(__APPLE__)
|
||||
# include <spawn.h>
|
||||
# include <paths.h>
|
||||
# include <sys/kauth.h>
|
||||
@ -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;
|
||||
@ -812,11 +810,6 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
|
||||
|
||||
*pid = fork();
|
||||
|
||||
if (*pid == -1) {
|
||||
/* Failed to fork */
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (*pid == 0) {
|
||||
/* Fork succeeded, in the child process */
|
||||
uv__process_child_init(options, stdio_count, pipes, error_fd);
|
||||
@ -826,6 +819,10 @@ static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
|
||||
if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0)
|
||||
abort();
|
||||
|
||||
if (*pid == -1)
|
||||
/* Failed to fork */
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Fork succeeded, in the parent process */
|
||||
return 0;
|
||||
}
|
||||
@ -1066,9 +1063,16 @@ int uv_process_kill(uv_process_t* process, int signum) {
|
||||
|
||||
|
||||
int uv_kill(int pid, int signum) {
|
||||
if (kill(pid, signum))
|
||||
if (kill(pid, signum)) {
|
||||
#if defined(__MVS__)
|
||||
/* EPERM is returned if the process is a zombie. */
|
||||
siginfo_t infop;
|
||||
if (errno == EPERM &&
|
||||
waitid(P_PID, pid, &infop, WNOHANG | WNOWAIT | WEXITED) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
return UV__ERR(errno);
|
||||
else
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
95
deps/libuv/src/unix/stream.c
vendored
95
deps/libuv/src/unix/stream.c
vendored
@ -66,6 +66,7 @@ static void uv__read(uv_stream_t* stream);
|
||||
static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
|
||||
static void uv__write_callbacks(uv_stream_t* stream);
|
||||
static size_t uv__write_req_size(uv_write_t* req);
|
||||
static void uv__drain(uv_stream_t* stream);
|
||||
|
||||
|
||||
void uv__stream_init(uv_loop_t* loop,
|
||||
@ -453,17 +454,7 @@ void uv__stream_destroy(uv_stream_t* stream) {
|
||||
|
||||
uv__stream_flush_write_queue(stream, UV_ECANCELED);
|
||||
uv__write_callbacks(stream);
|
||||
|
||||
if (stream->shutdown_req) {
|
||||
/* The ECANCELED error code is a lie, the shutdown(2) syscall is a
|
||||
* fait accompli at this point. Maybe we should revisit this in v0.11.
|
||||
* A possible reason for leaving it unchanged is that it informs the
|
||||
* callee that the handle has been destroyed.
|
||||
*/
|
||||
uv__req_unregister(stream->loop, stream->shutdown_req);
|
||||
stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED);
|
||||
stream->shutdown_req = NULL;
|
||||
}
|
||||
uv__drain(stream);
|
||||
|
||||
assert(stream->write_queue_size == 0);
|
||||
}
|
||||
@ -641,7 +632,9 @@ done:
|
||||
|
||||
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
|
||||
int err;
|
||||
|
||||
if (uv__is_closing(stream)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
switch (stream->type) {
|
||||
case UV_TCP:
|
||||
err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
|
||||
@ -667,25 +660,30 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
int err;
|
||||
|
||||
assert(QUEUE_EMPTY(&stream->write_queue));
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
if (!(stream->flags & UV_HANDLE_CLOSING)) {
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
|
||||
/* Shutdown? */
|
||||
if ((stream->flags & UV_HANDLE_SHUTTING) &&
|
||||
!(stream->flags & UV_HANDLE_CLOSING) &&
|
||||
if (!(stream->flags & UV_HANDLE_SHUTTING))
|
||||
return;
|
||||
|
||||
req = stream->shutdown_req;
|
||||
assert(req);
|
||||
|
||||
if ((stream->flags & UV_HANDLE_CLOSING) ||
|
||||
!(stream->flags & UV_HANDLE_SHUT)) {
|
||||
assert(stream->shutdown_req);
|
||||
|
||||
req = stream->shutdown_req;
|
||||
stream->shutdown_req = NULL;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
|
||||
err = 0;
|
||||
if (shutdown(uv__stream_fd(stream), SHUT_WR))
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
/* The user destroyed the stream before we got to do the shutdown. */
|
||||
err = UV_ECANCELED;
|
||||
else if (shutdown(uv__stream_fd(stream), SHUT_WR))
|
||||
err = UV__ERR(errno);
|
||||
|
||||
if (err == 0)
|
||||
else /* Success. */
|
||||
stream->flags |= UV_HANDLE_SHUT;
|
||||
|
||||
if (req->cb != NULL)
|
||||
@ -926,7 +924,6 @@ static void uv__write(uv_stream_t* stream) {
|
||||
}
|
||||
|
||||
req->error = n;
|
||||
// XXX(jwn): this must call uv__stream_flush_write_queue(stream, n) here, since we won't generate any more events
|
||||
uv__write_req_finish(req);
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
@ -964,49 +961,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
}
|
||||
|
||||
|
||||
uv_handle_type uv__handle_type(int fd) {
|
||||
struct sockaddr_storage ss;
|
||||
socklen_t sslen;
|
||||
socklen_t len;
|
||||
int type;
|
||||
|
||||
memset(&ss, 0, sizeof(ss));
|
||||
sslen = sizeof(ss);
|
||||
|
||||
if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof type;
|
||||
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
#if defined(_AIX) || defined(__DragonFly__)
|
||||
/* on AIX/DragonFly the getsockname call returns an empty sa structure
|
||||
* for sockets of type AF_UNIX. For all other types it will
|
||||
* return a properly filled in structure.
|
||||
*/
|
||||
if (sslen == 0)
|
||||
return UV_NAMED_PIPE;
|
||||
#endif
|
||||
switch (ss.ss_family) {
|
||||
case AF_UNIX:
|
||||
return UV_NAMED_PIPE;
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
return UV_TCP;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == SOCK_DGRAM &&
|
||||
(ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
|
||||
return UV_UDP;
|
||||
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
|
||||
stream->flags |= UV_HANDLE_READ_EOF;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
@ -1278,7 +1232,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
|
||||
assert(uv__stream_fd(stream) >= 0);
|
||||
|
||||
/* Initialize request */
|
||||
/* Initialize request. The `shutdown(2)` call will always be deferred until
|
||||
* `uv__drain`, just before the callback is run. */
|
||||
uv__req_init(stream->loop, req, UV_SHUTDOWN);
|
||||
req->handle = stream;
|
||||
req->cb = cb;
|
||||
@ -1286,8 +1241,8 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
stream->flags |= UV_HANDLE_SHUTTING;
|
||||
stream->flags &= ~UV_HANDLE_WRITABLE;
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
if (QUEUE_EMPTY(&stream->write_queue))
|
||||
uv__io_feed(stream->loop, &stream->io_watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
36
deps/libuv/src/unix/sunos.c
vendored
36
deps/libuv/src/unix/sunos.c
vendored
@ -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) */
|
||||
|
17
deps/libuv/src/unix/tcp.c
vendored
17
deps/libuv/src/unix/tcp.c
vendored
@ -184,14 +184,15 @@ int uv__tcp_bind(uv_tcp_t* tcp,
|
||||
#endif
|
||||
|
||||
errno = 0;
|
||||
if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
|
||||
err = bind(tcp->io_watcher.fd, addr, addrlen);
|
||||
if (err == -1 && errno != EADDRINUSE) {
|
||||
if (errno == EAFNOSUPPORT)
|
||||
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
|
||||
* socket created with AF_INET to an AF_INET6 address or vice versa. */
|
||||
return UV_EINVAL;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
tcp->delayed_error = UV__ERR(errno);
|
||||
tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
if (addr->sa_family == AF_INET6)
|
||||
@ -320,8 +321,16 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
return UV_EINVAL;
|
||||
|
||||
fd = uv__stream_fd(handle);
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
|
||||
return UV__ERR(errno);
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
|
||||
if (errno == EINVAL) {
|
||||
/* Open Group Specifications Issue 7, 2018 edition states that
|
||||
* EINVAL may mean the socket has been shut down already.
|
||||
* Behavior observed on Solaris, illumos and macOS. */
|
||||
errno = 0;
|
||||
} else {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
}
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
return 0;
|
||||
|
78
deps/libuv/src/unix/tty.c
vendored
78
deps/libuv/src/unix/tty.c
vendored
@ -66,6 +66,19 @@ static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
|
||||
int uv__tcsetattr(int fd, int how, const struct termios *term) {
|
||||
int rc;
|
||||
|
||||
do
|
||||
rc = tcsetattr(fd, how, term);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__tty_is_slave(const int fd) {
|
||||
int result;
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
@ -268,13 +281,18 @@ static void uv__tty_make_raw(struct termios* tio) {
|
||||
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
struct termios tmp;
|
||||
int fd;
|
||||
int rc;
|
||||
|
||||
if (tty->mode == (int) mode)
|
||||
return 0;
|
||||
|
||||
fd = uv__stream_fd(tty);
|
||||
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
|
||||
if (tcgetattr(fd, &tty->orig_termios))
|
||||
do
|
||||
rc = tcgetattr(fd, &tty->orig_termios);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
|
||||
if (rc == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* This is used for uv_tty_reset_mode() */
|
||||
@ -304,11 +322,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
|
||||
/* Apply changes after draining */
|
||||
if (tcsetattr(fd, TCSADRAIN, &tmp))
|
||||
return UV__ERR(errno);
|
||||
rc = uv__tcsetattr(fd, TCSADRAIN, &tmp);
|
||||
if (rc == 0)
|
||||
tty->mode = mode;
|
||||
|
||||
tty->mode = mode;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -331,7 +349,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
|
||||
|
||||
uv_handle_type uv_guess_handle(uv_file file) {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_storage ss;
|
||||
struct stat s;
|
||||
socklen_t len;
|
||||
int type;
|
||||
@ -342,8 +360,24 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
if (isatty(file))
|
||||
return UV_TTY;
|
||||
|
||||
if (fstat(file, &s))
|
||||
if (fstat(file, &s)) {
|
||||
#if defined(__PASE__)
|
||||
/* On ibmi receiving RST from TCP instead of FIN immediately puts fd into
|
||||
* an error state. fstat will return EINVAL, getsockname will also return
|
||||
* EINVAL, even if sockaddr_storage is valid. (If file does not refer to a
|
||||
* socket, ENOTSOCK is returned instead.)
|
||||
* In such cases, we will permit the user to open the connection as uv_tcp
|
||||
* still, so that the user can get immediately notified of the error in
|
||||
* their read callback and close this fd.
|
||||
*/
|
||||
len = sizeof(ss);
|
||||
if (getsockname(file, (struct sockaddr*) &ss, &len)) {
|
||||
if (errno == EINVAL)
|
||||
return UV_TCP;
|
||||
}
|
||||
#endif
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
if (S_ISREG(s.st_mode))
|
||||
return UV_FILE;
|
||||
@ -357,16 +391,29 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
if (!S_ISSOCK(s.st_mode))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(ss);
|
||||
if (getsockname(file, (struct sockaddr*) &ss, &len)) {
|
||||
#if defined(_AIX)
|
||||
/* On aix receiving RST from TCP instead of FIN immediately puts fd into
|
||||
* an error state. In such case getsockname will return EINVAL, even if
|
||||
* sockaddr_storage is valid.
|
||||
* In such cases, we will permit the user to open the connection as uv_tcp
|
||||
* still, so that the user can get immediately notified of the error in
|
||||
* their read callback and close this fd.
|
||||
*/
|
||||
if (errno == EINVAL) {
|
||||
return UV_TCP;
|
||||
}
|
||||
#endif
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
}
|
||||
|
||||
len = sizeof(type);
|
||||
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
len = sizeof(sa);
|
||||
if (getsockname(file, &sa, &len))
|
||||
return UV_UNKNOWN_HANDLE;
|
||||
|
||||
if (type == SOCK_DGRAM)
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
|
||||
return UV_UDP;
|
||||
|
||||
if (type == SOCK_STREAM) {
|
||||
@ -379,9 +426,9 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
return UV_NAMED_PIPE;
|
||||
#endif /* defined(_AIX) || defined(__DragonFly__) */
|
||||
|
||||
if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
|
||||
if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6)
|
||||
return UV_TCP;
|
||||
if (sa.sa_family == AF_UNIX)
|
||||
if (ss.ss_family == AF_UNIX)
|
||||
return UV_NAMED_PIPE;
|
||||
}
|
||||
|
||||
@ -403,8 +450,7 @@ int uv_tty_reset_mode(void) {
|
||||
|
||||
err = 0;
|
||||
if (orig_termios_fd != -1)
|
||||
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
|
||||
err = UV__ERR(errno);
|
||||
err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
|
||||
|
||||
uv_spinlock_unlock(&termios_spinlock);
|
||||
errno = saved_errno;
|
||||
|
9
deps/libuv/src/unix/udp.c
vendored
9
deps/libuv/src/unix/udp.c
vendored
@ -704,7 +704,16 @@ int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
#ifdef __PASE__
|
||||
/* On IBMi a connectionless transport socket can be disconnected by
|
||||
* either setting the addr parameter to NULL or setting the
|
||||
* addr_length parameter to zero, and issuing another connect().
|
||||
* https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/connec.htm
|
||||
*/
|
||||
r = connect(handle->io_watcher.fd, (struct sockaddr*) NULL, 0);
|
||||
#else
|
||||
r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
|
||||
#endif
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1) {
|
||||
|
4
deps/libuv/src/uv-common.c
vendored
4
deps/libuv/src/uv-common.c
vendored
@ -295,7 +295,9 @@ int uv_tcp_bind(uv_tcp_t* handle,
|
||||
|
||||
if (handle->type != UV_TCP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_closing(handle)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
|
13
deps/libuv/src/win/core.c
vendored
13
deps/libuv/src/win/core.c
vendored
@ -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
|
||||
|
2
deps/libuv/src/win/error.c
vendored
2
deps/libuv/src/win/error.c
vendored
@ -73,7 +73,6 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
|
||||
case ERROR_CANT_ACCESS_FILE: return UV_EACCES;
|
||||
case ERROR_ACCESS_DENIED: return UV_EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
@ -155,6 +154,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAENOTSOCK: return UV_ENOTSOCK;
|
||||
case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
|
||||
case ERROR_BROKEN_PIPE: return UV_EOF;
|
||||
case ERROR_ACCESS_DENIED: return UV_EPERM;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
|
||||
case ERROR_BAD_PIPE: return UV_EPIPE;
|
||||
case ERROR_NO_DATA: return UV_EPIPE;
|
||||
|
9
deps/libuv/src/win/internal.h
vendored
9
deps/libuv/src/win/internal.h
vendored
@ -88,6 +88,9 @@ void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* req);
|
||||
void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_connect_t* req);
|
||||
void uv__process_tcp_shutdown_req(uv_loop_t* loop,
|
||||
uv_tcp_t* stream,
|
||||
uv_shutdown_t* req);
|
||||
|
||||
void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
|
||||
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
|
||||
@ -130,6 +133,7 @@ int uv__pipe_write(uv_loop_t* loop,
|
||||
size_t nbufs,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb);
|
||||
void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req);
|
||||
|
||||
void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_req_t* req);
|
||||
@ -143,7 +147,6 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_shutdown_t* req);
|
||||
|
||||
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
|
||||
|
||||
|
||||
@ -177,7 +180,9 @@ void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
*/
|
||||
void uv__process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_connect_t* req);
|
||||
|
||||
void uv__process_tty_shutdown_req(uv_loop_t* loop,
|
||||
uv_tty_t* stream,
|
||||
uv_shutdown_t* req);
|
||||
void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
|
||||
|
||||
|
||||
|
464
deps/libuv/src/win/pipe.c
vendored
464
deps/libuv/src/win/pipe.c
vendored
@ -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,
|
||||
@ -578,135 +578,109 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
||||
}
|
||||
|
||||
|
||||
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
int err;
|
||||
void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t *req) {
|
||||
DWORD result;
|
||||
uv_shutdown_t* req;
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
FILE_PIPE_LOCAL_INFORMATION pipe_info;
|
||||
|
||||
assert(handle->flags & UV_HANDLE_CONNECTION);
|
||||
assert(req != NULL);
|
||||
assert(handle->stream.conn.write_reqs_pending == 0);
|
||||
SET_REQ_SUCCESS(req);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to avoid flushing the pipe buffer in the thread pool. */
|
||||
nt_status = pNtQueryInformationFile(handle->handle,
|
||||
&io_status,
|
||||
&pipe_info,
|
||||
sizeof pipe_info,
|
||||
FilePipeLocalInformation);
|
||||
|
||||
if (nt_status != STATUS_SUCCESS) {
|
||||
SET_REQ_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
|
||||
/* Short-circuit, no need to call FlushFileBuffers:
|
||||
* all writes have been read. */
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Run FlushFileBuffers in the thread pool. */
|
||||
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
|
||||
req,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
if (!result) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable. */
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
uv__ipc_xfer_queue_item_t* xfer_queue_item;
|
||||
|
||||
if ((handle->flags & UV_HANDLE_CONNECTION) &&
|
||||
handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
req = handle->stream.conn.shutdown_req;
|
||||
assert(handle->reqs_pending == 0);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
/* Clear the shutdown_req field so we don't go here again. */
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
/* Free pending sockets */
|
||||
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
|
||||
QUEUE* q;
|
||||
SOCKET socket;
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
|
||||
|
||||
/* Already closing. Cancel the shutdown. */
|
||||
if (req->cb) {
|
||||
req->cb(req, UV_ECANCELED);
|
||||
/* Materialize socket and close it */
|
||||
socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&xfer_queue_item->xfer_info.socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
uv__free(xfer_queue_item);
|
||||
|
||||
if (socket != INVALID_SOCKET)
|
||||
closesocket(socket);
|
||||
}
|
||||
handle->pipe.conn.ipc_xfer_queue_length = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to avoid flushing the pipe buffer in the thread pool. */
|
||||
nt_status = pNtQueryInformationFile(handle->handle,
|
||||
&io_status,
|
||||
&pipe_info,
|
||||
sizeof pipe_info,
|
||||
FilePipeLocalInformation);
|
||||
|
||||
if (nt_status != STATUS_SUCCESS) {
|
||||
/* Failure */
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
|
||||
if (req->cb) {
|
||||
err = pRtlNtStatusToDosError(nt_status);
|
||||
req->cb(req, uv_translate_sys_error(err));
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
|
||||
/* Short-circuit, no need to call FlushFileBuffers. */
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Run FlushFileBuffers in the thread pool. */
|
||||
result = QueueUserWorkItem(pipe_shutdown_thread_proc,
|
||||
req,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
if (result) {
|
||||
return;
|
||||
|
||||
} else {
|
||||
/* Failure. */
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
|
||||
if (req->cb) {
|
||||
err = GetLastError();
|
||||
req->cb(req, uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
}
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
|
||||
DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
/* Free pending sockets */
|
||||
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
|
||||
QUEUE* q;
|
||||
SOCKET socket;
|
||||
|
||||
q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
|
||||
|
||||
/* Materialize socket and close it */
|
||||
socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&xfer_queue_item->xfer_info.socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
uv__free(xfer_queue_item);
|
||||
|
||||
if (socket != INVALID_SOCKET)
|
||||
closesocket(socket);
|
||||
}
|
||||
handle->pipe.conn.ipc_xfer_queue_length = 0;
|
||||
|
||||
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 != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
|
||||
DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
assert(handle->pipe.serv.accept_reqs);
|
||||
uv__free(handle->pipe.serv.accept_reqs);
|
||||
handle->pipe.serv.accept_reqs = NULL;
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
assert(handle->pipe.serv.accept_reqs);
|
||||
uv__free(handle->pipe.serv.accept_reqs);
|
||||
handle->pipe.serv.accept_reqs = NULL;
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
|
||||
@ -731,7 +705,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
if (!name) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (uv__is_closing(handle)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
|
||||
handle->pipe.serv.pending_instances = default_pending_pipe_instances;
|
||||
}
|
||||
@ -815,7 +791,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 +801,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 +826,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 +877,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 +917,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;
|
||||
@ -973,17 +953,30 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
|
||||
void uv__pipe_read_stop(uv_pipe_t* handle) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(handle->loop, handle);
|
||||
|
||||
uv__pipe_interrupt_read(handle);
|
||||
}
|
||||
|
||||
|
||||
/* Cleans up uv_pipe_t (server or connection) and all resources associated with
|
||||
* it. */
|
||||
void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
int i;
|
||||
HANDLE pipeHandle;
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
handle->flags &= ~UV_HANDLE_LISTENING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
|
||||
uv__handle_closing(handle);
|
||||
|
||||
uv__pipe_interrupt_read(handle);
|
||||
|
||||
if (handle->name) {
|
||||
@ -1003,35 +996,17 @@ void uv__pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
handle->flags &= ~UV_HANDLE_WRITABLE;
|
||||
eof_timer_destroy(handle);
|
||||
}
|
||||
|
||||
if ((handle->flags & UV_HANDLE_CONNECTION)
|
||||
&& handle->handle != INVALID_HANDLE_VALUE)
|
||||
&& handle->handle != INVALID_HANDLE_VALUE) {
|
||||
/* This will eventually destroy the write queue for us too. */
|
||||
close_pipe(handle);
|
||||
}
|
||||
|
||||
|
||||
void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
handle->flags &= ~UV_HANDLE_LISTENING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
uv__pipe_cleanup(loop, handle);
|
||||
|
||||
if (handle->reqs_pending == 0) {
|
||||
if (handle->reqs_pending == 0)
|
||||
uv__want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
uv__handle_closing(handle);
|
||||
}
|
||||
|
||||
|
||||
@ -1099,6 +1074,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 +1086,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;
|
||||
|
||||
@ -2094,10 +2069,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv__queue_non_overlapped_write(handle);
|
||||
}
|
||||
|
||||
if (handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
if (handle->stream.conn.write_reqs_pending == 0)
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
@ -2110,7 +2084,7 @@ void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* The req->pipeHandle should be freed already in uv__pipe_cleanup(). */
|
||||
/* The req->pipeHandle should be freed already in uv__pipe_close(). */
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
@ -2140,52 +2114,72 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_shutdown_t* req) {
|
||||
int err;
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
/* Clear the shutdown_req field so we don't go here again. */
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
handle->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
if (handle->flags & UV_HANDLE_READABLE) {
|
||||
/* Initialize and optionally start the eof timer. Only do this if the pipe
|
||||
* is readable and we haven't seen EOF come in ourselves. */
|
||||
eof_timer_init(handle);
|
||||
|
||||
/* If reading start the timer right now. Otherwise uv__pipe_queue_read will
|
||||
* start it. */
|
||||
if (handle->flags & UV_HANDLE_READ_PENDING) {
|
||||
eof_timer_start(handle);
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* Already closing. Cancel the shutdown. */
|
||||
err = UV_ECANCELED;
|
||||
} else if (!REQ_SUCCESS(req)) {
|
||||
/* An error occurred in trying to shutdown gracefully. */
|
||||
err = uv_translate_sys_error(GET_REQ_ERROR(req));
|
||||
} else {
|
||||
/* This pipe is not readable. We can just close it to let the other end
|
||||
* know that we're done writing. */
|
||||
close_pipe(handle);
|
||||
if (handle->flags & UV_HANDLE_READABLE) {
|
||||
/* Initialize and optionally start the eof timer. Only do this if the pipe
|
||||
* is readable and we haven't seen EOF come in ourselves. */
|
||||
eof_timer_init(handle);
|
||||
|
||||
/* If reading start the timer right now. Otherwise uv__pipe_queue_read will
|
||||
* start it. */
|
||||
if (handle->flags & UV_HANDLE_READ_PENDING) {
|
||||
eof_timer_start(handle);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* This pipe is not readable. We can just close it to let the other end
|
||||
* know that we're done writing. */
|
||||
close_pipe(handle);
|
||||
}
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (req->cb) {
|
||||
req->cb(req, 0);
|
||||
}
|
||||
if (req->cb)
|
||||
req->cb(req, err);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
@ -2200,7 +2194,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 +2275,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 +2301,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 +2329,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 +2363,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 +2545,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;
|
||||
}
|
||||
|
||||
|
13
deps/libuv/src/win/req-inl.h
vendored
13
deps/libuv/src/win/req-inl.h
vendored
@ -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;
|
||||
@ -172,12 +172,7 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) {
|
||||
break;
|
||||
|
||||
case UV_SHUTDOWN:
|
||||
/* Tcp shutdown requests don't come here. */
|
||||
assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
|
||||
uv__process_pipe_shutdown_req(
|
||||
loop,
|
||||
(uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
|
||||
(uv_shutdown_t*) req);
|
||||
DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle);
|
||||
break;
|
||||
|
||||
case UV_UDP_RECV:
|
||||
@ -214,8 +209,6 @@ INLINE static int uv__process_reqs(uv_loop_t* loop) {
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* UV_WIN_REQ_INL_H_ */
|
||||
|
11
deps/libuv/src/win/stream.c
vendored
11
deps/libuv/src/win/stream.c
vendored
@ -29,7 +29,9 @@
|
||||
|
||||
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
|
||||
int err;
|
||||
|
||||
if (uv__is_closing(stream)) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
switch (stream->type) {
|
||||
case UV_TCP:
|
||||
@ -217,7 +219,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
if (handle->stream.conn.write_reqs_pending == 0) {
|
||||
if (handle->type == UV_NAMED_PIPE)
|
||||
uv__pipe_shutdown(loop, (uv_pipe_t*) handle, req);
|
||||
else
|
||||
uv__insert_pending_req(loop, (uv_req_t*) req);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
139
deps/libuv/src/win/tcp.c
vendored
139
deps/libuv/src/win/tcp.c
vendored
@ -205,73 +205,76 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown_t *req) {
|
||||
int err;
|
||||
|
||||
assert(req);
|
||||
assert(stream->stream.conn.write_reqs_pending == 0);
|
||||
assert(!(stream->flags & UV_HANDLE_SHUT));
|
||||
assert(stream->flags & UV_HANDLE_CONNECTION);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
|
||||
err = 0;
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
/* The user destroyed the stream before we got to do the shutdown. */
|
||||
err = UV_ECANCELED;
|
||||
else if (shutdown(stream->socket, SD_SEND) == SOCKET_ERROR)
|
||||
err = uv_translate_sys_error(WSAGetLastError());
|
||||
else /* Success. */
|
||||
stream->flags |= UV_HANDLE_SHUT;
|
||||
|
||||
if (req->cb)
|
||||
req->cb(req, err);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(stream);
|
||||
}
|
||||
|
||||
|
||||
void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
unsigned int i;
|
||||
uv_tcp_accept_t* req;
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION &&
|
||||
handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(handle->reqs_pending == 0);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
assert(handle->socket == INVALID_SOCKET);
|
||||
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
|
||||
|
||||
err = 0;
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
} else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
|
||||
err = WSAGetLastError();
|
||||
}
|
||||
|
||||
if (handle->stream.conn.shutdown_req->cb) {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
|
||||
uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
assert(handle->socket == INVALID_SOCKET);
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
|
||||
req = &handle->tcp.serv.accept_reqs[i];
|
||||
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
|
||||
req = &handle->tcp.serv.accept_reqs[i];
|
||||
if (req->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(handle->tcp.serv.accept_reqs);
|
||||
handle->tcp.serv.accept_reqs = NULL;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION &&
|
||||
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 != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
loop->active_tcp_streams--;
|
||||
uv__free(handle->tcp.serv.accept_reqs);
|
||||
handle->tcp.serv.accept_reqs = NULL;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CONNECTION &&
|
||||
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 != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
loop->active_tcp_streams--;
|
||||
}
|
||||
|
||||
|
||||
@ -1160,9 +1163,10 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
closesocket(handle->socket);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
}
|
||||
if (handle->stream.conn.shutdown_req != NULL) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
uv__process_tcp_shutdown_req(loop,
|
||||
handle,
|
||||
handle->stream.conn.shutdown_req);
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
@ -1411,7 +1415,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 +1462,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
|
||||
@ -1483,6 +1487,9 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
DECREASE_ACTIVE_COUNT(loop, tcp);
|
||||
}
|
||||
|
||||
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
uv__handle_closing(tcp);
|
||||
|
||||
/* If any overlapped req failed to cancel, calling `closesocket` now would
|
||||
* cause Win32 to send an RST packet. Try to avoid that for writes, if
|
||||
* possibly applicable, by waiting to process the completion notifications
|
||||
@ -1494,12 +1501,8 @@ void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
tcp->socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
uv__handle_closing(tcp);
|
||||
|
||||
if (tcp->reqs_pending == 0) {
|
||||
uv__want_endgame(tcp->loop, (uv_handle_t*)tcp);
|
||||
}
|
||||
if (tcp->reqs_pending == 0)
|
||||
uv__want_endgame(loop, (uv_handle_t*) tcp);
|
||||
}
|
||||
|
||||
|
||||
|
68
deps/libuv/src/win/tty.c
vendored
68
deps/libuv/src/win/tty.c
vendored
@ -2237,11 +2237,13 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
req->cb(req, uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
|
||||
handle->stream.conn.write_reqs_pending--;
|
||||
if (handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
uv__want_endgame(loop, (uv_handle_t*)handle);
|
||||
}
|
||||
if (handle->stream.conn.write_reqs_pending == 0)
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
uv__process_tty_shutdown_req(loop,
|
||||
handle,
|
||||
handle->stream.conn.shutdown_req);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
@ -2262,43 +2264,43 @@ void uv__tty_close(uv_tty_t* handle) {
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->reqs_pending == 0) {
|
||||
if (handle->reqs_pending == 0)
|
||||
uv__want_endgame(handle->loop, (uv_handle_t*) handle);
|
||||
}
|
||||
|
||||
|
||||
void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) {
|
||||
assert(stream->stream.conn.write_reqs_pending == 0);
|
||||
assert(req);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
if (req->cb) {
|
||||
if (stream->flags & UV_HANDLE_CLOSING) {
|
||||
req->cb(req, UV_ECANCELED);
|
||||
} else {
|
||||
req->cb(req, 0);
|
||||
}
|
||||
}
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(stream);
|
||||
}
|
||||
|
||||
|
||||
void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
|
||||
handle->stream.conn.shutdown_req != NULL &&
|
||||
handle->stream.conn.write_reqs_pending == 0) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(handle->reqs_pending == 0);
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
if (handle->stream.conn.shutdown_req->cb) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
|
||||
} else {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
|
||||
}
|
||||
}
|
||||
/* The wait handle used for raw reading should be unregistered when the
|
||||
* wait callback runs. */
|
||||
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
|
||||
handle->tty.rd.read_raw_wait == NULL);
|
||||
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
/* The wait handle used for raw reading should be unregistered when the
|
||||
* wait callback runs. */
|
||||
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
|
||||
handle->tty.rd.read_raw_wait == NULL);
|
||||
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
|
||||
|
5
deps/libuv/src/win/udp.c
vendored
5
deps/libuv/src/win/udp.c
vendored
@ -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());
|
||||
|
||||
@ -1146,6 +1146,7 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
addr = (const struct sockaddr*) &converted;
|
||||
}
|
||||
|
||||
/* Already sending a message.*/
|
||||
@ -1169,7 +1170,7 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
nbufs,
|
||||
&bytes,
|
||||
0,
|
||||
(const struct sockaddr*) &converted,
|
||||
addr,
|
||||
addrlen,
|
||||
NULL,
|
||||
NULL);
|
||||
|
Reference in New Issue
Block a user