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:
2022-07-24 21:25:38 +00:00
parent 41afc3bdd6
commit f06753b56e
67 changed files with 2148 additions and 764 deletions

52
deps/libuv/src/strtok.c vendored Normal file
View 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
View 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_ */

View File

@ -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
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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), &reg_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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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) */

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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)

View File

@ -592,7 +592,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout;
int r;
int ran_pending;
int can_sleep;
r = uv__loop_alive(loop);
if (!r)
@ -602,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv_update_time(loop);
uv__run_timers(loop);
ran_pending = uv__process_reqs(loop);
can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
uv__process_reqs(loop);
uv__idle_invoke(loop);
uv__prepare_invoke(loop);
timeout = 0;
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx)
@ -615,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
else
uv__poll_wine(loop, timeout);
/* Process immediate callbacks (e.g. write_cb) a small fixed number of
* times to avoid loop starvation.*/
for (r = 0; r < 8 && loop->pending_reqs_tail != NULL; r++)
uv__process_reqs(loop);
/* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This
* call will be ignored if the provider_entry_time was either never set (if

View File

@ -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;

View File

@ -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);

View File

@ -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, &current_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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);