Merge branch 'upstream-libuv' into update-libuv

* upstream-libuv:
  libuv 2022-07-12 (0c1fa696)
This commit is contained in:
Brad King
2022-09-22 14:10:43 -04:00
52 changed files with 2537 additions and 1430 deletions

View File

@@ -1150,8 +1150,8 @@ struct uv_interface_address_s {
struct uv_passwd_s { struct uv_passwd_s {
char* username; char* username;
long uid; unsigned long uid;
long gid; unsigned long gid;
char* shell; char* shell;
char* homedir; char* homedir;
}; };
@@ -1259,6 +1259,7 @@ UV_EXTERN uv_pid_t uv_os_getppid(void);
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority); UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority); UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
UV_EXTERN unsigned int uv_available_parallelism(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count); UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count); UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
UV_EXTERN int uv_cpumask_size(void); UV_EXTERN int uv_cpumask_size(void);

View File

@@ -31,10 +31,10 @@
*/ */
#define UV_VERSION_MAJOR 1 #define UV_VERSION_MAJOR 1
#define UV_VERSION_MINOR 43 #define UV_VERSION_MINOR 44
#define UV_VERSION_PATCH 1 #define UV_VERSION_PATCH 2
#define UV_VERSION_IS_RELEASE 0 #define UV_VERSION_IS_RELEASE 1
#define UV_VERSION_SUFFIX "dev" #define UV_VERSION_SUFFIX ""
#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \ #define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
(UV_VERSION_MINOR << 8) | \ (UV_VERSION_MINOR << 8) | \

View File

@@ -234,7 +234,7 @@ typedef struct _AFD_POLL_INFO {
AFD_POLL_HANDLE_INFO Handles[1]; AFD_POLL_HANDLE_INFO Handles[1];
} AFD_POLL_INFO, *PAFD_POLL_INFO; } AFD_POLL_INFO, *PAFD_POLL_INFO;
#define UV_MSAFD_PROVIDER_COUNT 3 #define UV_MSAFD_PROVIDER_COUNT 4
/** /**
@@ -388,6 +388,12 @@ typedef struct {
OVERLAPPED overlapped; \ OVERLAPPED overlapped; \
size_t queued_bytes; \ size_t queued_bytes; \
} io; \ } io; \
/* in v2, we can move these to the UV_CONNECT_PRIVATE_FIELDS */ \
struct { \
ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\
HANDLE pipeHandle; \
DWORD duplex_flags; \
} connect; \
} u; \ } u; \
struct uv_req_s* next_req; struct uv_req_s* next_req;

View File

@@ -25,7 +25,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include "win/internal.h" #include "win/internal.h"
#include "win/handle-inl.h" #include "win/handle-inl.h"
#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h)) #define uv__make_close_pending(h) uv__want_endgame((h)->loop, (h))
#else #else
#include "unix/internal.h" #include "unix/internal.h"
#endif #endif

View File

@@ -21,6 +21,7 @@
#include "idna.h" #include "idna.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <limits.h> /* UINT_MAX */
static unsigned uv__utf8_decode1_slow(const char** p, static unsigned uv__utf8_decode1_slow(const char** p,
const char* pe, const char* pe,
@@ -129,7 +130,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
while (s < se) { while (s < se) {
c = uv__utf8_decode1(&s, se); c = uv__utf8_decode1(&s, se);
if (c == -1u) if (c == UINT_MAX)
return UV_EINVAL; return UV_EINVAL;
if (c < 128) if (c < 128)
@@ -151,7 +152,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
s = ss; s = ss;
while (s < se) { while (s < se) {
c = uv__utf8_decode1(&s, se); c = uv__utf8_decode1(&s, se);
assert(c != -1u); assert(c != UINT_MAX);
if (c > 127) if (c > 127)
continue; continue;
@@ -182,7 +183,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
while (s < se) { while (s < se) {
c = uv__utf8_decode1(&s, se); c = uv__utf8_decode1(&s, se);
assert(c != -1u); assert(c != UINT_MAX);
if (c >= n) if (c >= n)
if (c < m) if (c < m)
@@ -201,7 +202,7 @@ static int uv__idna_toascii_label(const char* s, const char* se,
s = ss; s = ss;
while (s < se) { while (s < se) {
c = uv__utf8_decode1(&s, se); c = uv__utf8_decode1(&s, se);
assert(c != -1u); assert(c != UINT_MAX);
if (c < n) if (c < n)
if (++delta == 0) if (++delta == 0)
@@ -280,7 +281,7 @@ long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
st = si; st = si;
c = uv__utf8_decode1(&si, se); c = uv__utf8_decode1(&si, se);
if (c == -1u) if (c == UINT_MAX)
return UV_EINVAL; return UV_EINVAL;
if (c != '.') if (c != '.')

View File

@@ -28,7 +28,7 @@
*/ */
#include "uv.h" #include "uv.h"
/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates /* Copies up to |n-1| bytes from |s| to |d| and always zero-terminates
* the result, except when |n==0|. Returns the number of bytes copied * the result, except when |n==0|. Returns the number of bytes copied
* or UV_E2BIG if |d| is too small. * or UV_E2BIG if |d| is too small.
* *

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

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

@@ -43,12 +43,11 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
__compare_and_swap((volatile int*)ptr, &oldval, newval); __compare_and_swap((volatile int*)ptr, &oldval, newval);
return oldval; return oldval;
#elif defined(__MVS__) #elif defined(__MVS__)
unsigned int op4; /* Use hand-rolled assembly because codegen from builtin __plo_CSST results in
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval, * a runtime bug.
(unsigned int*) ptr, *ptr, &op4)) */
return oldval; __asm(" cs %0,%2,%1 \n " : "+r"(oldval), "+m"(*ptr) : "r"(newval) :);
else return oldval;
return op4;
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval); return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
#else #else
@@ -61,7 +60,9 @@ UV_UNUSED(static void cpu_relax(void)) {
__asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */ __asm__ __volatile__ ("rep; nop" ::: "memory"); /* a.k.a. PAUSE */
#elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__) #elif (defined(__arm__) && __ARM_ARCH >= 7) || defined(__aarch64__)
__asm__ __volatile__ ("yield" ::: "memory"); __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"); __asm__ __volatile__ ("or 1,1,1; or 2,2,2" ::: "memory");
#endif #endif
} }

View File

@@ -27,7 +27,7 @@
#include <ifaddrs.h> #include <ifaddrs.h>
#include <net/if.h> #include <net/if.h>
#if !defined(__CYGWIN__) && !defined(__MSYS__) #if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
#include <net/if_dl.h> #include <net/if_dl.h>
#endif #endif
@@ -40,7 +40,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return 1; return 1;
if (ent->ifa_addr == NULL) if (ent->ifa_addr == NULL)
return 1; return 1;
#if !defined(__CYGWIN__) && !defined(__MSYS__) #if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__GNU__)
/* /*
* If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family` * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, return whether `sa_family`
* equals `AF_LINK`. Otherwise, the result depends on the operating * equals `AF_LINK`. Otherwise, the result depends on the operating
@@ -69,7 +69,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs* addrs; struct ifaddrs* addrs;
struct ifaddrs* ent; struct ifaddrs* ent;
uv_interface_address_t* address; uv_interface_address_t* address;
#if !(defined(__CYGWIN__) || defined(__MSYS__)) #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
int i; int i;
#endif #endif
@@ -126,7 +126,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
address++; address++;
} }
#if !(defined(__CYGWIN__) || defined(__MSYS__)) #if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
/* Fill in physical addresses for each interface */ /* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) { for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS)) if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))

View File

@@ -38,6 +38,7 @@ static void init_process_title_mutex_once(void) {
void uv__process_title_cleanup(void) { void uv__process_title_cleanup(void) {
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
uv_mutex_destroy(&process_title_mutex); uv_mutex_destroy(&process_title_mutex);
} }

View File

@@ -20,6 +20,7 @@
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"
#include "strtok.h"
#include <stddef.h> /* NULL */ #include <stddef.h> /* NULL */
#include <stdio.h> /* printf */ #include <stdio.h> /* printf */
@@ -86,10 +87,12 @@ extern char** environ;
#endif #endif
#if defined(__MVS__) #if defined(__MVS__)
#include <sys/ioctl.h> # include <sys/ioctl.h>
# include "zos-sys-info.h"
#endif #endif
#if defined(__linux__) #if defined(__linux__)
# include <sched.h>
# include <sys/syscall.h> # include <sys/syscall.h>
# define uv__accept4 accept4 # define uv__accept4 accept4
#endif #endif
@@ -98,7 +101,7 @@ extern char** environ;
# include <sanitizer/linux_syscall_hooks.h> # include <sanitizer/linux_syscall_hooks.h>
#endif #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. */ /* Verify that uv_buf_t is ABI-compatible with struct iovec. */
STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec)); STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
@@ -164,6 +167,15 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
case UV_FS_EVENT: case UV_FS_EVENT:
uv__fs_event_close((uv_fs_event_t*)handle); 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; break;
case UV_POLL: case UV_POLL:
@@ -340,42 +352,43 @@ int uv_backend_fd(const uv_loop_t* loop) {
} }
int uv_backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag != 0)
return 0;
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
return 0;
if (!QUEUE_EMPTY(&loop->idle_handles))
return 0;
if (!QUEUE_EMPTY(&loop->pending_queue))
return 0;
if (loop->closing_handles)
return 0;
return uv__next_timeout(loop);
}
static int uv__loop_alive(const uv_loop_t* loop) { static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) || return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) || uv__has_active_reqs(loop) ||
!QUEUE_EMPTY(&loop->pending_queue) ||
loop->closing_handles != NULL; loop->closing_handles != NULL;
} }
static int uv__backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag == 0 &&
/* uv__loop_alive(loop) && */
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
QUEUE_EMPTY(&loop->pending_queue) &&
QUEUE_EMPTY(&loop->idle_handles) &&
loop->closing_handles == NULL)
return uv__next_timeout(loop);
return 0;
}
int uv_backend_timeout(const uv_loop_t* loop) {
if (QUEUE_EMPTY(&loop->watcher_queue))
return uv__backend_timeout(loop);
/* Need to call uv_run to update the backend fd state. */
return 0;
}
int uv_loop_alive(const uv_loop_t* loop) { int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop); return uv__loop_alive(loop);
} }
int uv_run(uv_loop_t* loop, uv_run_mode mode) { int uv_run(uv_loop_t* loop, uv_run_mode mode) {
int timeout; int timeout;
int r; int r;
int ran_pending; int can_sleep;
r = uv__loop_alive(loop); r = uv__loop_alive(loop);
if (!r) if (!r)
@@ -384,16 +397,25 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) {
while (r != 0 && loop->stop_flag == 0) { while (r != 0 && loop->stop_flag == 0) {
uv__update_time(loop); uv__update_time(loop);
uv__run_timers(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_idle(loop);
uv__run_prepare(loop); uv__run_prepare(loop);
timeout = 0; 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); timeout = uv__backend_timeout(loop);
uv__io_poll(loop, timeout); 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 /* 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 * 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 * call will be ignored if the provider_entry_time was either never set (if
@@ -603,20 +625,6 @@ int uv__nonblock_ioctl(int fd, int set) {
return 0; return 0;
} }
int uv__cloexec_ioctl(int fd, int set) {
int r;
do
r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
while (r == -1 && errno == EINTR);
if (r)
return UV__ERR(errno);
return 0;
}
#endif #endif
@@ -651,25 +659,13 @@ int uv__nonblock_fcntl(int fd, int set) {
} }
int uv__cloexec_fcntl(int fd, int set) { int uv__cloexec(int fd, int set) {
int flags; int flags;
int r; int r;
do flags = 0;
r = fcntl(fd, F_GETFD);
while (r == -1 && errno == EINTR);
if (r == -1)
return UV__ERR(errno);
/* Bail out now if already set/clear. */
if (!!(r & FD_CLOEXEC) == !!set)
return 0;
if (set) if (set)
flags = r | FD_CLOEXEC; flags = FD_CLOEXEC;
else
flags = r & ~FD_CLOEXEC;
do do
r = fcntl(fd, F_SETFD, flags); r = fcntl(fd, F_SETFD, flags);
@@ -683,28 +679,23 @@ int uv__cloexec_fcntl(int fd, int set) {
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { 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; 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* pfd;
int* end; int* end;
#if defined(__linux__) ssize_t rc;
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
rc = recvmsg(fd, msg, flags); rc = recvmsg(fd, msg, flags);
#endif
if (rc == -1) if (rc == -1)
return UV__ERR(errno); return UV__ERR(errno);
if (msg->msg_controllen == 0) if (msg->msg_controllen == 0)
@@ -717,6 +708,7 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
pfd += 1) pfd += 1)
uv__cloexec(*pfd, 1); uv__cloexec(*pfd, 1);
return rc; return rc;
#endif
} }
@@ -809,14 +801,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* q;
QUEUE pq; QUEUE pq;
uv__io_t* w; uv__io_t* w;
if (QUEUE_EMPTY(&loop->pending_queue))
return 0;
QUEUE_MOVE(&loop->pending_queue, &pq); QUEUE_MOVE(&loop->pending_queue, &pq);
while (!QUEUE_EMPTY(&pq)) { while (!QUEUE_EMPTY(&pq)) {
@@ -826,8 +815,6 @@ static int uv__run_pending(uv_loop_t* loop) {
w = QUEUE_DATA(q, uv__io_t, pending_queue); w = QUEUE_DATA(q, uv__io_t, pending_queue);
w->cb(loop, w, POLLOUT); w->cb(loop, w, POLLOUT);
} }
return 1;
} }
@@ -1042,6 +1029,32 @@ int uv__open_cloexec(const char* path, int flags) {
} }
int uv__slurp(const char* filename, char* buf, size_t len) {
ssize_t n;
int fd;
assert(len > 0);
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return fd;
do
n = read(fd, buf, len - 1);
while (n == -1 && errno == EINTR);
if (uv__close_nocheckstdio(fd))
abort();
if (n < 0)
return UV__ERR(errno);
buf[n] = '\0';
return 0;
}
int uv__dup2_cloexec(int oldfd, int newfd) { int uv__dup2_cloexec(int oldfd, int newfd) {
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__) #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
int r; int r;
@@ -1166,24 +1179,17 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
size_t name_size; size_t name_size;
size_t homedir_size; size_t homedir_size;
size_t shell_size; size_t shell_size;
long initsize;
int r; int r;
if (pwd == NULL) if (pwd == NULL)
return UV_EINVAL; return UV_EINVAL;
initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (initsize <= 0)
bufsize = 4096;
else
bufsize = (size_t) initsize;
uid = geteuid(); uid = geteuid();
buf = NULL;
for (;;) { /* Calling sysconf(_SC_GETPW_R_SIZE_MAX) would get the suggested size, but it
uv__free(buf); * 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); buf = uv__malloc(bufsize);
if (buf == NULL) if (buf == NULL)
@@ -1193,21 +1199,18 @@ int uv__getpwuid_r(uv_passwd_t* pwd) {
r = getpwuid_r(uid, &pw, buf, bufsize, &result); r = getpwuid_r(uid, &pw, buf, bufsize, &result);
while (r == EINTR); while (r == EINTR);
if (r != 0 || result == NULL)
uv__free(buf);
if (r != ERANGE) if (r != ERANGE)
break; break;
bufsize *= 2;
} }
if (r != 0) { if (r != 0)
uv__free(buf);
return UV__ERR(r); return UV__ERR(r);
}
if (result == NULL) { if (result == NULL)
uv__free(buf);
return UV_ENOENT; return UV_ENOENT;
}
/* Allocate memory for the username, shell, and home directory */ /* Allocate memory for the username, shell, and home directory */
name_size = strlen(pw.pw_name) + 1; name_size = strlen(pw.pw_name) + 1;
@@ -1569,6 +1572,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
char* cloned_path; char* cloned_path;
char* path_env; char* path_env;
char* token; char* token;
char* itr;
if (buf == NULL || buflen == NULL || *buflen == 0) if (buf == NULL || buflen == NULL || *buflen == 0)
return UV_EINVAL; return UV_EINVAL;
@@ -1610,7 +1614,7 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
if (cloned_path == NULL) if (cloned_path == NULL)
return UV_ENOMEM; return UV_ENOMEM;
token = strtok(cloned_path, ":"); token = uv__strtok(cloned_path, ":", &itr);
while (token != NULL) { while (token != NULL) {
snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog); snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, prog);
if (realpath(trypath, abspath) == abspath) { if (realpath(trypath, abspath) == abspath) {
@@ -1629,10 +1633,50 @@ int uv__search_path(const char* prog, char* buf, size_t* buflen) {
return 0; return 0;
} }
} }
token = strtok(NULL, ":"); token = uv__strtok(NULL, ":", &itr);
} }
uv__free(cloned_path); uv__free(cloned_path);
/* Out of tokens (path entries), and no match found */ /* Out of tokens (path entries), and no match found */
return UV_EINVAL; return UV_EINVAL;
} }
unsigned int uv_available_parallelism(void) {
#ifdef __linux__
cpu_set_t set;
long rc;
memset(&set, 0, sizeof(set));
/* sysconf(_SC_NPROCESSORS_ONLN) in musl calls sched_getaffinity() but in
* glibc it's... complicated... so for consistency try sched_getaffinity()
* before falling back to sysconf(_SC_NPROCESSORS_ONLN).
*/
if (0 == sched_getaffinity(0, sizeof(set), &set))
rc = CPU_COUNT(&set);
else
rc = sysconf(_SC_NPROCESSORS_ONLN);
if (rc < 1)
rc = 1;
return (unsigned) rc;
#elif defined(__MVS__)
int rc;
rc = __get_num_online_cpus();
if (rc < 1)
rc = 1;
return (unsigned) rc;
#else /* __linux__ */
long rc;
rc = sysconf(_SC_NPROCESSORS_ONLN);
if (rc < 1)
rc = 1;
return (unsigned) rc;
#endif /* __linux__ */
}

View File

@@ -287,3 +287,18 @@ int uv__recvmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen) {
return errno = ENOSYS, -1; return errno = ENOSYS, -1;
#endif #endif
} }
ssize_t
uv__fs_copy_file_range(int fd_in,
off_t* off_in,
int fd_out,
off_t* off_out,
size_t len,
unsigned int flags)
{
#if __FreeBSD__ >= 13 && !defined(__DragonFly__)
return copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
#else
return errno = ENOSYS, -1;
#endif
}

View File

@@ -247,7 +247,8 @@ UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
static ssize_t uv__fs_futime(uv_fs_t* req) { static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \ #if defined(__linux__) \
|| defined(_AIX71) \ || defined(_AIX71) \
|| defined(__HAIKU__) || defined(__HAIKU__) \
|| defined(__GNU__)
struct timespec ts[2]; struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime); ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime); ts[1] = uv__fs_to_timespec(req->mtime);
@@ -1085,6 +1086,17 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
*/ */
#if defined(__FreeBSD__) || defined(__DragonFly__) #if defined(__FreeBSD__) || defined(__DragonFly__)
#if defined(__FreeBSD__)
off_t off;
off = req->off;
r = uv__fs_copy_file_range(in_fd, &off, out_fd, NULL, req->bufsml[0].len, 0);
if (r >= 0) {
r = off - req->off;
req->off = off;
return r;
}
#endif
len = 0; len = 0;
r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0); r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
#elif defined(__FreeBSD_kernel__) #elif defined(__FreeBSD_kernel__)
@@ -1179,7 +1191,9 @@ static ssize_t uv__fs_lutime(uv_fs_t* req) {
#if defined(__linux__) || \ #if defined(__linux__) || \
defined(_AIX71) || \ defined(_AIX71) || \
defined(__sun) || \ defined(__sun) || \
defined(__HAIKU__) defined(__HAIKU__) || \
defined(__GNU__) || \
defined(__OpenBSD__)
struct timespec ts[2]; struct timespec ts[2];
ts[0] = uv__fs_to_timespec(req->atime); ts[0] = uv__fs_to_timespec(req->atime);
ts[1] = uv__fs_to_timespec(req->mtime); ts[1] = uv__fs_to_timespec(req->mtime);

View File

@@ -0,0 +1,167 @@
/* 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.
*/
#define _GNU_SOURCE 1
#include "uv.h"
#include "internal.h"
#include <hurd.h>
#include <hurd/process.h>
#include <mach/task_info.h>
#include <mach/vm_statistics.h>
#include <mach/vm_param.h>
#include <inttypes.h>
#include <stddef.h>
#include <unistd.h>
#include <string.h>
#include <limits.h>
int uv_exepath(char* buffer, size_t* size) {
kern_return_t err;
/* XXX in current Hurd, strings are char arrays of 1024 elements */
string_t exepath;
ssize_t copied;
if (buffer == NULL || size == NULL || *size == 0)
return UV_EINVAL;
if (*size - 1 > 0) {
/* XXX limited length of buffer in current Hurd, this API will probably
* evolve in the future */
err = proc_get_exe(getproc(), getpid(), exepath);
if (err)
return UV__ERR(err);
}
copied = uv__strscpy(buffer, exepath, *size);
/* do not return error on UV_E2BIG failure */
*size = copied < 0 ? strlen(buffer) : (size_t) copied;
return 0;
}
int uv_resident_set_memory(size_t* rss) {
kern_return_t err;
struct task_basic_info bi;
mach_msg_type_number_t count;
count = TASK_BASIC_INFO_COUNT;
err = task_info(mach_task_self(), TASK_BASIC_INFO,
(task_info_t) &bi, &count);
if (err)
return UV__ERR(err);
*rss = bi.resident_size;
return 0;
}
uint64_t uv_get_free_memory(void) {
kern_return_t err;
struct vm_statistics vmstats;
err = vm_statistics(mach_task_self(), &vmstats);
if (err)
return 0;
return vmstats.free_count * vm_page_size;
}
uint64_t uv_get_total_memory(void) {
kern_return_t err;
host_basic_info_data_t hbi;
mach_msg_type_number_t cnt;
cnt = HOST_BASIC_INFO_COUNT;
err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt);
if (err)
return 0;
return hbi.memory_size;
}
int uv_uptime(double* uptime) {
char buf[128];
/* Try /proc/uptime first */
if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
if (1 == sscanf(buf, "%lf", uptime))
return 0;
/* Reimplement here code from procfs to calculate uptime if not mounted? */
return UV__ERR(EIO);
}
void uv_loadavg(double avg[3]) {
char buf[128]; /* Large enough to hold all of /proc/loadavg. */
if (0 == uv__slurp("/proc/loadavg", buf, sizeof(buf)))
if (3 == sscanf(buf, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]))
return;
/* Reimplement here code from procfs to calculate loadavg if not mounted? */
}
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
kern_return_t err;
host_basic_info_data_t hbi;
mach_msg_type_number_t cnt;
/* Get count of cpus */
cnt = HOST_BASIC_INFO_COUNT;
err = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t) &hbi, &cnt);
if (err) {
err = UV__ERR(err);
goto abort;
}
/* XXX not implemented on the Hurd */
*cpu_infos = uv__calloc(hbi.avail_cpus, sizeof(**cpu_infos));
if (*cpu_infos == NULL) {
err = UV_ENOMEM;
goto abort;
}
*count = hbi.avail_cpus;
return 0;
abort:
*cpu_infos = NULL;
*count = 0;
return err;
}
uint64_t uv_get_constrained_memory(void) {
return 0; /* Memory constraints are unknown. */
}

View File

@@ -155,7 +155,8 @@ typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
/* loop flags */ /* loop flags */
enum { enum {
UV_LOOP_BLOCK_SIGPROF = 1 UV_LOOP_BLOCK_SIGPROF = 0x1,
UV_LOOP_REAP_CHILDREN = 0x2
}; };
/* flags of excluding ifaddr */ /* flags of excluding ifaddr */
@@ -184,11 +185,9 @@ struct uv__stream_queued_fds_s {
defined(__linux__) || \ defined(__linux__) || \
defined(__OpenBSD__) || \ defined(__OpenBSD__) || \
defined(__NetBSD__) defined(__NetBSD__)
#define uv__cloexec uv__cloexec_ioctl
#define uv__nonblock uv__nonblock_ioctl #define uv__nonblock uv__nonblock_ioctl
#define UV__NONBLOCK_IS_IOCTL 1 #define UV__NONBLOCK_IS_IOCTL 1
#else #else
#define uv__cloexec uv__cloexec_fcntl
#define uv__nonblock uv__nonblock_fcntl #define uv__nonblock uv__nonblock_fcntl
#define UV__NONBLOCK_IS_IOCTL 0 #define UV__NONBLOCK_IS_IOCTL 0
#endif #endif
@@ -206,8 +205,7 @@ struct uv__stream_queued_fds_s {
#endif #endif
/* core */ /* core */
int uv__cloexec_ioctl(int fd, int set); int uv__cloexec(int fd, int set);
int uv__cloexec_fcntl(int fd, int set);
int uv__nonblock_ioctl(int fd, int set); int uv__nonblock_ioctl(int fd, int set);
int uv__nonblock_fcntl(int fd, int set); int uv__nonblock_fcntl(int fd, int set);
int uv__close(int fd); /* preserves errno */ int uv__close(int fd); /* preserves errno */
@@ -251,14 +249,15 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
int uv__accept(int sockfd); int uv__accept(int sockfd);
int uv__dup2_cloexec(int oldfd, int newfd); int uv__dup2_cloexec(int oldfd, int newfd);
int uv__open_cloexec(const char* path, int flags); int uv__open_cloexec(const char* path, int flags);
int uv__slurp(const char* filename, char* buf, size_t len);
/* tcp */ /* tcp */
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
int uv__tcp_nodelay(int fd, int on); int uv__tcp_nodelay(int fd, int on);
int uv__tcp_keepalive(int fd, int on, unsigned int delay); int uv__tcp_keepalive(int fd, int on, unsigned int delay);
/* pipe */ /* pipe */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
/* signal */ /* signal */
void uv__signal_close(uv_signal_t* handle); void uv__signal_close(uv_signal_t* handle);
@@ -288,10 +287,10 @@ void uv__tcp_close(uv_tcp_t* handle);
size_t uv__thread_stack_size(void); size_t uv__thread_stack_size(void);
void uv__udp_close(uv_udp_t* handle); void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_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); FILE* uv__open_file(const char* path);
int uv__getpwuid_r(uv_passwd_t* pwd); int uv__getpwuid_r(uv_passwd_t* pwd);
int uv__search_path(const char* prog, char* buf, size_t* buflen); int uv__search_path(const char* prog, char* buf, size_t* buflen);
void uv__wait_children(uv_loop_t* loop);
/* random */ /* random */
int uv__random_devurandom(void* buf, size_t buflen); int uv__random_devurandom(void* buf, size_t buflen);
@@ -366,5 +365,15 @@ size_t strnlen(const char* s, size_t maxlen);
#endif #endif
#endif #endif
#if defined(__FreeBSD__)
ssize_t
uv__fs_copy_file_range(int fd_in,
off_t* off_in,
int fd_out,
off_t* off_out,
size_t len,
unsigned int flags);
#endif
#endif /* UV_UNIX_INTERNAL_H_ */ #endif /* UV_UNIX_INTERNAL_H_ */

View File

@@ -117,6 +117,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
unsigned int revents; unsigned int revents;
QUEUE* q; QUEUE* q;
uv__io_t* w; uv__io_t* w;
uv_process_t* process;
sigset_t* pset; sigset_t* pset;
sigset_t set; sigset_t set;
uint64_t base; uint64_t base;
@@ -285,6 +286,21 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
for (i = 0; i < nfds; i++) { for (i = 0; i < nfds; i++) {
ev = events + i; ev = events + i;
fd = ev->ident; fd = ev->ident;
/* Handle kevent NOTE_EXIT results */
if (ev->filter == EVFILT_PROC) {
QUEUE_FOREACH(q, &loop->process_handles) {
process = QUEUE_DATA(q, uv_process_t, queue);
if (process->pid == fd) {
process->flags |= UV_HANDLE_REAP;
loop->flags |= UV_LOOP_REAP_CHILDREN;
break;
}
}
nevents++;
continue;
}
/* Skip invalidated events, see uv__platform_invalidate_fd */ /* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1) if (fd == -1)
continue; continue;
@@ -377,6 +393,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents++; nevents++;
} }
if (loop->flags & UV_LOOP_REAP_CHILDREN) {
loop->flags &= ~UV_LOOP_REAP_CHILDREN;
uv__wait_children(loop);
}
if (reset_timeout != 0) { if (reset_timeout != 0) {
timeout = user_timeout; timeout = user_timeout;
reset_timeout = 0; reset_timeout = 0;
@@ -435,7 +456,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
/* Invalidate events with same file descriptor */ /* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++) 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; events[i].ident = -1;
} }

View File

@@ -211,31 +211,6 @@ err:
return UV_EINVAL; return UV_EINVAL;
} }
static int uv__slurp(const char* filename, char* buf, size_t len) {
ssize_t n;
int fd;
assert(len > 0);
fd = uv__open_cloexec(filename, O_RDONLY);
if (fd < 0)
return fd;
do
n = read(fd, buf, len - 1);
while (n == -1 && errno == EINTR);
if (uv__close_nocheckstdio(fd))
abort();
if (n < 0)
return UV__ERR(errno);
buf[n] = '\0';
return 0;
}
int uv_uptime(double* uptime) { int uv_uptime(double* uptime) {
static volatile int no_clock_boottime; static volatile int no_clock_boottime;
char buf[128]; char buf[128];
@@ -243,7 +218,7 @@ int uv_uptime(double* uptime) {
int r; int r;
/* Try /proc/uptime first, then fallback to clock_gettime(). */ /* Try /proc/uptime first, then fallback to clock_gettime(). */
if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf))) if (0 == uv__slurp("/proc/uptime", buf, sizeof(buf)))
if (1 == sscanf(buf, "%lf", uptime)) if (1 == sscanf(buf, "%lf", uptime))
return 0; return 0;
@@ -641,6 +616,7 @@ static uint64_t read_cpufreq(unsigned int cpunum) {
} }
#ifdef HAVE_IFADDRS_H
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING))) if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
return 1; return 1;
@@ -654,6 +630,7 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return exclude_type; return exclude_type;
return !exclude_type; return !exclude_type;
} }
#endif
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#ifndef HAVE_IFADDRS_H #ifndef HAVE_IFADDRS_H

View File

@@ -284,6 +284,8 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
nmsgsfds_t size; nmsgsfds_t size;
struct pollfd* pfds; struct pollfd* pfds;
int pollret; int pollret;
int pollfdret;
int pollmsgret;
int reventcount; int reventcount;
int nevents; int nevents;
struct pollfd msg_fd; struct pollfd msg_fd;
@@ -304,24 +306,24 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
return -1; return -1;
} }
if (lst->size > 0) assert(lst->size > 0);
_SET_FDS_MSGS(size, 1, lst->size - 1); _SET_FDS_MSGS(size, 1, lst->size - 1);
else
_SET_FDS_MSGS(size, 0, 0);
pfds = lst->items; pfds = lst->items;
pollret = poll(pfds, size, timeout); pollret = poll(pfds, size, timeout);
if (pollret <= 0) if (pollret <= 0)
return pollret; return pollret;
assert(lst->size > 0); pollfdret = _NFDS(pollret);
pollmsgret = _NMSGS(pollret);
pollret = _NFDS(pollret) + _NMSGS(pollret);
reventcount = 0; reventcount = 0;
nevents = 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; 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 epoll_event ev;
struct pollfd* pfd; struct pollfd* pfd;
@@ -332,18 +334,18 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
ev.fd = pfd->fd; ev.fd = pfd->fd;
ev.events = pfd->revents; ev.events = pfd->revents;
ev.is_msg = 0; 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; events[nevents++] = ev;
} }
if (msg_fd.revents != 0 && msg_fd.fd != -1) if (pollmsgret > 0 && msg_fd.revents != 0 && msg_fd.fd != -1) {
if (i == lst->size) struct epoll_event ev;
events[nevents - 1].is_msg = 1; ev.fd = msg_fd.fd;
ev.events = msg_fd.revents;
ev.is_msg = 1;
events[nevents++] = ev;
}
return nevents; return nevents;
} }

View File

@@ -278,7 +278,9 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
__net_ifconf6header_t ifc; __net_ifconf6header_t ifc;
__net_ifconf6entry_t* ifr; __net_ifconf6entry_t* ifr;
__net_ifconf6entry_t* p; __net_ifconf6entry_t* p;
__net_ifconf6entry_t flg; unsigned int i;
int count_names;
unsigned char netmask[16] = {0};
*count = 0; *count = 0;
/* Assume maximum buffer size allowable */ /* 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))) if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
return UV__ERR(errno); return UV__ERR(errno);
ifc.__nif6h_version = 1; ifc.__nif6h_buffer = uv__calloc(1, maxsize);
ifc.__nif6h_buflen = maxsize;
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) { if (ifc.__nif6h_buffer == NULL) {
uv__close(sockfd); 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); ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr; p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 || if (!(p->__nif6e_addr.sin6_family == AF_INET6))
p->__nif6e_addr.sin6_family == AF_INET))
continue; continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) 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); ++(*count);
} }
if ((*count) == 0) {
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd);
return 0;
}
/* Alloc the return interface structs */ /* 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)) { if (!(*addresses)) {
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd); uv__close(sockfd);
return UV_ENOMEM; return UV_ENOMEM;
} }
address = *addresses; address = *addresses;
count_names = 0;
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer); ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) { while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
p = ifr; p = ifr;
ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen); ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
if (!(p->__nif6e_addr.sin6_family == AF_INET6 || if (!(p->__nif6e_addr.sin6_family == AF_INET6))
p->__nif6e_addr.sin6_family == AF_INET))
continue; continue;
if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE)) 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 */ /* 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);
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
else
address->address.address4 = *((struct sockaddr_in*) &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; if (p->__nif6e_prefixlen % 8)
memset(address->phys_addr, 0, sizeof(address->phys_addr)); 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++; address++;
} }
uv__free(ifc.__nif6h_buffer);
uv__close(sockfd); uv__close(sockfd);
return 0; return 0;
} }
@@ -362,14 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifreq flg; struct ifreq flg;
struct ifreq* ifr; struct ifreq* ifr;
struct ifreq* p; struct ifreq* p;
uv_interface_address_t* addresses_v6;
int count_v6; int count_v6;
unsigned int i;
int rc;
int count_names;
*count = 0; *count = 0;
*addresses = NULL; *addresses = NULL;
/* get the ipv6 addresses first */ /* get the ipv6 addresses first */
uv_interface_address_t* addresses_v6; if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
uv__interface_addresses_v6(&addresses_v6, &count_v6); return rc;
/* now get the ipv4 addresses */ /* now get the ipv4 addresses */
@@ -377,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
maxsize = 16384; maxsize = 16384;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 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); return UV__ERR(errno);
}
ifc.ifc_req = uv__calloc(1, maxsize); 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; ifc.ifc_len = maxsize;
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { 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); uv__close(sockfd);
return UV__ERR(errno); 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)); memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { 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); uv__close(sockfd);
return UV__ERR(errno); return UV__ERR(errno);
} }
@@ -413,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
(*count)++; (*count)++;
} }
if (*count == 0) { if (*count == 0 && count_v6 == 0) {
uv__free(ifc.ifc_req);
uv__close(sockfd); uv__close(sockfd);
return 0; return 0;
} }
/* Alloc the return interface structs */ /* Alloc the return interface structs */
*addresses = uv__malloc((*count + count_v6) * *addresses = uv__calloc(1, (*count + count_v6) *
sizeof(uv_interface_address_t)); sizeof(uv_interface_address_t));
if (!(*addresses)) { if (!(*addresses)) {
if (count_v6)
uv_free_interface_addresses(addresses_v6, count_v6);
uv__free(ifc.ifc_req);
uv__close(sockfd); uv__close(sockfd);
return UV_ENOMEM; return UV_ENOMEM;
} }
address = *addresses; address = *addresses;
/* copy over the ipv6 addresses */ /* copy over the ipv6 addresses if any are found */
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t)); if (count_v6) {
address += count_v6; memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
*count += count_v6; address += count_v6;
uv__free(addresses_v6); *count += count_v6;
/* free ipv6 addresses, but keep address names */
uv__free(addresses_v6);
}
count_names = *count;
ifr = ifc.ifc_req; ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) { while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr; 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)); memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
uv_free_interface_addresses(*addresses, count_names);
uv__free(ifc.ifc_req);
uv__close(sockfd); uv__close(sockfd);
return UV_ENOSYS; 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 */ /* 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.address4 = *((struct sockaddr_in*) &p->ifr_addr);
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
} else { if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr); 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; address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
memset(address->phys_addr, 0, sizeof(address->phys_addr));
address++; address++;
} }
#undef ADDR_SIZE #undef ADDR_SIZE
#undef MAX #undef MAX
uv__free(ifc.ifc_req);
uv__close(sockfd); uv__close(sockfd);
return 0; 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) { 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); uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
return 0; return 0;
} }
int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, static int os390_regfileint(uv_fs_event_t* handle, char* path) {
const char* filename, unsigned int flags) {
uv__os390_epoll* ep; uv__os390_epoll* ep;
_RFIS reg_struct; _RFIS reg_struct;
char* path;
int rc; int rc;
if (uv__is_active(handle))
return UV_EINVAL;
ep = handle->loop->ep; ep = handle->loop->ep;
assert(ep->msg_queue != -1); 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; reg_struct.__rfis_type = 1;
memcpy(reg_struct.__rfis_utok, &handle, sizeof(handle)); 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); rc = __w_pioctl(path, _IOCC_REGFILEINT, sizeof(reg_struct), &reg_struct);
if (rc != 0) if (rc != 0)
return UV__ERR(errno); return UV__ERR(errno);
uv__handle_start(handle);
handle->path = path;
handle->cb = cb;
memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok, memcpy(handle->rfis_rftok, reg_struct.__rfis_rftok,
sizeof(handle->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; uv__os390_epoll* ep;
_RFIS reg_struct; _RFIS reg_struct;
int rc; int rc;
@@ -602,12 +703,40 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
if (rc != 0 && errno != EALREADY && errno != ENOENT) if (rc != 0 && errno != EALREADY && errno != ENOENT)
abort(); abort();
if (handle->path != NULL) {
uv__free(handle->path);
handle->path = NULL;
}
if (rc != 0 && errno == EALREADY)
return -1;
uv__handle_stop(handle); uv__handle_stop(handle);
return 0; 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) { static int os390_message_queue_handler(uv__os390_epoll* ep) {
uv_fs_event_t* handle; uv_fs_event_t* handle;
int msglen; int msglen;
@@ -628,7 +757,15 @@ static int os390_message_queue_handler(uv__os390_epoll* ep) {
events = 0; events = 0;
if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE) if (msg.__rfim_event == _RFIM_ATTR || msg.__rfim_event == _RFIM_WRITE)
events = UV_CHANGE; 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; events = UV_RENAME;
else else
/* Some event that we are not interested in. */ /* 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)); __a2e_l(msg.__rfim_utok, sizeof(msg.__rfim_utok));
handle = *(uv_fs_event_t**)(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); handle->cb(handle, uv__basename_r(handle->path), events, 0);
return 1; return 1;
} }
@@ -650,6 +807,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
struct epoll_event* pe; struct epoll_event* pe;
struct epoll_event e; struct epoll_event e;
uv__os390_epoll* ep; uv__os390_epoll* ep;
int have_signals;
int real_timeout; int real_timeout;
QUEUE* q; QUEUE* q;
uv__io_t* w; 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. */ count = 48; /* Benchmarks suggest this gives the best throughput. */
real_timeout = timeout; real_timeout = timeout;
int nevents = 0; int nevents = 0;
have_signals = 0;
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) { if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
reset_timeout = 1; reset_timeout = 1;
@@ -796,6 +955,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
ep = loop->ep; ep = loop->ep;
if (pe->is_msg) { if (pe->is_msg) {
os390_message_queue_handler(ep); os390_message_queue_handler(ep);
nevents++;
continue; continue;
} }
@@ -825,19 +985,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
pe->events |= w->pevents & (POLLIN | POLLOUT); pe->events |= w->pevents & (POLLIN | POLLOUT);
if (pe->events != 0) { if (pe->events != 0) {
uv__metrics_update_idle_time(loop); /* Run signal watchers last. This also affects child process watchers
w->cb(loop, w, pe->events); * 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++; nevents++;
} }
} }
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (reset_timeout != 0) { if (reset_timeout != 0) {
timeout = user_timeout; timeout = user_timeout;
reset_timeout = 0; 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 (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) {
/* Poll for more events but don't block this time. */ /* 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; loop->ep = NULL;
uv__platform_loop_delete(loop);
return uv__platform_loop_init(loop); return uv__platform_loop_init(loop);
} }

View File

@@ -49,7 +49,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
/* Already bound? */ /* Already bound? */
if (uv__stream_fd(handle) >= 0) if (uv__stream_fd(handle) >= 0)
return UV_EINVAL; return UV_EINVAL;
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
/* Make a copy of the file name, it outlives this function's scope. */ /* Make a copy of the file name, it outlives this function's scope. */
pipe_fname = uv__strdup(name); pipe_fname = uv__strdup(name);
if (pipe_fname == NULL) if (pipe_fname == NULL)
@@ -89,7 +91,7 @@ err_socket:
} }
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
if (uv__stream_fd(handle) == -1) if (uv__stream_fd(handle) == -1)
return UV_EINVAL; return UV_EINVAL;
@@ -317,7 +319,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
if (handle->accepted_fd == -1) if (handle->accepted_fd == -1)
return UV_UNKNOWN_HANDLE; return UV_UNKNOWN_HANDLE;
else else
return uv__handle_type(handle->accepted_fd); return uv_guess_handle(handle->accepted_fd);
} }

View File

@@ -27,6 +27,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@@ -35,9 +36,22 @@
#include <poll.h> #include <poll.h>
#include <sched.h> #include <sched.h>
#if defined(__APPLE__) && !TARGET_OS_IPHONE #if defined(__APPLE__)
# include <spawn.h>
# include <paths.h>
# include <sys/kauth.h>
# include <sys/types.h>
# include <sys/sysctl.h>
# include <dlfcn.h>
# include <crt_externs.h> # include <crt_externs.h>
# include <xlocale.h>
# define environ (*_NSGetEnviron()) # define environ (*_NSGetEnviron())
/* macOS 10.14 back does not define this constant */
# ifndef POSIX_SPAWN_SETSID
# define POSIX_SPAWN_SETSID 1024
# endif
#else #else
extern char **environ; extern char **environ;
#endif #endif
@@ -61,21 +75,35 @@ extern char **environ;
#endif #endif
#endif #endif
#if defined(__APPLE__) || \
defined(__DragonFly__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__)
#include <sys/event.h>
#else
#define UV_USE_SIGCHLD
#endif
#ifdef UV_USE_SIGCHLD
static void uv__chld(uv_signal_t* handle, int signum) { static void uv__chld(uv_signal_t* handle, int signum) {
assert(signum == SIGCHLD);
uv__wait_children(handle->loop);
}
#endif
void uv__wait_children(uv_loop_t* loop) {
uv_process_t* process; uv_process_t* process;
uv_loop_t* loop;
int exit_status; int exit_status;
int term_signal; int term_signal;
int status; int status;
int options;
pid_t pid; pid_t pid;
QUEUE pending; QUEUE pending;
QUEUE* q; QUEUE* q;
QUEUE* h; QUEUE* h;
assert(signum == SIGCHLD);
QUEUE_INIT(&pending); QUEUE_INIT(&pending);
loop = handle->loop;
h = &loop->process_handles; h = &loop->process_handles;
q = QUEUE_HEAD(h); q = QUEUE_HEAD(h);
@@ -83,19 +111,33 @@ static void uv__chld(uv_signal_t* handle, int signum) {
process = QUEUE_DATA(q, uv_process_t, queue); process = QUEUE_DATA(q, uv_process_t, queue);
q = QUEUE_NEXT(q); q = QUEUE_NEXT(q);
#ifndef UV_USE_SIGCHLD
if ((process->flags & UV_HANDLE_REAP) == 0)
continue;
options = 0;
process->flags &= ~UV_HANDLE_REAP;
#else
options = WNOHANG;
#endif
do do
pid = waitpid(process->pid, &status, WNOHANG); pid = waitpid(process->pid, &status, options);
while (pid == -1 && errno == EINTR); while (pid == -1 && errno == EINTR);
if (pid == 0) #ifdef UV_USE_SIGCHLD
if (pid == 0) /* Not yet exited */
continue; continue;
#endif
if (pid == -1) { if (pid == -1) {
if (errno != ECHILD) if (errno != ECHILD)
abort(); abort();
/* The child died, and we missed it. This probably means someone else
* stole the waitpid from us. Handle this by not handling it at all. */
continue; continue;
} }
assert(pid == process->pid);
process->status = status; process->status = status;
QUEUE_REMOVE(&process->queue); QUEUE_REMOVE(&process->queue);
QUEUE_INSERT_TAIL(&pending, &process->queue); QUEUE_INSERT_TAIL(&pending, &process->queue);
@@ -206,16 +248,14 @@ static void uv__write_int(int fd, int val) {
n = write(fd, &val, sizeof(val)); n = write(fd, &val, sizeof(val));
while (n == -1 && errno == EINTR); while (n == -1 && errno == EINTR);
if (n == -1 && errno == EPIPE) /* The write might have failed (e.g. if the parent process has died),
return; /* parent process has quit */ * but we have nothing left but to _exit ourself now too. */
_exit(127);
assert(n == sizeof(val));
} }
static void uv__write_errno(int error_fd) { static void uv__write_errno(int error_fd) {
uv__write_int(error_fd, UV__ERR(errno)); uv__write_int(error_fd, UV__ERR(errno));
_exit(127);
} }
@@ -273,22 +313,31 @@ static void uv__process_child_init(const uv_process_options_t* options,
use_fd = pipes[fd][1]; use_fd = pipes[fd][1];
if (use_fd < 0 || use_fd >= fd) if (use_fd < 0 || use_fd >= fd)
continue; continue;
#ifdef F_DUPFD_CLOEXEC /* POSIX 2008 */
pipes[fd][1] = fcntl(use_fd, F_DUPFD_CLOEXEC, stdio_count);
#else
pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count); pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
#endif
if (pipes[fd][1] == -1) if (pipes[fd][1] == -1)
uv__write_errno(error_fd); uv__write_errno(error_fd);
#ifndef F_DUPFD_CLOEXEC /* POSIX 2008 */
n = uv__cloexec(pipes[fd][1], 1);
if (n)
uv__write_int(error_fd, n);
#endif
} }
for (fd = 0; fd < stdio_count; fd++) { for (fd = 0; fd < stdio_count; fd++) {
close_fd = pipes[fd][0]; close_fd = -1;
use_fd = pipes[fd][1]; use_fd = pipes[fd][1];
if (use_fd < 0) { if (use_fd < 0) {
if (fd >= 3) if (fd >= 3)
continue; continue;
else { else {
/* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is /* Redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
* set * set. */
*/ uv__close_nocheckstdio(fd); /* Free up fd, if it happens to be open. */
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR); use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
close_fd = use_fd; close_fd = use_fd;
@@ -297,28 +346,27 @@ static void uv__process_child_init(const uv_process_options_t* options,
} }
} }
if (fd == use_fd) if (fd == use_fd) {
uv__cloexec_fcntl(use_fd, 0); if (close_fd == -1) {
else n = uv__cloexec(use_fd, 0);
if (n)
uv__write_int(error_fd, n);
}
}
else {
fd = dup2(use_fd, fd); fd = dup2(use_fd, fd);
}
if (fd == -1) if (fd == -1)
uv__write_errno(error_fd); uv__write_errno(error_fd);
if (fd <= 2) if (fd <= 2 && close_fd == -1)
uv__nonblock_fcntl(fd, 0); uv__nonblock_fcntl(fd, 0);
if (close_fd >= stdio_count) if (close_fd >= stdio_count)
uv__close(close_fd); uv__close(close_fd);
} }
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd >= stdio_count)
uv__close(use_fd);
}
if (options->cwd != NULL && chdir(options->cwd)) if (options->cwd != NULL && chdir(options->cwd))
uv__write_errno(error_fd); uv__write_errno(error_fd);
@@ -361,9 +409,8 @@ static void uv__process_child_init(const uv_process_options_t* options,
#endif #endif
#endif #endif
if (options->env != NULL) { if (options->env != NULL)
environ = options->env; environ = options->env;
}
/* Reset signal mask just before exec. */ /* Reset signal mask just before exec. */
sigemptyset(&signewset); sigemptyset(&signewset);
@@ -377,11 +424,555 @@ static void uv__process_child_init(const uv_process_options_t* options,
#endif #endif
uv__write_errno(error_fd); uv__write_errno(error_fd);
abort();
} }
#endif #endif
#if defined(__APPLE__)
typedef struct uv__posix_spawn_fncs_tag {
struct {
int (*addchdir_np)(const posix_spawn_file_actions_t *, const char *);
} file_actions;
} uv__posix_spawn_fncs_t;
static uv_once_t posix_spawn_init_once = UV_ONCE_INIT;
static uv__posix_spawn_fncs_t posix_spawn_fncs;
static int posix_spawn_can_use_setsid;
static void uv__spawn_init_posix_spawn_fncs(void) {
/* Try to locate all non-portable functions at runtime */
posix_spawn_fncs.file_actions.addchdir_np =
dlsym(RTLD_DEFAULT, "posix_spawn_file_actions_addchdir_np");
}
static void uv__spawn_init_can_use_setsid(void) {
int which[] = {CTL_KERN, KERN_OSRELEASE};
unsigned major;
unsigned minor;
unsigned patch;
char buf[256];
size_t len;
len = sizeof(buf);
if (sysctl(which, ARRAY_SIZE(which), buf, &len, NULL, 0))
return;
/* NULL specifies to use LC_C_LOCALE */
if (3 != sscanf_l(buf, NULL, "%u.%u.%u", &major, &minor, &patch))
return;
posix_spawn_can_use_setsid = (major >= 19); /* macOS Catalina */
}
static void uv__spawn_init_posix_spawn(void) {
/* Init handles to all potentially non-defined functions */
uv__spawn_init_posix_spawn_fncs();
/* Init feature detection for POSIX_SPAWN_SETSID flag */
uv__spawn_init_can_use_setsid();
}
static int uv__spawn_set_posix_spawn_attrs(
posix_spawnattr_t* attrs,
const uv__posix_spawn_fncs_t* posix_spawn_fncs,
const uv_process_options_t* options) {
int err;
unsigned int flags;
sigset_t signal_set;
err = posix_spawnattr_init(attrs);
if (err != 0) {
/* If initialization fails, no need to de-init, just return */
return err;
}
if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* kauth_cred_issuser currently requires exactly uid == 0 for these
* posixspawn_attrs (set_groups_np, setuid_np, setgid_np), which deviates
* from the normal specification of setuid (which also uses euid), and they
* are also undocumented syscalls, so we do not use them. */
err = ENOSYS;
goto error;
}
/* Set flags for spawn behavior
* 1) POSIX_SPAWN_CLOEXEC_DEFAULT: (Apple Extension) All descriptors in the
* parent will be treated as if they had been created with O_CLOEXEC. The
* only fds that will be passed on to the child are those manipulated by
* the file actions
* 2) POSIX_SPAWN_SETSIGDEF: Signals mentioned in spawn-sigdefault in the
* spawn attributes will be reset to behave as their default
* 3) POSIX_SPAWN_SETSIGMASK: Signal mask will be set to the value of
* spawn-sigmask in attributes
* 4) POSIX_SPAWN_SETSID: Make the process a new session leader if a detached
* session was requested. */
flags = POSIX_SPAWN_CLOEXEC_DEFAULT |
POSIX_SPAWN_SETSIGDEF |
POSIX_SPAWN_SETSIGMASK;
if (options->flags & UV_PROCESS_DETACHED) {
/* If running on a version of macOS where this flag is not supported,
* revert back to the fork/exec flow. Otherwise posix_spawn will
* silently ignore the flag. */
if (!posix_spawn_can_use_setsid) {
err = ENOSYS;
goto error;
}
flags |= POSIX_SPAWN_SETSID;
}
err = posix_spawnattr_setflags(attrs, flags);
if (err != 0)
goto error;
/* Reset all signal the child to their default behavior */
sigfillset(&signal_set);
err = posix_spawnattr_setsigdefault(attrs, &signal_set);
if (err != 0)
goto error;
/* Reset the signal mask for all signals */
sigemptyset(&signal_set);
err = posix_spawnattr_setsigmask(attrs, &signal_set);
if (err != 0)
goto error;
return err;
error:
(void) posix_spawnattr_destroy(attrs);
return err;
}
static int uv__spawn_set_posix_spawn_file_actions(
posix_spawn_file_actions_t* actions,
const uv__posix_spawn_fncs_t* posix_spawn_fncs,
const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2]) {
int fd;
int fd2;
int use_fd;
int err;
err = posix_spawn_file_actions_init(actions);
if (err != 0) {
/* If initialization fails, no need to de-init, just return */
return err;
}
/* Set the current working directory if requested */
if (options->cwd != NULL) {
if (posix_spawn_fncs->file_actions.addchdir_np == NULL) {
err = ENOSYS;
goto error;
}
err = posix_spawn_fncs->file_actions.addchdir_np(actions, options->cwd);
if (err != 0)
goto error;
}
/* Do not return ENOSYS after this point, as we may mutate pipes. */
/* First duplicate low numbered fds, since it's not safe to duplicate them,
* they could get replaced. Example: swapping stdout and stderr; without
* this fd 2 (stderr) would be duplicated into fd 1, thus making both
* stdout and stderr go to the same fd, which was not the intention. */
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd < 0 || use_fd >= fd)
continue;
use_fd = stdio_count;
for (fd2 = 0; fd2 < stdio_count; fd2++) {
/* If we were not setting POSIX_SPAWN_CLOEXEC_DEFAULT, we would need to
* also consider whether fcntl(fd, F_GETFD) returned without the
* FD_CLOEXEC flag set. */
if (pipes[fd2][1] == use_fd) {
use_fd++;
fd2 = 0;
}
}
err = posix_spawn_file_actions_adddup2(
actions,
pipes[fd][1],
use_fd);
assert(err != ENOSYS);
if (err != 0)
goto error;
pipes[fd][1] = use_fd;
}
/* Second, move the descriptors into their respective places */
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd < 0) {
if (fd >= 3)
continue;
else {
/* If ignored, redirect to (or from) /dev/null, */
err = posix_spawn_file_actions_addopen(
actions,
fd,
"/dev/null",
fd == 0 ? O_RDONLY : O_RDWR,
0);
assert(err != ENOSYS);
if (err != 0)
goto error;
continue;
}
}
if (fd == use_fd)
err = posix_spawn_file_actions_addinherit_np(actions, fd);
else
err = posix_spawn_file_actions_adddup2(actions, use_fd, fd);
assert(err != ENOSYS);
if (err != 0)
goto error;
/* Make sure the fd is marked as non-blocking (state shared between child
* and parent). */
uv__nonblock_fcntl(use_fd, 0);
}
/* Finally, close all the superfluous descriptors */
for (fd = 0; fd < stdio_count; fd++) {
use_fd = pipes[fd][1];
if (use_fd < stdio_count)
continue;
/* Check if we already closed this. */
for (fd2 = 0; fd2 < fd; fd2++) {
if (pipes[fd2][1] == use_fd)
break;
}
if (fd2 < fd)
continue;
err = posix_spawn_file_actions_addclose(actions, use_fd);
assert(err != ENOSYS);
if (err != 0)
goto error;
}
return 0;
error:
(void) posix_spawn_file_actions_destroy(actions);
return err;
}
char* uv__spawn_find_path_in_env(char** env) {
char** env_iterator;
const char path_var[] = "PATH=";
/* Look for an environment variable called PATH in the
* provided env array, and return its value if found */
for (env_iterator = env; *env_iterator != NULL; env_iterator++) {
if (strncmp(*env_iterator, path_var, sizeof(path_var) - 1) == 0) {
/* Found "PATH=" at the beginning of the string */
return *env_iterator + sizeof(path_var) - 1;
}
}
return NULL;
}
static int uv__spawn_resolve_and_spawn(const uv_process_options_t* options,
posix_spawnattr_t* attrs,
posix_spawn_file_actions_t* actions,
pid_t* pid) {
const char *p;
const char *z;
const char *path;
size_t l;
size_t k;
int err;
int seen_eacces;
path = NULL;
err = -1;
seen_eacces = 0;
/* Short circuit for erroneous case */
if (options->file == NULL)
return ENOENT;
/* The environment for the child process is that of the parent unless overriden
* by options->env */
char** env = environ;
if (options->env != NULL)
env = options->env;
/* 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_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(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 env, use the default value
* to look for the executable */
if (path == NULL)
path = _PATH_DEFPATH;
k = strnlen(options->file, NAME_MAX + 1);
if (k > NAME_MAX)
return ENAMETOOLONG;
l = strnlen(path, PATH_MAX - 1) + 1;
for (p = path;; p = z) {
/* Compose the new process file from the entry in the PATH
* environment variable and the actual file name */
char b[PATH_MAX + NAME_MAX];
z = strchr(p, ':');
if (!z)
z = p + strlen(p);
if ((size_t)(z - p) >= l) {
if (!*z++)
break;
continue;
}
memcpy(b, p, z - p);
b[z - p] = '/';
memcpy(b + (z - p) + (z > p), options->file, k + 1);
/* Try to spawn the new process file. If it fails with ENOENT, the
* new process file is not in this PATH entry, continue with the next
* PATH entry. */
do
err = posix_spawn(pid, b, actions, attrs, options->args, env);
while (err == EINTR);
switch (err) {
case EACCES:
seen_eacces = 1;
break; /* continue search */
case ENOENT:
case ENOTDIR:
break; /* continue search */
default:
return err;
}
if (!*z++)
break;
}
if (seen_eacces)
return EACCES;
return err;
}
static int uv__spawn_and_init_child_posix_spawn(
const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
pid_t* pid,
const uv__posix_spawn_fncs_t* posix_spawn_fncs) {
int err;
posix_spawnattr_t attrs;
posix_spawn_file_actions_t actions;
err = uv__spawn_set_posix_spawn_attrs(&attrs, posix_spawn_fncs, options);
if (err != 0)
goto error;
/* This may mutate pipes. */
err = uv__spawn_set_posix_spawn_file_actions(&actions,
posix_spawn_fncs,
options,
stdio_count,
pipes);
if (err != 0) {
(void) posix_spawnattr_destroy(&attrs);
goto error;
}
/* Try to spawn options->file resolving in the provided environment
* if any */
err = uv__spawn_resolve_and_spawn(options, &attrs, &actions, pid);
assert(err != ENOSYS);
/* Destroy the actions/attributes */
(void) posix_spawn_file_actions_destroy(&actions);
(void) posix_spawnattr_destroy(&attrs);
error:
/* In an error situation, the attributes and file actions are
* already destroyed, only the happy path requires cleanup */
return UV__ERR(err);
}
#endif
static int uv__spawn_and_init_child_fork(const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
int error_fd,
pid_t* pid) {
sigset_t signewset;
sigset_t sigoldset;
/* Start the child with most signals blocked, to avoid any issues before we
* can reset them, but allow program failures to exit (and not hang). */
sigfillset(&signewset);
sigdelset(&signewset, SIGKILL);
sigdelset(&signewset, SIGSTOP);
sigdelset(&signewset, SIGTRAP);
sigdelset(&signewset, SIGSEGV);
sigdelset(&signewset, SIGBUS);
sigdelset(&signewset, SIGILL);
sigdelset(&signewset, SIGSYS);
sigdelset(&signewset, SIGABRT);
if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
abort();
*pid = fork();
if (*pid == 0) {
/* Fork succeeded, in the child process */
uv__process_child_init(options, stdio_count, pipes, error_fd);
abort();
}
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;
}
static int uv__spawn_and_init_child(
uv_loop_t* loop,
const uv_process_options_t* options,
int stdio_count,
int (*pipes)[2],
pid_t* pid) {
int signal_pipe[2] = { -1, -1 };
int status;
int err;
int exec_errorno;
ssize_t r;
#if defined(__APPLE__)
uv_once(&posix_spawn_init_once, uv__spawn_init_posix_spawn);
/* Special child process spawn case for macOS Big Sur (11.0) onwards
*
* Big Sur introduced a significant performance degradation on a call to
* fork/exec when the process has many pages mmaped in with MAP_JIT, like, say
* a javascript interpreter. Electron-based applications, for example,
* are impacted; though the magnitude of the impact depends on how much the
* app relies on subprocesses.
*
* On macOS, though, posix_spawn is implemented in a way that does not
* exhibit the problem. This block implements the forking and preparation
* logic with posix_spawn and its related primitives. It also takes advantage of
* the macOS extension POSIX_SPAWN_CLOEXEC_DEFAULT that makes impossible to
* leak descriptors to the child process. */
err = uv__spawn_and_init_child_posix_spawn(options,
stdio_count,
pipes,
pid,
&posix_spawn_fncs);
/* The posix_spawn flow will return UV_ENOSYS if any of the posix_spawn_x_np
* non-standard functions is both _needed_ and _undefined_. In those cases,
* default back to the fork/execve strategy. For all other errors, just fail. */
if (err != UV_ENOSYS)
return err;
#endif
/* This pipe is used by the parent to wait until
* the child has called `execve()`. We need this
* to avoid the following race condition:
*
* if ((pid = fork()) > 0) {
* kill(pid, SIGTERM);
* }
* else if (pid == 0) {
* execve("/bin/cat", argp, envp);
* }
*
* The parent sends a signal immediately after forking.
* Since the child may not have called `execve()` yet,
* there is no telling what process receives the signal,
* our fork or /bin/cat.
*
* To avoid ambiguity, we create a pipe with both ends
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it EOFs or errors with EPIPE.
*/
err = uv__make_pipe(signal_pipe, 0);
if (err)
return err;
/* Acquire write lock to prevent opening new fds in worker threads */
uv_rwlock_wrlock(&loop->cloexec_lock);
err = uv__spawn_and_init_child_fork(options, stdio_count, pipes, signal_pipe[1], pid);
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[1]);
if (err == 0) {
do
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
while (r == -1 && errno == EINTR);
if (r == 0)
; /* okay, EOF */
else if (r == sizeof(exec_errorno)) {
do
err = waitpid(*pid, &status, 0); /* okay, read errorno */
while (err == -1 && errno == EINTR);
assert(err == *pid);
err = exec_errorno;
} else if (r == -1 && errno == EPIPE) {
/* Something unknown happened to our child before spawn */
do
err = waitpid(*pid, &status, 0); /* okay, got EPIPE */
while (err == -1 && errno == EINTR);
assert(err == *pid);
err = UV_EPIPE;
} else
abort();
}
uv__close_nocheckstdio(signal_pipe[0]);
return err;
}
int uv_spawn(uv_loop_t* loop, int uv_spawn(uv_loop_t* loop,
uv_process_t* process, uv_process_t* process,
const uv_process_options_t* options) { const uv_process_options_t* options) {
@@ -389,18 +980,13 @@ int uv_spawn(uv_loop_t* loop,
/* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
return UV_ENOSYS; return UV_ENOSYS;
#else #else
sigset_t signewset;
sigset_t sigoldset;
int signal_pipe[2] = { -1, -1 };
int pipes_storage[8][2]; int pipes_storage[8][2];
int (*pipes)[2]; int (*pipes)[2];
int stdio_count; int stdio_count;
ssize_t r;
pid_t pid; pid_t pid;
int err; int err;
int exec_errorno; int exec_errorno;
int i; int i;
int status;
if (options->cpumask != NULL) { if (options->cpumask != NULL) {
#ifndef CMAKE_BOOTSTRAP #ifndef CMAKE_BOOTSTRAP
@@ -427,6 +1013,7 @@ int uv_spawn(uv_loop_t* loop,
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
QUEUE_INIT(&process->queue); QUEUE_INIT(&process->queue);
process->status = 0;
stdio_count = options->stdio_count; stdio_count = options->stdio_count;
if (stdio_count < 3) if (stdio_count < 3)
@@ -451,92 +1038,43 @@ int uv_spawn(uv_loop_t* loop,
goto error; goto error;
} }
/* This pipe is used by the parent to wait until #ifdef UV_USE_SIGCHLD
* the child has called `execve()`. We need this
* to avoid the following race condition:
*
* if ((pid = fork()) > 0) {
* kill(pid, SIGTERM);
* }
* else if (pid == 0) {
* execve("/bin/cat", argp, envp);
* }
*
* The parent sends a signal immediately after forking.
* Since the child may not have called `execve()` yet,
* there is no telling what process receives the signal,
* our fork or /bin/cat.
*
* To avoid ambiguity, we create a pipe with both ends
* marked close-on-exec. Then, after the call to `fork()`,
* the parent polls the read end until it EOFs or errors with EPIPE.
*/
err = uv__make_pipe(signal_pipe, 0);
if (err)
goto error;
uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD); uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
#endif
/* Acquire write lock to prevent opening new fds in worker threads */ /* Spawn the child */
uv_rwlock_wrlock(&loop->cloexec_lock); exec_errorno = uv__spawn_and_init_child(loop, options, stdio_count, pipes, &pid);
/* Start the child with most signals blocked, to avoid any issues before we #if 0
* can reset them, but allow program failures to exit (and not hang). */ /* This runs into a nodejs issue (it expects initialized streams, even if the
sigfillset(&signewset); * exec failed).
sigdelset(&signewset, SIGKILL); * See https://github.com/libuv/libuv/pull/3107#issuecomment-782482608 */
sigdelset(&signewset, SIGSTOP); if (exec_errorno != 0)
sigdelset(&signewset, SIGTRAP); goto error;
sigdelset(&signewset, SIGSEGV); #endif
sigdelset(&signewset, SIGBUS);
sigdelset(&signewset, SIGILL);
sigdelset(&signewset, SIGSYS);
sigdelset(&signewset, SIGABRT);
if (pthread_sigmask(SIG_BLOCK, &signewset, &sigoldset) != 0)
abort();
pid = fork(); /* Activate this handle if exec() happened successfully, even if we later
if (pid == -1) * fail to open a stdio handle. This ensures we can eventually reap the child
err = UV__ERR(errno); * with waitpid. */
if (exec_errorno == 0) {
#ifndef UV_USE_SIGCHLD
struct kevent event;
EV_SET(&event, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT, 0, 0);
if (kevent(loop->backend_fd, &event, 1, NULL, 0, NULL)) {
if (errno != ESRCH)
abort();
/* Process already exited. Call waitpid on the next loop iteration. */
process->flags |= UV_HANDLE_REAP;
loop->flags |= UV_LOOP_REAP_CHILDREN;
}
#endif
if (pid == 0) process->pid = pid;
uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]); process->exit_cb = options->exit_cb;
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
if (pthread_sigmask(SIG_SETMASK, &sigoldset, NULL) != 0) uv__handle_start(process);
abort();
/* Release lock in parent process */
uv_rwlock_wrunlock(&loop->cloexec_lock);
uv__close(signal_pipe[1]);
if (pid == -1) {
uv__close(signal_pipe[0]);
goto error;
} }
process->status = 0;
exec_errorno = 0;
do
r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
while (r == -1 && errno == EINTR);
if (r == 0)
; /* okay, EOF */
else if (r == sizeof(exec_errorno)) {
do
err = waitpid(pid, &status, 0); /* okay, read errorno */
while (err == -1 && errno == EINTR);
assert(err == pid);
} else if (r == -1 && errno == EPIPE) {
do
err = waitpid(pid, &status, 0); /* okay, got EPIPE */
while (err == -1 && errno == EINTR);
assert(err == pid);
} else
abort();
uv__close_nocheckstdio(signal_pipe[0]);
for (i = 0; i < options->stdio_count; i++) { for (i = 0; i < options->stdio_count; i++) {
err = uv__process_open_stream(options->stdio + i, pipes[i]); err = uv__process_open_stream(options->stdio + i, pipes[i]);
if (err == 0) if (err == 0)
@@ -548,15 +1086,6 @@ int uv_spawn(uv_loop_t* loop,
goto error; goto error;
} }
/* Only activate this handle if exec() happened successfully */
if (exec_errorno == 0) {
QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
uv__handle_start(process);
}
process->pid = pid;
process->exit_cb = options->exit_cb;
if (pipes != pipes_storage) if (pipes != pipes_storage)
uv__free(pipes); uv__free(pipes);
@@ -589,9 +1118,16 @@ int uv_process_kill(uv_process_t* process, int signum) {
int uv_kill(int pid, 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); return UV__ERR(errno);
else } else
return 0; 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__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
static void uv__write_callbacks(uv_stream_t* stream); static void uv__write_callbacks(uv_stream_t* stream);
static size_t uv__write_req_size(uv_write_t* req); 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, 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__stream_flush_write_queue(stream, UV_ECANCELED);
uv__write_callbacks(stream); uv__write_callbacks(stream);
uv__drain(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;
}
assert(stream->write_queue_size == 0); assert(stream->write_queue_size == 0);
} }
@@ -641,14 +632,16 @@ done:
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err; int err;
if (uv__is_closing(stream)) {
return UV_EINVAL;
}
switch (stream->type) { switch (stream->type) {
case UV_TCP: case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
break; break;
default: default:
@@ -667,25 +660,30 @@ static void uv__drain(uv_stream_t* stream) {
int err; int err;
assert(QUEUE_EMPTY(&stream->write_queue)); assert(QUEUE_EMPTY(&stream->write_queue));
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); if (!(stream->flags & UV_HANDLE_CLOSING)) {
uv__stream_osx_interrupt_select(stream); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream);
}
/* Shutdown? */ if (!(stream->flags & UV_HANDLE_SHUTTING))
if ((stream->flags & UV_HANDLE_SHUTTING) && return;
!(stream->flags & UV_HANDLE_CLOSING) &&
req = stream->shutdown_req;
assert(req);
if ((stream->flags & UV_HANDLE_CLOSING) ||
!(stream->flags & UV_HANDLE_SHUT)) { !(stream->flags & UV_HANDLE_SHUT)) {
assert(stream->shutdown_req);
req = stream->shutdown_req;
stream->shutdown_req = NULL; stream->shutdown_req = NULL;
stream->flags &= ~UV_HANDLE_SHUTTING; stream->flags &= ~UV_HANDLE_SHUTTING;
uv__req_unregister(stream->loop, req); uv__req_unregister(stream->loop, req);
err = 0; 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); err = UV__ERR(errno);
else /* Success. */
if (err == 0)
stream->flags |= UV_HANDLE_SHUT; stream->flags |= UV_HANDLE_SHUT;
if (req->cb != NULL) if (req->cb != NULL)
@@ -926,7 +924,6 @@ static void uv__write(uv_stream_t* stream) {
} }
req->error = n; 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__write_req_finish(req);
uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
uv__stream_osx_interrupt_select(stream); 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) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
stream->flags |= UV_HANDLE_READ_EOF; stream->flags |= UV_HANDLE_READ_EOF;
stream->flags &= ~UV_HANDLE_READING; 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); 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); uv__req_init(stream->loop, req, UV_SHUTDOWN);
req->handle = stream; req->handle = stream;
req->cb = cb; 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_SHUTTING;
stream->flags &= ~UV_HANDLE_WRITABLE; stream->flags &= ~UV_HANDLE_WRITABLE;
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); if (QUEUE_EMPTY(&stream->write_queue))
uv__stream_osx_interrupt_select(stream); uv__io_feed(stream->loop, &stream->io_watcher);
return 0; return 0;
} }

View File

@@ -158,7 +158,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
sigset_t set; sigset_t set;
uint64_t base; uint64_t base;
uint64_t diff; uint64_t diff;
uint64_t idle_poll;
unsigned int nfds; unsigned int nfds;
unsigned int i; unsigned int i;
int saved_errno; int saved_errno;
@@ -428,7 +427,7 @@ void uv_loadavg(double avg[3]) {
#if defined(PORT_SOURCE_FILE) #if defined(PORT_SOURCE_FILE)
static int uv__fs_event_rearm(uv_fs_event_t *handle) { static int uv__fs_event_rearm(uv_fs_event_t *handle) {
if (handle->fd == -1) if (handle->fd == PORT_DELETED)
return UV_EBADF; return UV_EBADF;
if (port_associate(handle->loop->fs_fd, if (port_associate(handle->loop->fs_fd,
@@ -479,6 +478,12 @@ static void uv__fs_event_read(uv_loop_t* loop,
handle = (uv_fs_event_t*) pe.portev_user; handle = (uv_fs_event_t*) pe.portev_user;
assert((r == 0) && "unexpected port_get() error"); 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; events = 0;
if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED)) if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
events |= UV_CHANGE; events |= UV_CHANGE;
@@ -546,12 +551,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)) if (!uv__is_active(handle))
return 0; return 0;
if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) { if (handle->fd == PORT_LOADED) {
port_dissociate(handle->loop->fs_fd, ret = port_dissociate(handle->loop->fs_fd,
PORT_SOURCE_FILE, PORT_SOURCE_FILE,
(uintptr_t) &handle->fo); (uintptr_t) &handle->fo);
} }
@@ -560,13 +567,28 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
uv__free(handle->path); uv__free(handle->path);
handle->path = NULL; handle->path = NULL;
handle->fo.fo_name = 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; return 0;
} }
void uv__fs_event_close(uv_fs_event_t* handle) { 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) */ #else /* !defined(PORT_SOURCE_FILE) */

View File

@@ -184,14 +184,15 @@ int uv__tcp_bind(uv_tcp_t* tcp,
#endif #endif
errno = 0; 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) if (errno == EAFNOSUPPORT)
/* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
* socket created with AF_INET to an AF_INET6 address or vice versa. */ * socket created with AF_INET to an AF_INET6 address or vice versa. */
return UV_EINVAL; return UV_EINVAL;
return UV__ERR(errno); return UV__ERR(errno);
} }
tcp->delayed_error = UV__ERR(errno); tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
tcp->flags |= UV_HANDLE_BOUND; tcp->flags |= UV_HANDLE_BOUND;
if (addr->sa_family == AF_INET6) if (addr->sa_family == AF_INET6)
@@ -320,15 +321,23 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
return UV_EINVAL; return UV_EINVAL;
fd = uv__stream_fd(handle); fd = uv__stream_fd(handle);
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
return UV__ERR(errno); 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); uv_close((uv_handle_t*) handle, close_cb);
return 0; return 0;
} }
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
static int single_accept_cached = -1; static int single_accept_cached = -1;
unsigned long flags; unsigned long flags;
int single_accept; int single_accept;

View File

@@ -162,11 +162,45 @@ void uv_barrier_destroy(uv_barrier_t* barrier) {
#endif #endif
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
* too small to safely receive signals on.
*
* Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
* the largest MINSIGSTKSZ of the architectures that musl supports) so
* let's use that as a lower bound.
*
* We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
* is between 28 and 133 KB when compiling against glibc, depending
* on the architecture.
*/
static size_t uv__min_stack_size(void) {
static const size_t min = 8192;
#ifdef PTHREAD_STACK_MIN /* Not defined on NetBSD. */
if (min < (size_t) PTHREAD_STACK_MIN)
return PTHREAD_STACK_MIN;
#endif /* PTHREAD_STACK_MIN */
return min;
}
/* On Linux, threads created by musl have a much smaller stack than threads
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
*/
static size_t uv__default_stack_size(void) {
#if !defined(__linux__)
return 0;
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
return 4 << 20; /* glibc default. */
#else
return 2 << 20; /* glibc default. */
#endif
}
/* On MacOS, threads other than the main thread are created with a reduced /* On MacOS, threads other than the main thread are created with a reduced
* stack size by default. Adjust to RLIMIT_STACK aligned to the page size. * stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
*
* On Linux, threads created by musl have a much smaller stack than threads
* created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
*/ */
size_t uv__thread_stack_size(void) { size_t uv__thread_stack_size(void) {
#if defined(__APPLE__) || defined(__linux__) #if defined(__APPLE__) || defined(__linux__)
@@ -176,34 +210,20 @@ size_t uv__thread_stack_size(void) {
* the system call wrapper invokes the wrong system call. Don't treat * the system call wrapper invokes the wrong system call. Don't treat
* that as fatal, just use the default stack size instead. * that as fatal, just use the default stack size instead.
*/ */
if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) { if (getrlimit(RLIMIT_STACK, &lim))
/* pthread_attr_setstacksize() expects page-aligned values. */ return uv__default_stack_size();
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is if (lim.rlim_cur == RLIM_INFINITY)
* too small to safely receive signals on. return uv__default_stack_size();
*
* Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has /* pthread_attr_setstacksize() expects page-aligned values. */
* the largest MINSIGSTKSZ of the architectures that musl supports) so lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
* let's use that as a lower bound.
* if (lim.rlim_cur >= (rlim_t) uv__min_stack_size())
* We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ return lim.rlim_cur;
* is between 28 and 133 KB when compiling against glibc, depending
* on the architecture.
*/
if (lim.rlim_cur >= 8192)
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
return lim.rlim_cur;
}
#endif #endif
#if !defined(__linux__) return uv__default_stack_size();
return 0;
#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
return 4 << 20; /* glibc default. */
#else
return 2 << 20; /* glibc default. */
#endif
} }
@@ -222,6 +242,7 @@ int uv_thread_create_ex(uv_thread_t* tid,
pthread_attr_t attr_storage; pthread_attr_t attr_storage;
size_t pagesize; size_t pagesize;
size_t stack_size; size_t stack_size;
size_t min_stack_size;
/* Used to squelch a -Wcast-function-type warning. */ /* Used to squelch a -Wcast-function-type warning. */
union { union {
@@ -239,10 +260,9 @@ int uv_thread_create_ex(uv_thread_t* tid,
pagesize = (size_t)getpagesize(); pagesize = (size_t)getpagesize();
/* Round up to the nearest page boundary. */ /* Round up to the nearest page boundary. */
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1); stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
#ifdef PTHREAD_STACK_MIN min_stack_size = uv__min_stack_size();
if (stack_size < PTHREAD_STACK_MIN) if (stack_size < min_stack_size)
stack_size = PTHREAD_STACK_MIN; stack_size = min_stack_size;
#endif
} }
if (stack_size > 0) { if (stack_size > 0) {

View File

@@ -66,6 +66,19 @@ static int orig_termios_fd = -1;
static struct termios orig_termios; static struct termios orig_termios;
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; 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) { static int uv__tty_is_slave(const int fd) {
int result; int result;
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -265,13 +278,18 @@ static void uv__tty_make_raw(struct termios* tio) {
int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
struct termios tmp; struct termios tmp;
int fd; int fd;
int rc;
if (tty->mode == (int) mode) if (tty->mode == (int) mode)
return 0; return 0;
fd = uv__stream_fd(tty); fd = uv__stream_fd(tty);
if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) { 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); return UV__ERR(errno);
/* This is used for uv_tty_reset_mode() */ /* This is used for uv_tty_reset_mode() */
@@ -301,11 +319,11 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
} }
/* Apply changes after draining */ /* Apply changes after draining */
if (tcsetattr(fd, TCSADRAIN, &tmp)) rc = uv__tcsetattr(fd, TCSADRAIN, &tmp);
return UV__ERR(errno); if (rc == 0)
tty->mode = mode;
tty->mode = mode; return rc;
return 0;
} }
@@ -328,7 +346,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
uv_handle_type uv_guess_handle(uv_file file) { uv_handle_type uv_guess_handle(uv_file file) {
struct sockaddr sa; struct sockaddr_storage ss;
struct stat s; struct stat s;
socklen_t len; socklen_t len;
int type; int type;
@@ -339,8 +357,24 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (isatty(file)) if (isatty(file))
return UV_TTY; 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; return UV_UNKNOWN_HANDLE;
}
if (S_ISREG(s.st_mode)) if (S_ISREG(s.st_mode))
return UV_FILE; return UV_FILE;
@@ -354,16 +388,29 @@ uv_handle_type uv_guess_handle(uv_file file) {
if (!S_ISSOCK(s.st_mode)) if (!S_ISSOCK(s.st_mode))
return UV_UNKNOWN_HANDLE; 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); len = sizeof(type);
if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
return UV_UNKNOWN_HANDLE; return UV_UNKNOWN_HANDLE;
len = sizeof(sa);
if (getsockname(file, &sa, &len))
return UV_UNKNOWN_HANDLE;
if (type == SOCK_DGRAM) 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; return UV_UDP;
if (type == SOCK_STREAM) { if (type == SOCK_STREAM) {
@@ -376,9 +423,9 @@ uv_handle_type uv_guess_handle(uv_file file) {
return UV_NAMED_PIPE; return UV_NAMED_PIPE;
#endif /* defined(_AIX) || defined(__DragonFly__) */ #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; return UV_TCP;
if (sa.sa_family == AF_UNIX) if (ss.ss_family == AF_UNIX)
return UV_NAMED_PIPE; return UV_NAMED_PIPE;
} }
@@ -400,8 +447,7 @@ int uv_tty_reset_mode(void) {
err = 0; err = 0;
if (orig_termios_fd != -1) if (orig_termios_fd != -1)
if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios)) err = uv__tcsetattr(orig_termios_fd, TCSANOW, &orig_termios);
err = UV__ERR(errno);
uv_spinlock_unlock(&termios_spinlock); uv_spinlock_unlock(&termios_spinlock);
errno = saved_errno; errno = saved_errno;

View File

@@ -201,6 +201,7 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
for (k = 0; k < chunks; ++k) { for (k = 0; k < chunks; ++k) {
iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE; iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE; iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
memset(&msgs[k].msg_hdr, 0, sizeof(msgs[k].msg_hdr));
msgs[k].msg_hdr.msg_iov = iov + k; msgs[k].msg_hdr.msg_iov = iov + k;
msgs[k].msg_hdr.msg_iovlen = 1; msgs[k].msg_hdr.msg_iovlen = 1;
msgs[k].msg_hdr.msg_name = peers + k; msgs[k].msg_hdr.msg_name = peers + k;
@@ -494,7 +495,7 @@ static int uv__set_reuse(int fd) {
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return UV__ERR(errno); return UV__ERR(errno);
} }
#elif defined(SO_REUSEPORT) && !defined(__linux__) #elif defined(SO_REUSEPORT) && !defined(__linux__) && !defined(__GNU__)
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return UV__ERR(errno); return UV__ERR(errno);
#else #else
@@ -655,16 +656,16 @@ int uv__udp_connect(uv_udp_t* handle,
} }
/* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html /* From https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html
* Any of uv supported UNIXs kernel should be standardized, but the kernel * Any of uv supported UNIXs kernel should be standardized, but the kernel
* implementation logic not same, let's use pseudocode to explain the udp * implementation logic not same, let's use pseudocode to explain the udp
* disconnect behaviors: * disconnect behaviors:
* *
* Predefined stubs for pseudocode: * Predefined stubs for pseudocode:
* 1. sodisconnect: The function to perform the real udp disconnect * 1. sodisconnect: The function to perform the real udp disconnect
* 2. pru_connect: The function to perform the real udp connect * 2. pru_connect: The function to perform the real udp connect
* 3. so: The kernel object match with socket fd * 3. so: The kernel object match with socket fd
* 4. addr: The sockaddr parameter from user space * 4. addr: The sockaddr parameter from user space
* *
* BSDs: * BSDs:
* if(sodisconnect(so) == 0) { // udp disconnect succeed * if(sodisconnect(so) == 0) { // udp disconnect succeed
* if (addr->sa_len != so->addr->sa_len) return EINVAL; * if (addr->sa_len != so->addr->sa_len) return EINVAL;
@@ -694,16 +695,25 @@ int uv__udp_disconnect(uv_udp_t* handle) {
#endif #endif
memset(&addr, 0, sizeof(addr)); memset(&addr, 0, sizeof(addr));
#if defined(__MVS__) #if defined(__MVS__)
addr.ss_family = AF_UNSPEC; addr.ss_family = AF_UNSPEC;
#else #else
addr.sa_family = AF_UNSPEC; addr.sa_family = AF_UNSPEC;
#endif #endif
do { do {
errno = 0; 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)); r = connect(handle->io_watcher.fd, (struct sockaddr*) &addr, sizeof(addr));
#endif
} while (r == -1 && errno == EINTR); } while (r == -1 && errno == EINTR);
if (r == -1) { if (r == -1) {
@@ -927,7 +937,8 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
!defined(__NetBSD__) && \ !defined(__NetBSD__) && \
!defined(__ANDROID__) && \ !defined(__ANDROID__) && \
!defined(__DragonFly__) && \ !defined(__DragonFly__) && \
!defined(__QNX__) !defined(__QNX__) && \
!defined(__GNU__)
static int uv__udp_set_source_membership4(uv_udp_t* handle, static int uv__udp_set_source_membership4(uv_udp_t* handle,
const struct sockaddr_in* multicast_addr, const struct sockaddr_in* multicast_addr,
const char* interface_addr, const char* interface_addr,
@@ -1119,7 +1130,8 @@ int uv_udp_set_source_membership(uv_udp_t* handle,
!defined(__NetBSD__) && \ !defined(__NetBSD__) && \
!defined(__ANDROID__) && \ !defined(__ANDROID__) && \
!defined(__DragonFly__) && \ !defined(__DragonFly__) && \
!defined(__QNX__) !defined(__QNX__) && \
!defined(__GNU__)
int err; int err;
union uv__sockaddr mcast_addr; union uv__sockaddr mcast_addr;
union uv__sockaddr src_addr; union uv__sockaddr src_addr;

View File

@@ -296,7 +296,9 @@ int uv_tcp_bind(uv_tcp_t* handle,
if (handle->type != UV_TCP) if (handle->type != UV_TCP)
return UV_EINVAL; return UV_EINVAL;
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
if (addr->sa_family == AF_INET) if (addr->sa_family == AF_INET)
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
else if (addr->sa_family == AF_INET6) else if (addr->sa_family == AF_INET6)

View File

@@ -130,7 +130,10 @@ enum {
UV_SIGNAL_ONE_SHOT = 0x02000000, UV_SIGNAL_ONE_SHOT = 0x02000000,
/* Only used by uv_poll_t handles. */ /* Only used by uv_poll_t handles. */
UV_HANDLE_POLL_SLOW = 0x01000000 UV_HANDLE_POLL_SLOW = 0x01000000,
/* Only used by uv_process_t handles. */
UV_HANDLE_REAP = 0x10000000
}; };
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);

View File

@@ -28,7 +28,7 @@
#include "req-inl.h" #include "req-inl.h"
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING && if (handle->flags & UV_HANDLE_CLOSING &&
!handle->async_sent) { !handle->async_sent) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -54,9 +54,9 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
} }
void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { void uv__async_close(uv_loop_t* loop, uv_async_t* handle) {
if (!((uv_async_t*)handle)->async_sent) { if (!((uv_async_t*)handle)->async_sent) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
uv__handle_closing(handle); uv__handle_closing(handle);
@@ -83,7 +83,7 @@ int uv_async_send(uv_async_t* handle) {
} }
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req) { uv_req_t* req) {
assert(handle->type == UV_ASYNC); assert(handle->type == UV_ASYNC);
assert(req->type == UV_WAKEUP); assert(req->type == UV_WAKEUP);
@@ -91,7 +91,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
handle->async_sent = 0; handle->async_sent = 0;
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle); uv__want_endgame(loop, (uv_handle_t*)handle);
} else if (handle->async_cb != NULL) { } else if (handle->async_cb != NULL) {
handle->async_cb(handle); handle->async_cb(handle);
} }

View File

@@ -84,10 +84,12 @@ static int uv__loops_capacity;
#define UV__LOOPS_CHUNK_SIZE 8 #define UV__LOOPS_CHUNK_SIZE 8
static uv_mutex_t uv__loops_lock; static uv_mutex_t uv__loops_lock;
static void uv__loops_init(void) { static void uv__loops_init(void) {
uv_mutex_init(&uv__loops_lock); uv_mutex_init(&uv__loops_lock);
} }
static int uv__loops_add(uv_loop_t* loop) { static int uv__loops_add(uv_loop_t* loop) {
uv_loop_t** new_loops; uv_loop_t** new_loops;
int new_capacity, i; int new_capacity, i;
@@ -115,6 +117,7 @@ failed_loops_realloc:
return ERROR_OUTOFMEMORY; return ERROR_OUTOFMEMORY;
} }
static void uv__loops_remove(uv_loop_t* loop) { static void uv__loops_remove(uv_loop_t* loop) {
int loop_index; int loop_index;
int smaller_capacity; int smaller_capacity;
@@ -173,7 +176,7 @@ void uv__wake_all_loops(void) {
uv_mutex_unlock(&uv__loops_lock); uv_mutex_unlock(&uv__loops_lock);
} }
static void uv_init(void) { static void uv__init(void) {
/* Tell Windows that we will handle critical errors. */ /* Tell Windows that we will handle critical errors. */
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX); SEM_NOOPENFILEERRORBOX);
@@ -199,19 +202,19 @@ static void uv_init(void) {
/* Fetch winapi function pointers. This must be done first because other /* Fetch winapi function pointers. This must be done first because other
* initialization code might need these function pointers to be loaded. * initialization code might need these function pointers to be loaded.
*/ */
uv_winapi_init(); uv__winapi_init();
/* Initialize winsock */ /* Initialize winsock */
uv_winsock_init(); uv__winsock_init();
/* Initialize FS */ /* Initialize FS */
uv_fs_init(); uv__fs_init();
/* Initialize signal stuff */ /* Initialize signal stuff */
uv_signals_init(); uv__signals_init();
/* Initialize console */ /* Initialize console */
uv_console_init(); uv__console_init();
/* Initialize utilities */ /* Initialize utilities */
uv__util_init(); uv__util_init();
@@ -327,7 +330,7 @@ void uv_update_time(uv_loop_t* loop) {
void uv__once_init(void) { void uv__once_init(void) {
uv_once(&uv_init_guard_, uv_init); uv_once(&uv_init_guard_, uv__init);
} }
@@ -395,23 +398,28 @@ int uv_loop_fork(uv_loop_t* loop) {
} }
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->pending_reqs_tail != NULL ||
loop->endgame_handles != NULL;
}
int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop);
}
int uv_backend_timeout(const uv_loop_t* loop) { int uv_backend_timeout(const uv_loop_t* loop) {
if (loop->stop_flag != 0) if (loop->stop_flag == 0 &&
return 0; /* uv__loop_alive(loop) && */
(uv__has_active_handles(loop) || uv__has_active_reqs(loop)) &&
if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop)) loop->pending_reqs_tail == NULL &&
return 0; loop->idle_handles == NULL &&
loop->endgame_handles == NULL)
if (loop->pending_reqs_tail) return uv__next_timeout(loop);
return 0; return 0;
if (loop->endgame_handles)
return 0;
if (loop->idle_handles)
return 0;
return uv__next_timeout(loop);
} }
@@ -462,8 +470,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
if (overlapped) { if (overlapped) {
/* Package was dequeued */ /* Package was dequeued */
req = uv_overlapped_to_req(overlapped); req = uv__overlapped_to_req(overlapped);
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
/* Some time might have passed waiting for I/O, /* Some time might have passed waiting for I/O,
* so update the loop time here. * so update the loop time here.
@@ -547,8 +555,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
* meant only to wake us up. * meant only to wake us up.
*/ */
if (overlappeds[i].lpOverlapped) { if (overlappeds[i].lpOverlapped) {
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); req = uv__overlapped_to_req(overlappeds[i].lpOverlapped);
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
} }
} }
@@ -581,22 +589,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
} }
static int uv__loop_alive(const uv_loop_t* loop) {
return uv__has_active_handles(loop) ||
uv__has_active_reqs(loop) ||
loop->endgame_handles != NULL;
}
int uv_loop_alive(const uv_loop_t* loop) {
return uv__loop_alive(loop);
}
int uv_run(uv_loop_t *loop, uv_run_mode mode) { int uv_run(uv_loop_t *loop, uv_run_mode mode) {
DWORD timeout; DWORD timeout;
int r; int r;
int ran_pending; int can_sleep;
r = uv__loop_alive(loop); r = uv__loop_alive(loop);
if (!r) if (!r)
@@ -606,12 +602,14 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv_update_time(loop); uv_update_time(loop);
uv__run_timers(loop); uv__run_timers(loop);
ran_pending = uv_process_reqs(loop); can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
uv_idle_invoke(loop);
uv_prepare_invoke(loop); uv__process_reqs(loop);
uv__idle_invoke(loop);
uv__prepare_invoke(loop);
timeout = 0; 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); timeout = uv_backend_timeout(loop);
if (pGetQueuedCompletionStatusEx) if (pGetQueuedCompletionStatusEx)
@@ -619,6 +617,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
else else
uv__poll_wine(loop, timeout); 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* /* Run one final update on the provider_idle_time in case uv__poll*
* returned because the timeout expired, but no events were received. This * 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 * call will be ignored if the provider_entry_time was either never set (if
@@ -626,8 +629,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
*/ */
uv__metrics_update_idle_time(loop); uv__metrics_update_idle_time(loop);
uv_check_invoke(loop); uv__check_invoke(loop);
uv_process_endgames(loop); uv__process_endgames(loop);
if (mode == UV_RUN_ONCE) { if (mode == UV_RUN_ONCE) {
/* UV_RUN_ONCE implies forward progress: at least one callback must have /* UV_RUN_ONCE implies forward progress: at least one callback must have
@@ -638,6 +641,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
* the check. * the check.
*/ */
uv_update_time(loop);
uv__run_timers(loop); uv__run_timers(loop);
} }

View File

@@ -33,7 +33,7 @@
const unsigned int uv_directory_watcher_buffer_size = 4096; const unsigned int uv_directory_watcher_buffer_size = 4096;
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, static void uv__fs_event_queue_readdirchanges(uv_loop_t* loop,
uv_fs_event_t* handle) { uv_fs_event_t* handle) {
assert(handle->dir_handle != INVALID_HANDLE_VALUE); assert(handle->dir_handle != INVALID_HANDLE_VALUE);
assert(!handle->req_pending); assert(!handle->req_pending);
@@ -57,15 +57,15 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
NULL)) { NULL)) {
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(&handle->req, GetLastError()); SET_REQ_ERROR(&handle->req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)&handle->req); uv__insert_pending_req(loop, (uv_req_t*)&handle->req);
} }
handle->req_pending = 1; handle->req_pending = 1;
} }
static void uv_relative_path(const WCHAR* filename, static void uv__relative_path(const WCHAR* filename,
const WCHAR* dir, const WCHAR* dir,
WCHAR** relpath) { WCHAR** relpath) {
size_t relpathlen; size_t relpathlen;
size_t filenamelen = wcslen(filename); size_t filenamelen = wcslen(filename);
size_t dirlen = wcslen(dir); size_t dirlen = wcslen(dir);
@@ -80,7 +80,7 @@ static void uv_relative_path(const WCHAR* filename,
(*relpath)[relpathlen] = L'\0'; (*relpath)[relpathlen] = L'\0';
} }
static int uv_split_path(const WCHAR* filename, WCHAR** dir, static int uv__split_path(const WCHAR* filename, WCHAR** dir,
WCHAR** file) { WCHAR** file) {
size_t len, i; size_t len, i;
DWORD dir_len; DWORD dir_len;
@@ -255,12 +255,12 @@ int uv_fs_event_start(uv_fs_event_t* handle,
short_path_done: short_path_done:
short_path = short_path_buffer; short_path = short_path_buffer;
if (uv_split_path(pathw, &dir, &handle->filew) != 0) { if (uv__split_path(pathw, &dir, &handle->filew) != 0) {
last_error = GetLastError(); last_error = GetLastError();
goto error; goto error;
} }
if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) { if (uv__split_path(short_path, NULL, &handle->short_filew) != 0) {
last_error = GetLastError(); last_error = GetLastError();
goto error; goto error;
} }
@@ -423,7 +423,7 @@ static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
} }
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle) { uv_fs_event_t* handle) {
FILE_NOTIFY_INFORMATION* file_info; FILE_NOTIFY_INFORMATION* file_info;
int err, sizew, size; int err, sizew, size;
@@ -442,7 +442,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
*/ */
if (!uv__is_active(handle)) { if (!uv__is_active(handle)) {
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
return; return;
} }
@@ -515,9 +515,9 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
if (long_filenamew) { if (long_filenamew) {
/* Get the file name out of the long path. */ /* Get the file name out of the long path. */
uv_relative_path(long_filenamew, uv__relative_path(long_filenamew,
handle->dirw, handle->dirw,
&filenamew); &filenamew);
uv__free(long_filenamew); uv__free(long_filenamew);
long_filenamew = filenamew; long_filenamew = filenamew;
sizew = -1; sizew = -1;
@@ -575,26 +575,26 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
} }
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*)handle); uv__want_endgame(loop, (uv_handle_t*)handle);
} else if (uv__is_active(handle)) { } else if (uv__is_active(handle)) {
uv_fs_event_queue_readdirchanges(loop, handle); uv__fs_event_queue_readdirchanges(loop, handle);
} }
} }
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
uv_fs_event_stop(handle); uv_fs_event_stop(handle);
uv__handle_closing(handle); uv__handle_closing(handle);
if (!handle->req_pending) { if (!handle->req_pending) {
uv_want_endgame(loop, (uv_handle_t*)handle); uv__want_endgame(loop, (uv_handle_t*)handle);
} }
} }
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) { if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));

View File

@@ -46,7 +46,7 @@
do { \ do { \
if (req == NULL) \ if (req == NULL) \
return UV_EINVAL; \ return UV_EINVAL; \
uv_fs_req_init(loop, req, subtype, cb); \ uv__fs_req_init(loop, req, subtype, cb); \
} \ } \
while (0) while (0)
@@ -132,7 +132,7 @@ static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGE
static DWORD uv__allocation_granularity; static DWORD uv__allocation_granularity;
void uv_fs_init(void) { void uv__fs_init(void) {
SYSTEM_INFO system_info; SYSTEM_INFO system_info;
GetSystemInfo(&system_info); GetSystemInfo(&system_info);
@@ -241,7 +241,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req,
uv_fs_type fs_type, const uv_fs_cb cb) { uv_fs_type fs_type, const uv_fs_cb cb) {
uv__once_init(); uv__once_init();
UV_REQ_INIT(req, UV_FS); UV_REQ_INIT(req, UV_FS);
@@ -912,12 +912,11 @@ void fs__read(uv_fs_t* req) {
SET_REQ_RESULT(req, bytes); SET_REQ_RESULT(req, bytes);
} else { } else {
error = GetLastError(); error = GetLastError();
if (error == ERROR_ACCESS_DENIED) { if (error == ERROR_ACCESS_DENIED) {
error = ERROR_INVALID_FLAGS; error = ERROR_INVALID_FLAGS;
} }
if (error == ERROR_HANDLE_EOF) { if (error == ERROR_HANDLE_EOF || error == ERROR_BROKEN_PIPE) {
SET_REQ_RESULT(req, bytes); SET_REQ_RESULT(req, bytes);
} else { } else {
SET_REQ_WIN32_ERROR(req, error); SET_REQ_WIN32_ERROR(req, error);
@@ -1881,8 +1880,9 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
NULL); NULL);
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
ret = GetLastError(); return GetLastError();
else if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
ret = GetLastError(); ret = GetLastError();
else else
ret = 0; ret = 0;
@@ -2300,13 +2300,13 @@ INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
flags, flags,
NULL); NULL);
if (handle == INVALID_HANDLE_VALUE) { if (handle == INVALID_HANDLE_VALUE)
return GetLastError();
if (fs__utime_handle(handle, atime, mtime) != 0)
ret = GetLastError(); ret = GetLastError();
} else if (fs__utime_handle(handle, atime, mtime) != 0) { else
ret = GetLastError();
} else {
ret = 0; ret = 0;
}
CloseHandle(handle); CloseHandle(handle);
return ret; return ret;

View File

@@ -55,7 +55,7 @@
\ \
if (handle->flags & UV_HANDLE_CLOSING && \ if (handle->flags & UV_HANDLE_CLOSING && \
handle->reqs_pending == 0) { \ handle->reqs_pending == 0) { \
uv_want_endgame(loop, (uv_handle_t*)handle); \ uv__want_endgame(loop, (uv_handle_t*)handle); \
} \ } \
} while (0) } while (0)
@@ -85,7 +85,7 @@
} while (0) } while (0)
INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { INLINE static void uv__want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) { if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
handle->flags |= UV_HANDLE_ENDGAME_QUEUED; handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
@@ -95,7 +95,7 @@ INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
} }
INLINE static void uv_process_endgames(uv_loop_t* loop) { INLINE static void uv__process_endgames(uv_loop_t* loop) {
uv_handle_t* handle; uv_handle_t* handle;
while (loop->endgame_handles) { while (loop->endgame_handles) {
@@ -106,23 +106,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
switch (handle->type) { switch (handle->type) {
case UV_TCP: case UV_TCP:
uv_tcp_endgame(loop, (uv_tcp_t*) handle); uv__tcp_endgame(loop, (uv_tcp_t*) handle);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
uv_pipe_endgame(loop, (uv_pipe_t*) handle); uv__pipe_endgame(loop, (uv_pipe_t*) handle);
break; break;
case UV_TTY: case UV_TTY:
uv_tty_endgame(loop, (uv_tty_t*) handle); uv__tty_endgame(loop, (uv_tty_t*) handle);
break; break;
case UV_UDP: case UV_UDP:
uv_udp_endgame(loop, (uv_udp_t*) handle); uv__udp_endgame(loop, (uv_udp_t*) handle);
break; break;
case UV_POLL: case UV_POLL:
uv_poll_endgame(loop, (uv_poll_t*) handle); uv__poll_endgame(loop, (uv_poll_t*) handle);
break; break;
case UV_TIMER: case UV_TIMER:
@@ -133,23 +133,23 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
case UV_PREPARE: case UV_PREPARE:
case UV_CHECK: case UV_CHECK:
case UV_IDLE: case UV_IDLE:
uv_loop_watcher_endgame(loop, handle); uv__loop_watcher_endgame(loop, handle);
break; break;
case UV_ASYNC: case UV_ASYNC:
uv_async_endgame(loop, (uv_async_t*) handle); uv__async_endgame(loop, (uv_async_t*) handle);
break; break;
case UV_SIGNAL: case UV_SIGNAL:
uv_signal_endgame(loop, (uv_signal_t*) handle); uv__signal_endgame(loop, (uv_signal_t*) handle);
break; break;
case UV_PROCESS: case UV_PROCESS:
uv_process_endgame(loop, (uv_process_t*) handle); uv__process_endgame(loop, (uv_process_t*) handle);
break; break;
case UV_FS_EVENT: case UV_FS_EVENT:
uv_fs_event_endgame(loop, (uv_fs_event_t*) handle); uv__fs_event_endgame(loop, (uv_fs_event_t*) handle);
break; break;
case UV_FS_POLL: case UV_FS_POLL:

View File

@@ -77,63 +77,63 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
/* Handle-specific close actions */ /* Handle-specific close actions */
switch (handle->type) { switch (handle->type) {
case UV_TCP: case UV_TCP:
uv_tcp_close(loop, (uv_tcp_t*)handle); uv__tcp_close(loop, (uv_tcp_t*)handle);
return; return;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
uv_pipe_close(loop, (uv_pipe_t*) handle); uv__pipe_close(loop, (uv_pipe_t*) handle);
return; return;
case UV_TTY: case UV_TTY:
uv_tty_close((uv_tty_t*) handle); uv__tty_close((uv_tty_t*) handle);
return; return;
case UV_UDP: case UV_UDP:
uv_udp_close(loop, (uv_udp_t*) handle); uv__udp_close(loop, (uv_udp_t*) handle);
return; return;
case UV_POLL: case UV_POLL:
uv_poll_close(loop, (uv_poll_t*) handle); uv__poll_close(loop, (uv_poll_t*) handle);
return; return;
case UV_TIMER: case UV_TIMER:
uv_timer_stop((uv_timer_t*)handle); uv_timer_stop((uv_timer_t*)handle);
uv__handle_closing(handle); uv__handle_closing(handle);
uv_want_endgame(loop, handle); uv__want_endgame(loop, handle);
return; return;
case UV_PREPARE: case UV_PREPARE:
uv_prepare_stop((uv_prepare_t*)handle); uv_prepare_stop((uv_prepare_t*)handle);
uv__handle_closing(handle); uv__handle_closing(handle);
uv_want_endgame(loop, handle); uv__want_endgame(loop, handle);
return; return;
case UV_CHECK: case UV_CHECK:
uv_check_stop((uv_check_t*)handle); uv_check_stop((uv_check_t*)handle);
uv__handle_closing(handle); uv__handle_closing(handle);
uv_want_endgame(loop, handle); uv__want_endgame(loop, handle);
return; return;
case UV_IDLE: case UV_IDLE:
uv_idle_stop((uv_idle_t*)handle); uv_idle_stop((uv_idle_t*)handle);
uv__handle_closing(handle); uv__handle_closing(handle);
uv_want_endgame(loop, handle); uv__want_endgame(loop, handle);
return; return;
case UV_ASYNC: case UV_ASYNC:
uv_async_close(loop, (uv_async_t*) handle); uv__async_close(loop, (uv_async_t*) handle);
return; return;
case UV_SIGNAL: case UV_SIGNAL:
uv_signal_close(loop, (uv_signal_t*) handle); uv__signal_close(loop, (uv_signal_t*) handle);
return; return;
case UV_PROCESS: case UV_PROCESS:
uv_process_close(loop, (uv_process_t*) handle); uv__process_close(loop, (uv_process_t*) handle);
return; return;
case UV_FS_EVENT: case UV_FS_EVENT:
uv_fs_event_close(loop, (uv_fs_event_t*) handle); uv__fs_event_close(loop, (uv_fs_event_t*) handle);
return; return;
case UV_FS_POLL: case UV_FS_POLL:

View File

@@ -76,25 +76,28 @@ typedef struct {
uint32_t delayed_error; uint32_t delayed_error;
} uv__ipc_socket_xfer_info_t; } uv__ipc_socket_xfer_info_t;
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb); int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client); int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb); uv_read_cb read_cb);
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, int uv__tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[], int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
unsigned int nbufs); unsigned int nbufs);
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req); void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_write_t* req); uv_write_t* req);
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req); uv_req_t* req);
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_connect_t* req); 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_close(uv_loop_t* loop, uv_tcp_t* tcp);
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
int uv__tcp_xfer_export(uv_tcp_t* handle, int uv__tcp_xfer_export(uv_tcp_t* handle,
int pid, int pid,
@@ -108,12 +111,12 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
/* /*
* UDP * UDP
*/ */
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
uv_udp_send_t* req); uv_udp_send_t* req);
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle);
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
/* /*
@@ -122,9 +125,9 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
int uv__create_stdio_pipe_pair(uv_loop_t* loop, int uv__create_stdio_pipe_pair(uv_loop_t* loop,
uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags); uv_pipe_t* parent_pipe, HANDLE* child_pipe_ptr, unsigned int flags);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client);
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, int uv__pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb); uv_read_cb read_cb);
void uv__pipe_read_stop(uv_pipe_t* handle); void uv__pipe_read_stop(uv_pipe_t* handle);
int uv__pipe_write(uv_loop_t* loop, int uv__pipe_write(uv_loop_t* loop,
@@ -134,75 +137,77 @@ int uv__pipe_write(uv_loop_t* loop,
size_t nbufs, size_t nbufs,
uv_stream_t* send_handle, uv_stream_t* send_handle,
uv_write_cb cb); 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, void uv__process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* req); uv_req_t* req);
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_write_t* req); uv_write_t* req);
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* raw_req); uv_req_t* raw_req);
void uv_process_pipe_connect_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); uv_connect_t* req);
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req); uv_shutdown_t* req);
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); 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);
void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
/* /*
* TTY * TTY
*/ */
void uv_console_init(void); void uv__console_init(void);
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb); uv_read_cb read_cb);
int uv_tty_read_stop(uv_tty_t* handle); int uv__tty_read_stop(uv_tty_t* handle);
int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, int uv__tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[], int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
unsigned int nbufs); unsigned int nbufs);
void uv_tty_close(uv_tty_t* handle); void uv__tty_close(uv_tty_t* handle);
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req); uv_req_t* req);
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req); uv_write_t* req);
/* /*
* uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it * TODO: find a way to remove it
*/ */
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req); uv_req_t* raw_req);
/* /*
* uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it * TODO: find a way to remove it
*/ */
void uv_process_tty_connect_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); uv_connect_t* req);
void uv__process_tty_shutdown_req(uv_loop_t* loop,
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); uv_tty_t* stream,
uv_shutdown_t* req);
void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
/* /*
* Poll watchers * Poll watchers
*/ */
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
uv_req_t* req); uv_req_t* req);
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle);
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
/* /*
* Loop watchers * Loop watchers
*/ */
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv__loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
void uv_prepare_invoke(uv_loop_t* loop); void uv__prepare_invoke(uv_loop_t* loop);
void uv_check_invoke(uv_loop_t* loop); void uv__check_invoke(uv_loop_t* loop);
void uv_idle_invoke(uv_loop_t* loop); void uv__idle_invoke(uv_loop_t* loop);
void uv__once_init(void); void uv__once_init(void);
@@ -210,53 +215,47 @@ void uv__once_init(void);
/* /*
* Async watcher * Async watcher
*/ */
void uv_async_close(uv_loop_t* loop, uv_async_t* handle); void uv__async_close(uv_loop_t* loop, uv_async_t* handle);
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle);
void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, void uv__process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
uv_req_t* req); uv_req_t* req);
/* /*
* Signal watcher * Signal watcher
*/ */
void uv_signals_init(void); void uv__signals_init(void);
int uv__signal_dispatch(int signum); int uv__signal_dispatch(int signum);
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle); void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle);
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle); void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req); uv_req_t* req);
/* /*
* Spawn * Spawn
*/ */
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle); void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
void uv_process_close(uv_loop_t* loop, uv_process_t* handle); void uv__process_close(uv_loop_t* loop, uv_process_t* handle);
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle);
/*
* Error
*/
int uv_translate_sys_error(int sys_errno);
/* /*
* FS * FS
*/ */
void uv_fs_init(void); void uv__fs_init(void);
/* /*
* FS Event * FS Event
*/ */
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, void uv__process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
uv_fs_event_t* handle); uv_fs_event_t* handle);
void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle); void uv__fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); void uv__fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
/* /*
@@ -303,28 +302,28 @@ HANDLE uv__stdio_handle(BYTE* buffer, int fd);
/* /*
* Winapi and ntapi utility functions * Winapi and ntapi utility functions
*/ */
void uv_winapi_init(void); void uv__winapi_init(void);
/* /*
* Winsock utility functions * Winsock utility functions
*/ */
void uv_winsock_init(void); void uv__winsock_init(void);
int uv_ntstatus_to_winsock_error(NTSTATUS status); int uv__ntstatus_to_winsock_error(NTSTATUS status);
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
int* addr_len, WSAOVERLAPPED *overlapped, int* addr_len, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped); AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
/* Whether there are any non-IFS LSPs stacked on TCP */ /* Whether there are any non-IFS LSPs stacked on TCP */

View File

@@ -26,7 +26,7 @@
#include "handle-inl.h" #include "handle-inl.h"
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { void uv__loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
handle->flags |= UV_HANDLE_CLOSED; handle->flags |= UV_HANDLE_CLOSED;
@@ -104,7 +104,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
} \ } \
\ \
\ \
void uv_##name##_invoke(uv_loop_t* loop) { \ void uv__##name##_invoke(uv_loop_t* loop) { \
uv_##name##_t* handle; \ uv_##name##_t* handle; \
\ \
(loop)->next_##name##_handle = (loop)->name##_handles; \ (loop)->next_##name##_handle = (loop)->name##_handles; \

View File

@@ -98,13 +98,13 @@ static void eof_timer_destroy(uv_pipe_t* pipe);
static void eof_timer_close_cb(uv_handle_t* handle); static void eof_timer_close_cb(uv_handle_t* handle);
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { static void uv__unique_pipe_name(char* ptr, char* name, size_t size) {
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId()); snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
} }
int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
handle->reqs_pending = 0; handle->reqs_pending = 0;
handle->handle = INVALID_HANDLE_VALUE; handle->handle = INVALID_HANDLE_VALUE;
@@ -120,15 +120,11 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
} }
static void uv_pipe_connection_init(uv_pipe_t* handle) { static void uv__pipe_connection_init(uv_pipe_t* handle) {
uv_connection_init((uv_stream_t*) handle); assert(!(handle->flags & UV_HANDLE_PIPESERVER));
uv__connection_init((uv_stream_t*) handle);
handle->read_req.data = handle; handle->read_req.data = handle;
handle->pipe.conn.eof_timer = NULL; 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);
}
} }
@@ -209,7 +205,7 @@ static int uv__pipe_server(
int err; int err;
for (;;) { for (;;) {
uv_unique_pipe_name(random, name, nameSize); uv__unique_pipe_name(random, name, nameSize);
pipeHandle = CreateNamedPipeA(name, pipeHandle = CreateNamedPipeA(name,
access | FILE_FLAG_FIRST_PIPE_INSTANCE, access | FILE_FLAG_FIRST_PIPE_INSTANCE,
@@ -393,6 +389,8 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
unsigned int client_flags; unsigned int client_flags;
int err; int err;
uv__pipe_connection_init(parent_pipe);
server_pipe = INVALID_HANDLE_VALUE; server_pipe = INVALID_HANDLE_VALUE;
client_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; goto error;
} }
uv_pipe_connection_init(parent_pipe);
parent_pipe->handle = server_pipe; parent_pipe->handle = server_pipe;
*child_pipe_ptr = client_pipe; *child_pipe_ptr = client_pipe;
@@ -450,11 +447,11 @@ int uv__create_stdio_pipe_pair(uv_loop_t* loop,
} }
static int uv_set_pipe_handle(uv_loop_t* loop, static int uv__set_pipe_handle(uv_loop_t* loop,
uv_pipe_t* handle, uv_pipe_t* handle,
HANDLE pipeHandle, HANDLE pipeHandle,
int fd, int fd,
DWORD duplex_flags) { DWORD duplex_flags) {
NTSTATUS nt_status; NTSTATUS nt_status;
IO_STATUS_BLOCK io_status; IO_STATUS_BLOCK io_status;
FILE_MODE_INFORMATION mode_info; FILE_MODE_INFORMATION mode_info;
@@ -462,7 +459,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
DWORD current_mode = 0; DWORD current_mode = 0;
DWORD err = 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; return UV_EINVAL;
if (handle->handle != INVALID_HANDLE_VALUE) if (handle->handle != INVALID_HANDLE_VALUE)
return UV_EBUSY; return UV_EBUSY;
@@ -478,18 +477,17 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
*/ */
if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL, if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
NULL, NULL, 0)) { NULL, NULL, 0)) {
return -1; return uv_translate_sys_error(GetLastError());
} else if (current_mode & PIPE_NOWAIT) { } else if (current_mode & PIPE_NOWAIT) {
SetLastError(ERROR_ACCESS_DENIED); return UV_EACCES;
return -1;
} }
} else { } else {
/* If this returns ERROR_INVALID_PARAMETER we probably opened /* If this returns ERROR_INVALID_PARAMETER we probably opened
* something that is not a pipe. */ * something that is not a pipe. */
if (err == ERROR_INVALID_PARAMETER) { 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), sizeof(mode_info),
FileModeInformation); FileModeInformation);
if (nt_status != STATUS_SUCCESS) { if (nt_status != STATUS_SUCCESS) {
return -1; return uv_translate_sys_error(err);
} }
if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT || if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) { mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
/* Non-overlapped pipe. */ /* Non-overlapped pipe. */
handle->flags |= UV_HANDLE_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 { } else {
/* Overlapped pipe. Try to associate with IOCP. */ /* Overlapped pipe. Try to associate with IOCP. */
if (CreateIoCompletionPort(pipeHandle, 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) { void uv__pipe_shutdown(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t *req) {
int err;
DWORD result; DWORD result;
uv_shutdown_t* req;
NTSTATUS nt_status; NTSTATUS nt_status;
IO_STATUS_BLOCK io_status; IO_STATUS_BLOCK io_status;
FILE_PIPE_LOCAL_INFORMATION pipe_info; 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; uv__ipc_xfer_queue_item_t* xfer_queue_item;
if ((handle->flags & UV_HANDLE_CONNECTION) && assert(handle->reqs_pending == 0);
handle->stream.conn.shutdown_req != NULL && assert(handle->flags & UV_HANDLE_CLOSING);
handle->stream.conn.write_reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED));
req = handle->stream.conn.shutdown_req;
/* Clear the shutdown_req field so we don't go here again. */ if (handle->flags & UV_HANDLE_CONNECTION) {
handle->stream.conn.shutdown_req = NULL; /* Free pending sockets */
while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
QUEUE* q;
SOCKET socket;
if (handle->flags & UV_HANDLE_CLOSING) { q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
UNREGISTER_HANDLE_REQ(loop, handle, req); QUEUE_REMOVE(q);
xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
/* Already closing. Cancel the shutdown. */ /* Materialize socket and close it */
if (req->cb) { socket = WSASocketW(FROM_PROTOCOL_INFO,
req->cb(req, UV_ECANCELED); 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) {
DECREASE_PENDING_REQ_COUNT(handle); CloseHandle(handle->read_req.event_handle);
return; handle->read_req.event_handle = NULL;
}
/* 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));
} }
DECREASE_PENDING_REQ_COUNT(handle);
return;
} }
if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) { if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
/* Short-circuit, no need to call FlushFileBuffers. */ DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
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_CLOSING && if (handle->flags & UV_HANDLE_PIPESERVER) {
handle->reqs_pending == 0) { assert(handle->pipe.serv.accept_reqs);
assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__free(handle->pipe.serv.accept_reqs);
handle->pipe.serv.accept_reqs = NULL;
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);
} }
uv__handle_close(handle);
} }
@@ -731,7 +705,9 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
if (!name) { if (!name) {
return UV_EINVAL; return UV_EINVAL;
} }
if (uv__is_closing(handle)) {
return UV_EINVAL;
}
if (!(handle->flags & UV_HANDLE_PIPESERVER)) { if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
handle->pipe.serv.pending_instances = default_pending_pipe_instances; handle->pipe.serv.pending_instances = default_pending_pipe_instances;
} }
@@ -815,7 +791,7 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
assert(loop); assert(loop);
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait /* 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)) { while (WaitNamedPipeW(handle->name, 30000)) {
/* The pipe is now available, try to connect. */ /* The pipe is now available, try to connect. */
pipeHandle = open_named_pipe(handle->name, &duplex_flags); pipeHandle = open_named_pipe(handle->name, &duplex_flags);
@@ -825,9 +801,10 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
SwitchToThread(); SwitchToThread();
} }
if (pipeHandle != INVALID_HANDLE_VALUE && if (pipeHandle != INVALID_HANDLE_VALUE) {
!uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
SET_REQ_SUCCESS(req); SET_REQ_SUCCESS(req);
req->u.connect.pipeHandle = pipeHandle;
req->u.connect.duplex_flags = duplex_flags;
} else { } else {
SET_REQ_ERROR(req, GetLastError()); 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); UV_REQ_INIT(req, UV_CONNECT);
req->handle = (uv_stream_t*) handle; req->handle = (uv_stream_t*) handle;
req->cb = cb; 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. */ /* Convert name to UTF16. */
nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR); nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
@@ -888,19 +877,10 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
goto error; goto error;
} }
assert(pipeHandle != INVALID_HANDLE_VALUE); req->u.connect.pipeHandle = pipeHandle;
req->u.connect.duplex_flags = duplex_flags;
if (uv_set_pipe_handle(loop,
(uv_pipe_t*) req->handle,
pipeHandle,
-1,
duplex_flags)) {
err = GetLastError();
goto error;
}
SET_REQ_SUCCESS(req); SET_REQ_SUCCESS(req);
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++; handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
return; return;
@@ -916,7 +896,7 @@ error:
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, err); SET_REQ_ERROR(req, err);
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++; handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
return; return;
@@ -937,7 +917,7 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
/* Cancel asynchronous read. */ /* Cancel asynchronous read. */
r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped); r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped);
assert(r || GetLastError() == ERROR_NOT_FOUND); assert(r || GetLastError() == ERROR_NOT_FOUND);
(void) r;
} else { } else {
/* Cancel synchronous read (which is happening in the thread pool). */ /* Cancel synchronous read (which is happening in the thread pool). */
HANDLE thread; HANDLE thread;
@@ -973,17 +953,30 @@ void uv__pipe_interrupt_read(uv_pipe_t* handle) {
void uv__pipe_read_stop(uv_pipe_t* handle) { void uv__pipe_read_stop(uv_pipe_t* handle) {
handle->flags &= ~UV_HANDLE_READING; handle->flags &= ~UV_HANDLE_READING;
DECREASE_ACTIVE_COUNT(handle->loop, handle); DECREASE_ACTIVE_COUNT(handle->loop, handle);
uv__pipe_interrupt_read(handle); uv__pipe_interrupt_read(handle);
} }
/* Cleans up uv_pipe_t (server or connection) and all resources associated with /* Cleans up uv_pipe_t (server or connection) and all resources associated with
* it. */ * 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; int i;
HANDLE pipeHandle; 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); uv__pipe_interrupt_read(handle);
if (handle->name) { if (handle->name) {
@@ -1003,45 +996,27 @@ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
} }
if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->flags & UV_HANDLE_CONNECTION) {
handle->flags &= ~UV_HANDLE_WRITABLE;
eof_timer_destroy(handle); eof_timer_destroy(handle);
} }
if ((handle->flags & UV_HANDLE_CONNECTION) 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); close_pipe(handle);
}
if (handle->reqs_pending == 0)
uv__want_endgame(loop, (uv_handle_t*) handle);
} }
void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { static void uv__pipe_queue_accept(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) {
uv_want_endgame(loop, (uv_handle_t*) handle);
}
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle);
}
static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
uv_pipe_accept_t* req, BOOL firstInstance) { uv_pipe_accept_t* req, BOOL firstInstance) {
assert(handle->flags & UV_HANDLE_LISTENING); assert(handle->flags & UV_HANDLE_LISTENING);
if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) { if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++; handle->reqs_pending++;
return; return;
} }
@@ -1061,7 +1036,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
} }
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
handle->reqs_pending++; handle->reqs_pending++;
return; return;
} }
@@ -1071,7 +1046,7 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
} }
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
uv_loop_t* loop = server->loop; uv_loop_t* loop = server->loop;
uv_pipe_t* pipe_client; uv_pipe_t* pipe_client;
uv_pipe_accept_t* req; uv_pipe_accept_t* req;
@@ -1099,6 +1074,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
} else { } else {
pipe_client = (uv_pipe_t*) client; pipe_client = (uv_pipe_t*) client;
uv__pipe_connection_init(pipe_client);
/* Find a connection instance that has been connected, but not yet /* Find a connection instance that has been connected, but not yet
* accepted. */ * 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 */ /* Initialize the client handle and copy the pipeHandle to the client */
uv_pipe_connection_init(pipe_client);
pipe_client->handle = req->pipeHandle; pipe_client->handle = req->pipeHandle;
pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
@@ -1121,7 +1096,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
server->handle = INVALID_HANDLE_VALUE; server->handle = INVALID_HANDLE_VALUE;
if (!(server->flags & UV_HANDLE_CLOSING)) { if (!(server->flags & UV_HANDLE_CLOSING)) {
uv_pipe_queue_accept(loop, server, req, FALSE); uv__pipe_queue_accept(loop, server, req, FALSE);
} }
} }
@@ -1130,7 +1105,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
/* Starts listening for connections for the given pipe. */ /* Starts listening for connections for the given pipe. */
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { int uv__pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;
int i; int i;
@@ -1162,7 +1137,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE); assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
for (i = 0; i < handle->pipe.serv.pending_instances; i++) { for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0); uv__pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
} }
return 0; return 0;
@@ -1306,7 +1281,7 @@ static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out
} }
static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { static void uv__pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
uv_read_t* req; uv_read_t* req;
int result; int result;
@@ -1365,15 +1340,15 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
return; return;
error: error:
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++; handle->reqs_pending++;
} }
int uv_pipe_read_start(uv_pipe_t* handle, int uv__pipe_read_start(uv_pipe_t* handle,
uv_alloc_cb alloc_cb, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) { uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;
handle->flags |= UV_HANDLE_READING; handle->flags |= UV_HANDLE_READING;
@@ -1391,14 +1366,14 @@ int uv_pipe_read_start(uv_pipe_t* handle,
uv_fatal_error(GetLastError(), "CreateEvent"); uv_fatal_error(GetLastError(), "CreateEvent");
} }
} }
uv_pipe_queue_read(loop, handle); uv__pipe_queue_read(loop, handle);
} }
return 0; return 0;
} }
static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle, static void uv__insert_non_overlapped_write_req(uv_pipe_t* handle,
uv_write_t* req) { uv_write_t* req) {
req->next_req = NULL; req->next_req = NULL;
if (handle->pipe.conn.non_overlapped_writes_tail) { if (handle->pipe.conn.non_overlapped_writes_tail) {
@@ -1434,7 +1409,7 @@ static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
} }
static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { static void uv__queue_non_overlapped_write(uv_pipe_t* handle) {
uv_write_t* req = uv_remove_non_overlapped_write_req(handle); uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
if (req) { if (req) {
if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc, if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
@@ -1575,9 +1550,9 @@ static int uv__pipe_write_data(uv_loop_t* loop,
return 0; return 0;
} else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
req->write_buffer = write_buf; req->write_buffer = write_buf;
uv_insert_non_overlapped_write_req(handle, req); uv__insert_non_overlapped_write_req(handle, req);
if (handle->stream.conn.write_reqs_pending == 0) { if (handle->stream.conn.write_reqs_pending == 0) {
uv_queue_non_overlapped_write(handle); uv__queue_non_overlapped_write(handle);
} }
/* Request queued by the kernel. */ /* Request queued by the kernel. */
@@ -1790,7 +1765,7 @@ int uv__pipe_write(uv_loop_t* loop,
} }
static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, static void uv__pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
uv_buf_t buf) { uv_buf_t buf) {
/* If there is an eof timer running, we don't need it any more, so discard /* If there is an eof timer running, we don't need it any more, so discard
* it. */ * it. */
@@ -1802,7 +1777,7 @@ static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
} }
static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error, static void uv__pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
uv_buf_t buf) { uv_buf_t buf) {
/* If there is an eof timer running, we don't need it any more, so discard /* If there is an eof timer running, we don't need it any more, so discard
* it. */ * it. */
@@ -1814,12 +1789,12 @@ static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
} }
static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, static void uv__pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
int error, uv_buf_t buf) { int error, uv_buf_t buf) {
if (error == ERROR_BROKEN_PIPE) { if (error == ERROR_BROKEN_PIPE) {
uv_pipe_read_eof(loop, handle, buf); uv__pipe_read_eof(loop, handle, buf);
} else { } else {
uv_pipe_read_error(loop, handle, error, buf); uv__pipe_read_error(loop, handle, error, buf);
} }
} }
@@ -1890,7 +1865,7 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop,
/* Read into the user buffer. */ /* Read into the user buffer. */
if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) { if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) {
uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); uv__pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
return 0; /* Break out of read loop. */ return 0; /* Break out of read loop. */
} }
@@ -1977,14 +1952,14 @@ invalid:
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
error: error:
uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
return 0; /* Break out of read loop. */ return 0; /* Break out of read loop. */
} }
void uv_process_pipe_read_req(uv_loop_t* loop, void uv__process_pipe_read_req(uv_loop_t* loop,
uv_pipe_t* handle, uv_pipe_t* handle,
uv_req_t* req) { uv_req_t* req) {
assert(handle->type == UV_NAMED_PIPE); assert(handle->type == UV_NAMED_PIPE);
handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING); handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING);
@@ -2005,7 +1980,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
* indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to * indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to
* the user; we'll start a new zero-read at the end of this function. */ * the user; we'll start a new zero-read at the end of this function. */
if (err != ERROR_OPERATION_ABORTED) if (err != ERROR_OPERATION_ABORTED)
uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); uv__pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
} else { } else {
/* The zero-read completed without error, indicating there is data /* The zero-read completed without error, indicating there is data
@@ -2015,7 +1990,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
/* Get the number of bytes available. */ /* Get the number of bytes available. */
avail = 0; avail = 0;
if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL)) if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL))
uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); uv__pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
/* Read until we've either read all the bytes available, or the 'reading' /* Read until we've either read all the bytes available, or the 'reading'
* flag is cleared. */ * flag is cleared. */
@@ -2044,12 +2019,12 @@ void uv_process_pipe_read_req(uv_loop_t* loop,
/* Start another zero-read request if necessary. */ /* Start another zero-read request if necessary. */
if ((handle->flags & UV_HANDLE_READING) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_pipe_queue_read(loop, handle); uv__pipe_queue_read(loop, handle);
} }
} }
void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_write_t* req) { uv_write_t* req) {
int err; int err;
@@ -2091,26 +2066,25 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE && if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
handle->pipe.conn.non_overlapped_writes_tail) { handle->pipe.conn.non_overlapped_writes_tail) {
assert(handle->stream.conn.write_reqs_pending > 0); assert(handle->stream.conn.write_reqs_pending > 0);
uv_queue_non_overlapped_write(handle); uv__queue_non_overlapped_write(handle);
} }
if (handle->stream.conn.shutdown_req != NULL && if (handle->stream.conn.write_reqs_pending == 0)
handle->stream.conn.write_reqs_pending == 0) { if (handle->flags & UV_HANDLE_SHUTTING)
uv_want_endgame(loop, (uv_handle_t*)handle); uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
}
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, void uv__process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_req_t* raw_req) { uv_req_t* raw_req) {
uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req; uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
assert(handle->type == UV_NAMED_PIPE); assert(handle->type == UV_NAMED_PIPE);
if (handle->flags & UV_HANDLE_CLOSING) { 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); assert(req->pipeHandle == INVALID_HANDLE_VALUE);
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
return; return;
@@ -2130,7 +2104,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
req->pipeHandle = INVALID_HANDLE_VALUE; req->pipeHandle = INVALID_HANDLE_VALUE;
} }
if (!(handle->flags & UV_HANDLE_CLOSING)) { if (!(handle->flags & UV_HANDLE_CLOSING)) {
uv_pipe_queue_accept(loop, handle, req, FALSE); uv__pipe_queue_accept(loop, handle, req, FALSE);
} }
} }
@@ -2138,54 +2112,74 @@ 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, void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_connect_t* req) { uv_connect_t* req) {
HANDLE pipeHandle;
DWORD duplex_flags;
int err; int err;
assert(handle->type == UV_NAMED_PIPE); assert(handle->type == UV_NAMED_PIPE);
UNREGISTER_HANDLE_REQ(loop, handle, req); UNREGISTER_HANDLE_REQ(loop, handle, req);
if (req->cb) { err = 0;
err = 0; if (REQ_SUCCESS(req)) {
if (REQ_SUCCESS(req)) { pipeHandle = req->u.connect.pipeHandle;
uv_pipe_connection_init(handle); duplex_flags = req->u.connect.duplex_flags;
} else { err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
err = GET_REQ_ERROR(req); if (err)
} CloseHandle(pipeHandle);
req->cb(req, uv_translate_sys_error(err)); } else {
err = uv_translate_sys_error(GET_REQ_ERROR(req));
} }
if (req->cb)
req->cb(req, err);
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
uv_shutdown_t* req) { uv_shutdown_t* req) {
int err;
assert(handle->type == UV_NAMED_PIPE); 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); UNREGISTER_HANDLE_REQ(loop, handle, req);
if (handle->flags & UV_HANDLE_READABLE) { if (handle->flags & UV_HANDLE_CLOSING) {
/* Initialize and optionally start the eof timer. Only do this if the pipe /* Already closing. Cancel the shutdown. */
* is readable and we haven't seen EOF come in ourselves. */ err = UV_ECANCELED;
eof_timer_init(handle); } else if (!REQ_SUCCESS(req)) {
/* An error occurred in trying to shutdown gracefully. */
/* If reading start the timer right now. Otherwise uv_pipe_queue_read will err = uv_translate_sys_error(GET_REQ_ERROR(req));
* start it. */
if (handle->flags & UV_HANDLE_READ_PENDING) {
eof_timer_start(handle);
}
} else { } else {
/* This pipe is not readable. We can just close it to let the other end if (handle->flags & UV_HANDLE_READABLE) {
* know that we're done writing. */ /* Initialize and optionally start the eof timer. Only do this if the pipe
close_pipe(handle); * 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) { if (req->cb)
req->cb(req, 0); req->cb(req, err);
}
DECREASE_PENDING_REQ_COUNT(handle); 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); 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); 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; pipe->pipe.conn.eof_timer->data = pipe;
uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer); uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
} }
@@ -2231,9 +2226,9 @@ static void eof_timer_cb(uv_timer_t* timer) {
assert(pipe->type == UV_NAMED_PIPE); assert(pipe->type == UV_NAMED_PIPE);
/* This should always be true, since we start the timer only in /* This should always be true, since we start the timer only in
* uv_pipe_queue_read after successfully calling ReadFile, or in * uv__pipe_queue_read after successfully calling ReadFile, or in
* uv_process_pipe_shutdown_req if a read is pending, and we always * uv__process_pipe_shutdown_req if a read is pending, and we always
* immediately stop the timer in uv_process_pipe_read_req. */ * immediately stop the timer in uv__process_pipe_read_req. */
assert(pipe->flags & UV_HANDLE_READ_PENDING); assert(pipe->flags & UV_HANDLE_READ_PENDING);
/* If there are many packets coming off the iocp then the timer callback may /* If there are many packets coming off the iocp then the timer callback may
@@ -2254,7 +2249,7 @@ static void eof_timer_cb(uv_timer_t* timer) {
/* Report the eof and update flags. This will get reported even if the user /* Report the eof and update flags. This will get reported even if the user
* stopped reading in the meantime. TODO: is that okay? */ * stopped reading in the meantime. TODO: is that okay? */
uv_pipe_read_eof(loop, pipe, uv_null_buf_); uv__pipe_read_eof(loop, pipe, uv_null_buf_);
} }
@@ -2280,10 +2275,16 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
IO_STATUS_BLOCK io_status; IO_STATUS_BLOCK io_status;
FILE_ACCESS_INFORMATION access; FILE_ACCESS_INFORMATION access;
DWORD duplex_flags = 0; DWORD duplex_flags = 0;
int err;
if (os_handle == INVALID_HANDLE_VALUE) if (os_handle == INVALID_HANDLE_VALUE)
return UV_EBADF; 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(); uv__once_init();
/* In order to avoid closing a stdio file descriptor 0-2, duplicate the /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
* underlying OS handle and forget about the original fd. * 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, FALSE,
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS))
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
assert(os_handle != INVALID_HANDLE_VALUE);
file = -1; file = -1;
} }
@@ -2327,17 +2329,17 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
if (access.AccessFlags & FILE_READ_DATA) if (access.AccessFlags & FILE_READ_DATA)
duplex_flags |= UV_HANDLE_READABLE; duplex_flags |= UV_HANDLE_READABLE;
if (os_handle == INVALID_HANDLE_VALUE || err = uv__set_pipe_handle(pipe->loop,
uv_set_pipe_handle(pipe->loop, pipe,
pipe, os_handle,
os_handle, file,
file, duplex_flags);
duplex_flags) == -1) { if (err) {
return UV_EINVAL; if (file == -1)
CloseHandle(os_handle);
return err;
} }
uv_pipe_connection_init(pipe);
if (pipe->ipc) { if (pipe->ipc) {
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); 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(); uv__once_init();
name_info = NULL; 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) { if (handle->handle == INVALID_HANDLE_VALUE) {
*size = 0; *size = 0;
return UV_EINVAL; 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) if (handle->handle != INVALID_HANDLE_VALUE)
return uv__pipe_getname(handle, buffer, size); 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; return UV_EBADF;
} }

View File

@@ -34,7 +34,9 @@ static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
{0xf9eab0c0, 0x26d4, 0x11d0, {0xf9eab0c0, 0x26d4, 0x11d0,
{0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
{0x9fc48064, 0x7298, 0x43e4, {0x9fc48064, 0x7298, 0x43e4,
{0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}},
{0xa00943d9, 0x9c2e, 0x4633,
{0x9b, 0x59, 0x00, 0x57, 0xa3, 0x16, 0x09, 0x94}}
}; };
typedef struct uv_single_fd_set_s { typedef struct uv_single_fd_set_s {
@@ -122,14 +124,14 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped); memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
result = uv_msafd_poll((SOCKET) handle->peer_socket, result = uv__msafd_poll((SOCKET) handle->peer_socket,
afd_poll_info, afd_poll_info,
afd_poll_info, afd_poll_info,
&req->u.io.overlapped); &req->u.io.overlapped);
if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
/* Queue this req, reporting an error. */ /* Queue this req, reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
} }
} }
@@ -195,7 +197,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
} else if ((handle->flags & UV_HANDLE_CLOSING) && } else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 && handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) { handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
} }
@@ -357,7 +359,7 @@ static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
WT_EXECUTELONGFUNCTION)) { WT_EXECUTELONGFUNCTION)) {
/* Make this req pending, reporting an error. */ /* Make this req pending, reporting an error. */
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
} }
} }
@@ -400,7 +402,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
} else if ((handle->flags & UV_HANDLE_CLOSING) && } else if ((handle->flags & UV_HANDLE_CLOSING) &&
handle->submitted_events_1 == 0 && handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) { handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
} }
@@ -524,7 +526,7 @@ int uv_poll_stop(uv_poll_t* handle) {
} }
void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { void uv__process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
uv__fast_poll_process_poll_req(loop, handle, req); uv__fast_poll_process_poll_req(loop, handle, req);
} else { } else {
@@ -533,7 +535,7 @@ void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
} }
int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { int uv__poll_close(uv_loop_t* loop, uv_poll_t* handle) {
AFD_POLL_INFO afd_poll_info; AFD_POLL_INFO afd_poll_info;
DWORD error; DWORD error;
int result; int result;
@@ -543,7 +545,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
if (handle->submitted_events_1 == 0 && if (handle->submitted_events_1 == 0 &&
handle->submitted_events_2 == 0) { handle->submitted_events_2 == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
return 0; return 0;
} }
@@ -559,10 +561,10 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
afd_poll_info.Handles[0].Status = 0; afd_poll_info.Handles[0].Status = 0;
afd_poll_info.Handles[0].Events = AFD_POLL_ALL; afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
result = uv_msafd_poll(handle->socket, result = uv__msafd_poll(handle->socket,
&afd_poll_info, &afd_poll_info,
uv__get_afd_poll_info_dummy(), uv__get_afd_poll_info_dummy(),
uv__get_overlapped_dummy()); uv__get_overlapped_dummy());
if (result == SOCKET_ERROR) { if (result == SOCKET_ERROR) {
error = WSAGetLastError(); error = WSAGetLastError();
@@ -574,7 +576,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
} }
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { void uv__poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING); assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));

View File

@@ -105,7 +105,7 @@ static void uv__init_global_job_handle(void) {
} }
static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { static int uv__utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
int ws_len, r; int ws_len, r;
WCHAR* ws; WCHAR* ws;
@@ -137,7 +137,7 @@ static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
} }
static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS); uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
handle->exit_cb = NULL; handle->exit_cb = NULL;
handle->pid = 0; handle->pid = 0;
@@ -864,7 +864,7 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
/* Called on main thread after a child process has exited. */ /* Called on main thread after a child process has exited. */
void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { void uv__process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
int64_t exit_code; int64_t exit_code;
DWORD status; DWORD status;
@@ -874,7 +874,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
/* If we're closing, don't call the exit callback. Just schedule a close /* If we're closing, don't call the exit callback. Just schedule a close
* callback now. */ * callback now. */
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
return; return;
} }
@@ -902,7 +902,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
} }
void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { void uv__process_close(uv_loop_t* loop, uv_process_t* handle) {
uv__handle_closing(handle); uv__handle_closing(handle);
if (handle->wait_handle != INVALID_HANDLE_VALUE) { if (handle->wait_handle != INVALID_HANDLE_VALUE) {
@@ -918,12 +918,12 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
} }
if (!handle->exit_cb_pending) { if (!handle->exit_cb_pending) {
uv_want_endgame(loop, (uv_handle_t*)handle); uv__want_endgame(loop, (uv_handle_t*)handle);
} }
} }
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { void uv__process_endgame(uv_loop_t* loop, uv_process_t* handle) {
assert(!handle->exit_cb_pending); assert(!handle->exit_cb_pending);
assert(handle->flags & UV_HANDLE_CLOSING); assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -948,7 +948,7 @@ int uv_spawn(uv_loop_t* loop,
PROCESS_INFORMATION info; PROCESS_INFORMATION info;
DWORD process_flags; DWORD process_flags;
uv_process_init(loop, process); uv__process_init(loop, process);
process->exit_cb = options->exit_cb; process->exit_cb = options->exit_cb;
if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
@@ -975,7 +975,7 @@ int uv_spawn(uv_loop_t* loop,
UV_PROCESS_WINDOWS_HIDE_GUI | UV_PROCESS_WINDOWS_HIDE_GUI |
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
err = uv_utf8_to_utf16_alloc(options->file, &application); err = uv__utf8_to_utf16_alloc(options->file, &application);
if (err) if (err)
goto done; goto done;
@@ -994,7 +994,7 @@ int uv_spawn(uv_loop_t* loop,
if (options->cwd) { if (options->cwd) {
/* Explicit cwd */ /* Explicit cwd */
err = uv_utf8_to_utf16_alloc(options->cwd, &cwd); err = uv__utf8_to_utf16_alloc(options->cwd, &cwd);
if (err) if (err)
goto done; goto done;

View File

@@ -50,7 +50,7 @@
(pRtlNtStatusToDosError(GET_REQ_STATUS((req)))) (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
#define GET_REQ_SOCK_ERROR(req) \ #define GET_REQ_SOCK_ERROR(req) \
(uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req)))) (uv__ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
#define REGISTER_HANDLE_REQ(loop, handle, req) \ #define REGISTER_HANDLE_REQ(loop, handle, req) \
@@ -82,12 +82,12 @@
} }
INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) { INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) {
return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped); return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
} }
INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) { INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
req->next_req = NULL; req->next_req = NULL;
if (loop->pending_reqs_tail) { if (loop->pending_reqs_tail) {
#ifdef _DEBUG #ifdef _DEBUG
@@ -115,19 +115,19 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
do { \ do { \
switch (((uv_handle_t*) (req)->handle_at)->type) { \ switch (((uv_handle_t*) (req)->handle_at)->type) { \
case UV_TCP: \ case UV_TCP: \
uv_process_tcp_##method##_req(loop, \ uv__process_tcp_##method##_req(loop, \
(uv_tcp_t*) ((req)->handle_at), \ (uv_tcp_t*) ((req)->handle_at), \
req); \ req); \
break; \ break; \
\ \
case UV_NAMED_PIPE: \ case UV_NAMED_PIPE: \
uv_process_pipe_##method##_req(loop, \ uv__process_pipe_##method##_req(loop, \
(uv_pipe_t*) ((req)->handle_at), \ (uv_pipe_t*) ((req)->handle_at), \
req); \ req); \
break; \ break; \
\ \
case UV_TTY: \ case UV_TTY: \
uv_process_tty_##method##_req(loop, \ uv__process_tty_##method##_req(loop, \
(uv_tty_t*) ((req)->handle_at), \ (uv_tty_t*) ((req)->handle_at), \
req); \ req); \
break; \ break; \
@@ -138,13 +138,13 @@ INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
} while (0) } 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* req;
uv_req_t* first; uv_req_t* first;
uv_req_t* next; uv_req_t* next;
if (loop->pending_reqs_tail == NULL) if (loop->pending_reqs_tail == NULL)
return 0; return;
first = loop->pending_reqs_tail->next_req; first = loop->pending_reqs_tail->next_req;
next = first; next = first;
@@ -172,50 +172,43 @@ INLINE static int uv_process_reqs(uv_loop_t* loop) {
break; break;
case UV_SHUTDOWN: case UV_SHUTDOWN:
/* Tcp shutdown requests don't come here. */ DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle);
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);
break; break;
case UV_UDP_RECV: case UV_UDP_RECV:
uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req); uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
break; break;
case UV_UDP_SEND: case UV_UDP_SEND:
uv_process_udp_send_req(loop, uv__process_udp_send_req(loop,
((uv_udp_send_t*) req)->handle, ((uv_udp_send_t*) req)->handle,
(uv_udp_send_t*) req); (uv_udp_send_t*) req);
break; break;
case UV_WAKEUP: case UV_WAKEUP:
uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
break; break;
case UV_SIGNAL_REQ: case UV_SIGNAL_REQ:
uv_process_signal_req(loop, (uv_signal_t*) req->data, req); uv__process_signal_req(loop, (uv_signal_t*) req->data, req);
break; break;
case UV_POLL_REQ: case UV_POLL_REQ:
uv_process_poll_req(loop, (uv_poll_t*) req->data, req); uv__process_poll_req(loop, (uv_poll_t*) req->data, req);
break; break;
case UV_PROCESS_EXIT: case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data); uv__process_proc_exit(loop, (uv_process_t*) req->data);
break; break;
case UV_FS_EVENT_REQ: case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break; break;
default: default:
assert(0); assert(0);
} }
} }
return 1;
} }
#endif /* UV_WIN_REQ_INL_H_ */ #endif /* UV_WIN_REQ_INL_H_ */

View File

@@ -39,7 +39,7 @@ int uv__signal_start(uv_signal_t* handle,
int signum, int signum,
int oneshot); int oneshot);
void uv_signals_init(void) { void uv__signals_init(void) {
InitializeCriticalSection(&uv__signal_lock); InitializeCriticalSection(&uv__signal_lock);
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE)) if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
abort(); abort();
@@ -231,7 +231,7 @@ int uv__signal_start(uv_signal_t* handle,
} }
void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, void uv__process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
uv_req_t* req) { uv_req_t* req) {
long dispatched_signum; long dispatched_signum;
@@ -254,22 +254,22 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
if (handle->flags & UV_HANDLE_CLOSING) { if (handle->flags & UV_HANDLE_CLOSING) {
/* When it is closing, it must be stopped at this point. */ /* When it is closing, it must be stopped at this point. */
assert(handle->signum == 0); assert(handle->signum == 0);
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
} }
void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) { void uv__signal_close(uv_loop_t* loop, uv_signal_t* handle) {
uv_signal_stop(handle); uv_signal_stop(handle);
uv__handle_closing(handle); uv__handle_closing(handle);
if (handle->pending_signum == 0) { if (handle->pending_signum == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
} }
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) { void uv__signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
assert(handle->flags & UV_HANDLE_CLOSING); assert(handle->flags & UV_HANDLE_CLOSING);
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));

View File

@@ -30,9 +30,9 @@
#include "req-inl.h" #include "req-inl.h"
INLINE static void uv_stream_init(uv_loop_t* loop, INLINE static void uv__stream_init(uv_loop_t* loop,
uv_stream_t* handle, uv_stream_t* handle,
uv_handle_type type) { uv_handle_type type) {
uv__handle_init(loop, (uv_handle_t*) handle, type); uv__handle_init(loop, (uv_handle_t*) handle, type);
handle->write_queue_size = 0; handle->write_queue_size = 0;
handle->activecnt = 0; handle->activecnt = 0;
@@ -46,7 +46,7 @@ INLINE static void uv_stream_init(uv_loop_t* loop,
} }
INLINE static void uv_connection_init(uv_stream_t* handle) { INLINE static void uv__connection_init(uv_stream_t* handle) {
handle->flags |= UV_HANDLE_CONNECTION; handle->flags |= UV_HANDLE_CONNECTION;
} }

View File

@@ -29,14 +29,16 @@
int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
int err; int err;
if (uv__is_closing(stream)) {
return UV_EINVAL;
}
err = ERROR_INVALID_PARAMETER; err = ERROR_INVALID_PARAMETER;
switch (stream->type) { switch (stream->type) {
case UV_TCP: case UV_TCP:
err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); err = uv__tcp_listen((uv_tcp_t*)stream, backlog, cb);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); err = uv__pipe_listen((uv_pipe_t*)stream, backlog, cb);
break; break;
default: default:
assert(0); assert(0);
@@ -52,10 +54,10 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
err = ERROR_INVALID_PARAMETER; err = ERROR_INVALID_PARAMETER;
switch (server->type) { switch (server->type) {
case UV_TCP: case UV_TCP:
err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client); err = uv__tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
err = uv_pipe_accept((uv_pipe_t*)server, client); err = uv__pipe_accept((uv_pipe_t*)server, client);
break; break;
default: default:
assert(0); assert(0);
@@ -73,13 +75,13 @@ int uv__read_start(uv_stream_t* handle,
err = ERROR_INVALID_PARAMETER; err = ERROR_INVALID_PARAMETER;
switch (handle->type) { switch (handle->type) {
case UV_TCP: case UV_TCP:
err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb); err = uv__tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb); err = uv__pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
break; break;
case UV_TTY: case UV_TTY:
err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb); err = uv__tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
break; break;
default: default:
assert(0); assert(0);
@@ -97,7 +99,7 @@ int uv_read_stop(uv_stream_t* handle) {
err = 0; err = 0;
if (handle->type == UV_TTY) { if (handle->type == UV_TTY) {
err = uv_tty_read_stop((uv_tty_t*) handle); err = uv__tty_read_stop((uv_tty_t*) handle);
} else if (handle->type == UV_NAMED_PIPE) { } else if (handle->type == UV_NAMED_PIPE) {
uv__pipe_read_stop((uv_pipe_t*) handle); uv__pipe_read_stop((uv_pipe_t*) handle);
} else { } else {
@@ -124,14 +126,14 @@ int uv_write(uv_write_t* req,
err = ERROR_INVALID_PARAMETER; err = ERROR_INVALID_PARAMETER;
switch (handle->type) { switch (handle->type) {
case UV_TCP: case UV_TCP:
err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); err = uv__tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
break; break;
case UV_NAMED_PIPE: case UV_NAMED_PIPE:
err = uv__pipe_write( err = uv__pipe_write(
loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb); loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
break; break;
case UV_TTY: case UV_TTY:
err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); err = uv__tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
break; break;
default: default:
assert(0); assert(0);
@@ -217,7 +219,12 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
handle->reqs_pending++; handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); 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; return 0;
} }

View File

@@ -78,11 +78,11 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign
} }
static int uv_tcp_set_socket(uv_loop_t* loop, static int uv__tcp_set_socket(uv_loop_t* loop,
uv_tcp_t* handle, uv_tcp_t* handle,
SOCKET socket, SOCKET socket,
int family, int family,
int imported) { int imported) {
DWORD yes = 1; DWORD yes = 1;
int non_ifs_lsp; int non_ifs_lsp;
int err; int err;
@@ -162,7 +162,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
if (flags & ~0xFF) if (flags & ~0xFF)
return UV_EINVAL; return UV_EINVAL;
uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP); uv__stream_init(loop, (uv_stream_t*) handle, UV_TCP);
handle->tcp.serv.accept_reqs = NULL; handle->tcp.serv.accept_reqs = NULL;
handle->tcp.serv.pending_accepts = NULL; handle->tcp.serv.pending_accepts = NULL;
handle->socket = INVALID_SOCKET; handle->socket = INVALID_SOCKET;
@@ -173,7 +173,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
handle->delayed_error = 0; handle->delayed_error = 0;
/* If anything fails beyond this point we need to remove the handle from /* If anything fails beyond this point we need to remove the handle from
* the handle queue, since it was added by uv__handle_init in uv_stream_init. * the handle queue, since it was added by uv__handle_init in uv__stream_init.
*/ */
if (domain != AF_UNSPEC) { if (domain != AF_UNSPEC) {
@@ -187,7 +187,7 @@ int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0); err = uv__tcp_set_socket(handle->loop, handle, sock, domain, 0);
if (err) { if (err) {
closesocket(sock); closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue); QUEUE_REMOVE(&handle->handle_queue);
@@ -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; 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; unsigned int i;
uv_tcp_accept_t* req; uv_tcp_accept_t* req;
if (handle->flags & UV_HANDLE_CONNECTION && assert(handle->flags & UV_HANDLE_CLOSING);
handle->stream.conn.shutdown_req != NULL && assert(handle->reqs_pending == 0);
handle->stream.conn.write_reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED));
assert(handle->socket == INVALID_SOCKET);
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
err = 0; for (i = 0; i < uv_simultaneous_server_accepts; i++) {
if (handle->flags & UV_HANDLE_CLOSING) { req = &handle->tcp.serv.accept_reqs[i];
err = ERROR_OPERATION_ABORTED; if (req->wait_handle != INVALID_HANDLE_VALUE) {
} else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { UnregisterWait(req->wait_handle);
err = WSAGetLastError(); req->wait_handle = INVALID_HANDLE_VALUE;
} }
if (req->event_handle != NULL) {
if (handle->stream.conn.shutdown_req->cb) { CloseHandle(req->event_handle);
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, req->event_handle = NULL;
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;
}
} }
} }
uv__free(handle->tcp.serv.accept_reqs);
handle->tcp.serv.accept_reqs = NULL;
} }
if (handle->flags & UV_HANDLE_CONNECTION && uv__free(handle->tcp.serv.accept_reqs);
handle->flags & UV_HANDLE_EMULATE_IOCP) { handle->tcp.serv.accept_reqs = NULL;
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--;
} }
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--;
} }
@@ -286,10 +289,10 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
* See issue #1360. * See issue #1360.
* *
*/ */
static int uv_tcp_try_bind(uv_tcp_t* handle, static int uv__tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int addrlen, unsigned int addrlen,
unsigned int flags) { unsigned int flags) {
DWORD err; DWORD err;
int r; int r;
@@ -305,7 +308,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
return WSAGetLastError(); return WSAGetLastError();
} }
err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0); err = uv__tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
if (err) { if (err) {
closesocket(sock); closesocket(sock);
return err; return err;
@@ -385,7 +388,7 @@ static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
} }
static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;
BOOL success; BOOL success;
DWORD bytes; DWORD bytes;
@@ -406,7 +409,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
accept_socket = socket(family, SOCK_STREAM, 0); accept_socket = socket(family, SOCK_STREAM, 0);
if (accept_socket == INVALID_SOCKET) { if (accept_socket == INVALID_SOCKET) {
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
handle->reqs_pending++; handle->reqs_pending++;
return; return;
} }
@@ -414,7 +417,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
/* Make the socket non-inheritable */ /* Make the socket non-inheritable */
if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
handle->reqs_pending++; handle->reqs_pending++;
closesocket(accept_socket); closesocket(accept_socket);
return; return;
@@ -440,7 +443,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
/* Process the req without IOCP. */ /* Process the req without IOCP. */
req->accept_socket = accept_socket; req->accept_socket = accept_socket;
handle->reqs_pending++; handle->reqs_pending++;
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) { } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
/* The req will be processed with IOCP. */ /* The req will be processed with IOCP. */
req->accept_socket = accept_socket; req->accept_socket = accept_socket;
@@ -451,12 +454,12 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
req->event_handle, post_completion, (void*) req, req->event_handle, post_completion, (void*) req,
INFINITE, WT_EXECUTEINWAITTHREAD)) { INFINITE, WT_EXECUTEINWAITTHREAD)) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
} else { } else {
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
handle->reqs_pending++; handle->reqs_pending++;
/* Destroy the preallocated client socket. */ /* Destroy the preallocated client socket. */
closesocket(accept_socket); closesocket(accept_socket);
@@ -469,7 +472,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
} }
static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
uv_read_t* req; uv_read_t* req;
uv_buf_t buf; uv_buf_t buf;
int result; int result;
@@ -524,7 +527,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
/* Process the req without IOCP. */ /* Process the req without IOCP. */
req->u.io.overlapped.InternalHigh = bytes; req->u.io.overlapped.InternalHigh = bytes;
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */ /* The req will be processed with IOCP. */
if (handle->flags & UV_HANDLE_EMULATE_IOCP && if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
@@ -533,12 +536,12 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
req->event_handle, post_completion, (void*) req, req->event_handle, post_completion, (void*) req,
INFINITE, WT_EXECUTEINWAITTHREAD)) { INFINITE, WT_EXECUTEINWAITTHREAD)) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
} else { } else {
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
} }
@@ -558,7 +561,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
} }
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
unsigned int i, simultaneous_accepts; unsigned int i, simultaneous_accepts;
uv_tcp_accept_t* req; uv_tcp_accept_t* req;
int err; int err;
@@ -578,10 +581,10 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
} }
if (!(handle->flags & UV_HANDLE_BOUND)) { if (!(handle->flags & UV_HANDLE_BOUND)) {
err = uv_tcp_try_bind(handle, err = uv__tcp_try_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_, (const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_), sizeof(uv_addr_ip4_any_),
0); 0);
if (err) if (err)
return err; return err;
if (handle->delayed_error) if (handle->delayed_error)
@@ -589,7 +592,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
} }
if (!handle->tcp.serv.func_acceptex) { if (!handle->tcp.serv.func_acceptex) {
if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
return WSAEAFNOSUPPORT; return WSAEAFNOSUPPORT;
} }
} }
@@ -630,7 +633,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
req->event_handle = NULL; req->event_handle = NULL;
} }
uv_tcp_queue_accept(handle, req); uv__tcp_queue_accept(handle, req);
} }
/* Initialize other unused requests too, because uv_tcp_endgame doesn't /* Initialize other unused requests too, because uv_tcp_endgame doesn't
@@ -650,7 +653,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
} }
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
uv_loop_t* loop = server->loop; uv_loop_t* loop = server->loop;
int err = 0; int err = 0;
int family; int family;
@@ -672,7 +675,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
family = AF_INET; family = AF_INET;
} }
err = uv_tcp_set_socket(client->loop, err = uv__tcp_set_socket(client->loop,
client, client,
req->accept_socket, req->accept_socket,
family, family,
@@ -680,7 +683,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
if (err) { if (err) {
closesocket(req->accept_socket); closesocket(req->accept_socket);
} else { } else {
uv_connection_init((uv_stream_t*) client); uv__connection_init((uv_stream_t*) client);
/* AcceptEx() implicitly binds the accepted socket. */ /* AcceptEx() implicitly binds the accepted socket. */
client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
} }
@@ -693,7 +696,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
if (!(server->flags & UV_HANDLE_CLOSING)) { if (!(server->flags & UV_HANDLE_CLOSING)) {
/* Check if we're in a middle of changing the number of pending accepts. */ /* Check if we're in a middle of changing the number of pending accepts. */
if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
uv_tcp_queue_accept(server, req); uv__tcp_queue_accept(server, req);
} else { } else {
/* We better be switching to a single pending accept. */ /* We better be switching to a single pending accept. */
assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT); assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
@@ -706,7 +709,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
* All previously queued accept requests are now processed. * All previously queued accept requests are now processed.
* We now switch to queueing just a single accept. * We now switch to queueing just a single accept.
*/ */
uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]); uv__tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING; server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
} }
@@ -719,7 +722,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
} }
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, int uv__tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) { uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;
@@ -738,7 +741,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
uv_fatal_error(GetLastError(), "CreateEvent"); uv_fatal_error(GetLastError(), "CreateEvent");
} }
} }
uv_tcp_queue_read(loop, handle); uv__tcp_queue_read(loop, handle);
} }
return 0; return 0;
@@ -779,7 +782,7 @@ static int uv__is_fast_loopback_fail_supported(void) {
return os_info.dwBuildNumber >= 16299; return os_info.dwBuildNumber >= 16299;
} }
static int uv_tcp_try_connect(uv_connect_t* req, static int uv__tcp_try_connect(uv_connect_t* req,
uv_tcp_t* handle, uv_tcp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int addrlen, unsigned int addrlen,
@@ -807,7 +810,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
} else { } else {
abort(); abort();
} }
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0); err = uv__tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return err; return err;
if (handle->delayed_error != 0) if (handle->delayed_error != 0)
@@ -815,7 +818,7 @@ static int uv_tcp_try_connect(uv_connect_t* req,
} }
if (!handle->tcp.conn.func_connectex) { if (!handle->tcp.conn.func_connectex) {
if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
return WSAEAFNOSUPPORT; return WSAEAFNOSUPPORT;
} }
} }
@@ -850,7 +853,7 @@ out:
/* Process the req without IOCP. */ /* Process the req without IOCP. */
handle->reqs_pending++; handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
return 0; return 0;
} }
@@ -866,7 +869,7 @@ out:
/* Process the req without IOCP. */ /* Process the req without IOCP. */
handle->reqs_pending++; handle->reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(success)) { } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
/* The req will be processed with IOCP. */ /* The req will be processed with IOCP. */
handle->reqs_pending++; handle->reqs_pending++;
@@ -903,7 +906,7 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
} }
int uv_tcp_write(uv_loop_t* loop, int uv__tcp_write(uv_loop_t* loop,
uv_write_t* req, uv_write_t* req,
uv_tcp_t* handle, uv_tcp_t* handle,
const uv_buf_t bufs[], const uv_buf_t bufs[],
@@ -941,7 +944,7 @@ int uv_tcp_write(uv_loop_t* loop,
handle->reqs_pending++; handle->reqs_pending++;
handle->stream.conn.write_reqs_pending++; handle->stream.conn.write_reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
@@ -954,7 +957,7 @@ int uv_tcp_write(uv_loop_t* loop,
req->event_handle, post_write_completion, (void*) req, req->event_handle, post_write_completion, (void*) req,
INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
} else { } else {
/* Send failed due to an error, report it later */ /* Send failed due to an error, report it later */
@@ -963,7 +966,7 @@ int uv_tcp_write(uv_loop_t* loop,
handle->stream.conn.write_reqs_pending++; handle->stream.conn.write_reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
} }
return 0; return 0;
@@ -994,7 +997,7 @@ int uv__tcp_try_write(uv_tcp_t* handle,
} }
void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* req) { uv_req_t* req) {
DWORD bytes, flags, err; DWORD bytes, flags, err;
uv_buf_t buf; uv_buf_t buf;
@@ -1115,7 +1118,7 @@ done:
/* Post another read if still reading and not closing. */ /* Post another read if still reading and not closing. */
if ((handle->flags & UV_HANDLE_READING) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tcp_queue_read(loop, handle); uv__tcp_queue_read(loop, handle);
} }
} }
@@ -1123,7 +1126,7 @@ done:
} }
void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_write_t* req) { uv_write_t* req) {
int err; int err;
@@ -1160,16 +1163,17 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
closesocket(handle->socket); closesocket(handle->socket);
handle->socket = INVALID_SOCKET; handle->socket = INVALID_SOCKET;
} }
if (handle->stream.conn.shutdown_req != NULL) { if (handle->flags & UV_HANDLE_SHUTTING)
uv_want_endgame(loop, (uv_handle_t*)handle); uv__process_tcp_shutdown_req(loop,
} handle,
handle->stream.conn.shutdown_req);
} }
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_req_t* raw_req) { uv_req_t* raw_req) {
uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req; uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
int err; int err;
@@ -1209,7 +1213,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
closesocket(req->accept_socket); closesocket(req->accept_socket);
req->accept_socket = INVALID_SOCKET; req->accept_socket = INVALID_SOCKET;
if (handle->flags & UV_HANDLE_LISTENING) { if (handle->flags & UV_HANDLE_LISTENING) {
uv_tcp_queue_accept(handle, req); uv__tcp_queue_accept(handle, req);
} }
} }
@@ -1217,7 +1221,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
} }
void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
uv_connect_t* req) { uv_connect_t* req) {
int err; int err;
@@ -1242,7 +1246,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
SO_UPDATE_CONNECT_CONTEXT, SO_UPDATE_CONNECT_CONTEXT,
NULL, NULL,
0) == 0) { 0) == 0) {
uv_connection_init((uv_stream_t*)handle); uv__connection_init((uv_stream_t*)handle);
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
loop->active_tcp_streams++; loop->active_tcp_streams++;
} else { } else {
@@ -1312,7 +1316,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
return WSAGetLastError(); return WSAGetLastError();
} }
err = uv_tcp_set_socket( err = uv__tcp_set_socket(
tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1); tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
if (err) { if (err) {
closesocket(socket); closesocket(socket);
@@ -1323,7 +1327,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
uv_connection_init((uv_stream_t*)tcp); uv__connection_init((uv_stream_t*)tcp);
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
} }
@@ -1404,14 +1408,14 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
} }
static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) { static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
SOCKET socket; SOCKET socket;
int non_ifs_lsp; int non_ifs_lsp;
int reading; int reading;
int writing; int writing;
socket = tcp->socket; socket = tcp->socket;
reading = tcp->flags & UV_HANDLE_READING; reading = tcp->flags & UV_HANDLE_READ_PENDING;
writing = tcp->stream.conn.write_reqs_pending > 0; writing = tcp->stream.conn.write_reqs_pending > 0;
if (!reading && !writing) if (!reading && !writing)
return; return;
@@ -1456,12 +1460,12 @@ static void uv_tcp_try_cancel_reqs(uv_tcp_t* tcp) {
} }
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { void uv__tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
if (tcp->flags & UV_HANDLE_CONNECTION) { if (tcp->flags & UV_HANDLE_CONNECTION) {
uv_tcp_try_cancel_reqs(tcp);
if (tcp->flags & UV_HANDLE_READING) { if (tcp->flags & UV_HANDLE_READING) {
uv_read_stop((uv_stream_t*) tcp); uv_read_stop((uv_stream_t*) tcp);
} }
uv__tcp_try_cancel_reqs(tcp);
} else { } else {
if (tcp->tcp.serv.accept_reqs != NULL) { if (tcp->tcp.serv.accept_reqs != NULL) {
/* First close the incoming sockets to cancel the accept operations before /* 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); 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 /* 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 * cause Win32 to send an RST packet. Try to avoid that for writes, if
* possibly applicable, by waiting to process the completion notifications * 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->socket = INVALID_SOCKET;
} }
tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (tcp->reqs_pending == 0)
uv__handle_closing(tcp); uv__want_endgame(loop, (uv_handle_t*) tcp);
if (tcp->reqs_pending == 0) {
uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
}
} }
@@ -1520,7 +1523,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
err = uv_tcp_set_socket(handle->loop, err = uv__tcp_set_socket(handle->loop,
handle, handle,
sock, sock,
protocol_info.iAddressFamily, protocol_info.iAddressFamily,
@@ -1537,7 +1540,7 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
saddr_len = sizeof(saddr); saddr_len = sizeof(saddr);
if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) { if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
/* Socket is already connected. */ /* Socket is already connected. */
uv_connection_init((uv_stream_t*) handle); uv__connection_init((uv_stream_t*) handle);
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
} }
} }
@@ -1555,7 +1558,7 @@ int uv__tcp_bind(uv_tcp_t* handle,
unsigned int flags) { unsigned int flags) {
int err; int err;
err = uv_tcp_try_bind(handle, addr, addrlen, flags); err = uv__tcp_try_bind(handle, addr, addrlen, flags);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -1573,7 +1576,7 @@ int uv__tcp_connect(uv_connect_t* req,
uv_connect_cb cb) { uv_connect_cb cb) {
int err; int err;
err = uv_tcp_try_connect(req, handle, addr, addrlen, cb); err = uv__tcp_try_connect(req, handle, addr, addrlen, cb);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -1634,7 +1637,7 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f
goto wsaerror; goto wsaerror;
if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0)) if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0))
goto error; goto error;
if (!uv_get_acceptex_function(server, &func_acceptex)) { if (!uv__get_acceptex_function(server, &func_acceptex)) {
err = WSAEAFNOSUPPORT; err = WSAEAFNOSUPPORT;
goto cleanup; goto cleanup;
} }

View File

@@ -182,8 +182,9 @@ int uv_thread_create_ex(uv_thread_t* tid,
uv_thread_t uv_thread_self(void) { uv_thread_t uv_thread_self(void) {
uv_thread_t key;
uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key); uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
uv_thread_t key = uv_key_get(&uv__current_thread_key); key = uv_key_get(&uv__current_thread_key);
if (key == NULL) { if (key == NULL) {
/* If the thread wasn't started by uv_thread_create (such as the main /* If the thread wasn't started by uv_thread_create (such as the main
* thread), we assign an id to it now. */ * thread), we assign an id to it now. */

View File

@@ -67,10 +67,10 @@
#define CURSOR_SIZE_SMALL 25 #define CURSOR_SIZE_SMALL 25
#define CURSOR_SIZE_LARGE 100 #define CURSOR_SIZE_LARGE 100
static void uv_tty_capture_initial_style( static void uv__tty_capture_initial_style(
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
CONSOLE_CURSOR_INFO* cursor_info); CONSOLE_CURSOR_INFO* cursor_info);
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
static int uv__cancel_read_console(uv_tty_t* handle); static int uv__cancel_read_console(uv_tty_t* handle);
@@ -163,7 +163,7 @@ static BOOL uv__need_check_vterm_state = TRUE;
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED; static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
static void uv__determine_vterm_state(HANDLE handle); static void uv__determine_vterm_state(HANDLE handle);
void uv_console_init(void) { void uv__console_init(void) {
if (uv_sem_init(&uv_tty_output_lock, 1)) if (uv_sem_init(&uv_tty_output_lock, 1))
abort(); abort();
uv__tty_console_handle = CreateFileW(L"CONOUT$", uv__tty_console_handle = CreateFileW(L"CONOUT$",
@@ -238,16 +238,16 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
uv__determine_vterm_state(handle); uv__determine_vterm_state(handle);
/* Remember the original console text attributes and cursor info. */ /* Remember the original console text attributes and cursor info. */
uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info); uv__tty_capture_initial_style(&screen_buffer_info, &cursor_info);
uv_tty_update_virtual_window(&screen_buffer_info); uv__tty_update_virtual_window(&screen_buffer_info);
uv_sem_post(&uv_tty_output_lock); uv_sem_post(&uv_tty_output_lock);
} }
uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY); uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
uv_connection_init((uv_stream_t*) tty); uv__connection_init((uv_stream_t*) tty);
tty->handle = handle; tty->handle = handle;
tty->u.fd = fd; tty->u.fd = fd;
@@ -289,7 +289,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
/* Set the default console text attributes based on how the console was /* Set the default console text attributes based on how the console was
* configured when libuv started. * configured when libuv started.
*/ */
static void uv_tty_capture_initial_style( static void uv__tty_capture_initial_style(
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info, CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
CONSOLE_CURSOR_INFO* cursor_info) { CONSOLE_CURSOR_INFO* cursor_info) {
static int style_captured = 0; static int style_captured = 0;
@@ -380,7 +380,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
was_reading = 1; was_reading = 1;
alloc_cb = tty->alloc_cb; alloc_cb = tty->alloc_cb;
read_cb = tty->read_cb; read_cb = tty->read_cb;
err = uv_tty_read_stop(tty); err = uv__tty_read_stop(tty);
if (err) { if (err) {
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
@@ -404,7 +404,7 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
/* If we just stopped reading, restart. */ /* If we just stopped reading, restart. */
if (was_reading) { if (was_reading) {
err = uv_tty_read_start(tty, alloc_cb, read_cb); err = uv__tty_read_start(tty, alloc_cb, read_cb);
if (err) { if (err) {
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
@@ -422,7 +422,7 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
} }
uv_sem_wait(&uv_tty_output_lock); uv_sem_wait(&uv_tty_output_lock);
uv_tty_update_virtual_window(&info); uv__tty_update_virtual_window(&info);
uv_sem_post(&uv_tty_output_lock); uv_sem_post(&uv_tty_output_lock);
*width = uv_tty_virtual_width; *width = uv_tty_virtual_width;
@@ -452,7 +452,7 @@ static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
} }
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
uv_read_t* req; uv_read_t* req;
BOOL r; BOOL r;
@@ -475,7 +475,7 @@ static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
if (!r) { if (!r) {
handle->tty.rd.read_raw_wait = NULL; handle->tty.rd.read_raw_wait = NULL;
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
@@ -579,7 +579,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
} }
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
uv_read_t* req; uv_read_t* req;
BOOL r; BOOL r;
@@ -611,7 +611,7 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
WT_EXECUTELONGFUNCTION); WT_EXECUTELONGFUNCTION);
if (!r) { if (!r) {
SET_REQ_ERROR(req, GetLastError()); SET_REQ_ERROR(req, GetLastError());
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} }
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
@@ -619,11 +619,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
} }
static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) { static void uv__tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
if (handle->flags & UV_HANDLE_TTY_RAW) { if (handle->flags & UV_HANDLE_TTY_RAW) {
uv_tty_queue_read_raw(loop, handle); uv__tty_queue_read_raw(loop, handle);
} else { } else {
uv_tty_queue_read_line(loop, handle); uv__tty_queue_read_line(loop, handle);
} }
} }
@@ -947,7 +947,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
/* Wait for more input events. */ /* Wait for more input events. */
if ((handle->flags & UV_HANDLE_READING) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tty_queue_read(loop, handle); uv__tty_queue_read(loop, handle);
} }
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
@@ -992,14 +992,14 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
/* Wait for more input events. */ /* Wait for more input events. */
if ((handle->flags & UV_HANDLE_READING) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_tty_queue_read(loop, handle); uv__tty_queue_read(loop, handle);
} }
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* req) { uv_req_t* req) {
assert(handle->type == UV_TTY); assert(handle->type == UV_TTY);
assert(handle->flags & UV_HANDLE_TTY_READABLE); assert(handle->flags & UV_HANDLE_TTY_READABLE);
@@ -1015,7 +1015,7 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
} }
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv__tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
uv_read_cb read_cb) { uv_read_cb read_cb) {
uv_loop_t* loop = handle->loop; uv_loop_t* loop = handle->loop;
@@ -1038,20 +1038,20 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
* Short-circuit if this could be the case. */ * Short-circuit if this could be the case. */
if (handle->tty.rd.last_key_len > 0) { if (handle->tty.rd.last_key_len > 0) {
SET_REQ_SUCCESS(&handle->read_req); SET_REQ_SUCCESS(&handle->read_req);
uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); uv__insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
/* Make sure no attempt is made to insert it again until it's handled. */ /* Make sure no attempt is made to insert it again until it's handled. */
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
handle->reqs_pending++; handle->reqs_pending++;
return 0; return 0;
} }
uv_tty_queue_read(loop, handle); uv__tty_queue_read(loop, handle);
return 0; return 0;
} }
int uv_tty_read_stop(uv_tty_t* handle) { int uv__tty_read_stop(uv_tty_t* handle) {
INPUT_RECORD record; INPUT_RECORD record;
DWORD written, err; DWORD written, err;
@@ -1137,7 +1137,7 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
} }
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { static void uv__tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
uv_tty_virtual_width = info->dwSize.X; uv_tty_virtual_width = info->dwSize.X;
uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1; uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
@@ -1160,12 +1160,12 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
} }
static COORD uv_tty_make_real_coord(uv_tty_t* handle, static COORD uv__tty_make_real_coord(uv_tty_t* handle,
CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y, CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
unsigned char y_relative) { unsigned char y_relative) {
COORD result; COORD result;
uv_tty_update_virtual_window(info); uv__tty_update_virtual_window(info);
/* Adjust y position */ /* Adjust y position */
if (y_relative) { if (y_relative) {
@@ -1197,7 +1197,7 @@ static COORD uv_tty_make_real_coord(uv_tty_t* handle,
} }
static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length, static int uv__tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
DWORD* error) { DWORD* error) {
DWORD written; DWORD written;
@@ -1218,7 +1218,7 @@ static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
} }
static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative, static int uv__tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
int y, unsigned char y_relative, DWORD* error) { int y, unsigned char y_relative, DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
COORD pos; COORD pos;
@@ -1232,7 +1232,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
*error = GetLastError(); *error = GetLastError();
} }
pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative); pos = uv__tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
if (!SetConsoleCursorPosition(handle->handle, pos)) { if (!SetConsoleCursorPosition(handle->handle, pos)) {
if (GetLastError() == ERROR_INVALID_PARAMETER) { if (GetLastError() == ERROR_INVALID_PARAMETER) {
@@ -1248,7 +1248,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
} }
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { static int uv__tty_reset(uv_tty_t* handle, DWORD* error) {
const COORD origin = {0, 0}; const COORD origin = {0, 0};
const WORD char_attrs = uv_tty_default_text_attributes; const WORD char_attrs = uv_tty_default_text_attributes;
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
@@ -1300,7 +1300,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
/* Move the virtual window up to the top. */ /* Move the virtual window up to the top. */
uv_tty_virtual_offset = 0; uv_tty_virtual_offset = 0;
uv_tty_update_virtual_window(&screen_buffer_info); uv__tty_update_virtual_window(&screen_buffer_info);
/* Reset the cursor size and the cursor state. */ /* Reset the cursor size and the cursor state. */
if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) { if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
@@ -1312,7 +1312,7 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
} }
static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, static int uv__tty_clear(uv_tty_t* handle, int dir, char entire_screen,
DWORD* error) { DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
COORD start, end; COORD start, end;
@@ -1341,7 +1341,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
x2r = 1; x2r = 1;
} else { } else {
/* Clear to end of row. We pretend the console is 65536 characters wide, /* Clear to end of row. We pretend the console is 65536 characters wide,
* uv_tty_make_real_coord will clip it to the actual console width. */ * uv__tty_make_real_coord will clip it to the actual console width. */
x2 = 0xffff; x2 = 0xffff;
x2r = 0; x2r = 0;
} }
@@ -1364,8 +1364,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
return -1; return -1;
} }
start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r); start = uv__tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r); end = uv__tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
count = (end.Y * info.dwSize.X + end.X) - count = (end.Y * info.dwSize.X + end.X) -
(start.Y * info.dwSize.X + start.X) + 1; (start.Y * info.dwSize.X + start.X) + 1;
@@ -1400,7 +1400,7 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
info.wAttributes |= bg >> 4; \ info.wAttributes |= bg >> 4; \
} while (0) } while (0)
static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) { static int uv__tty_set_style(uv_tty_t* handle, DWORD* error) {
unsigned short argc = handle->tty.wr.ansi_csi_argc; unsigned short argc = handle->tty.wr.ansi_csi_argc;
unsigned short* argv = handle->tty.wr.ansi_csi_argv; unsigned short* argv = handle->tty.wr.ansi_csi_argv;
int i; int i;
@@ -1556,7 +1556,7 @@ static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
} }
static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes, static int uv__tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
DWORD* error) { DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
@@ -1569,10 +1569,11 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
return -1; return -1;
} }
uv_tty_update_virtual_window(&info); uv__tty_update_virtual_window(&info);
handle->tty.wr.saved_position.X = info.dwCursorPosition.X; handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset; handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y -
uv_tty_virtual_offset;
handle->flags |= UV_HANDLE_TTY_SAVED_POSITION; handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
if (save_attributes) { if (save_attributes) {
@@ -1585,7 +1586,7 @@ static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
} }
static int uv_tty_restore_state(uv_tty_t* handle, static int uv__tty_restore_state(uv_tty_t* handle,
unsigned char restore_attributes, DWORD* error) { unsigned char restore_attributes, DWORD* error) {
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
WORD new_attributes; WORD new_attributes;
@@ -1595,7 +1596,7 @@ static int uv_tty_restore_state(uv_tty_t* handle,
} }
if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) { if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
if (uv_tty_move_caret(handle, if (uv__tty_move_caret(handle,
handle->tty.wr.saved_position.X, handle->tty.wr.saved_position.X,
0, 0,
handle->tty.wr.saved_position.Y, handle->tty.wr.saved_position.Y,
@@ -1625,7 +1626,7 @@ static int uv_tty_restore_state(uv_tty_t* handle,
return 0; return 0;
} }
static int uv_tty_set_cursor_visibility(uv_tty_t* handle, static int uv__tty_set_cursor_visibility(uv_tty_t* handle,
BOOL visible, BOOL visible,
DWORD* error) { DWORD* error) {
CONSOLE_CURSOR_INFO cursor_info; CONSOLE_CURSOR_INFO cursor_info;
@@ -1645,7 +1646,7 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
return 0; return 0;
} }
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) { static int uv__tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
CONSOLE_CURSOR_INFO cursor_info; CONSOLE_CURSOR_INFO cursor_info;
if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) { if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
@@ -1670,7 +1671,7 @@ static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
} }
static int uv_tty_write_bufs(uv_tty_t* handle, static int uv__tty_write_bufs(uv_tty_t* handle,
const uv_buf_t bufs[], const uv_buf_t bufs[],
unsigned int nbufs, unsigned int nbufs,
DWORD* error) { DWORD* error) {
@@ -1683,7 +1684,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
#define FLUSH_TEXT() \ #define FLUSH_TEXT() \
do { \ do { \
if (utf16_buf_used > 0) { \ if (utf16_buf_used > 0) { \
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \ uv__tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
utf16_buf_used = 0; \ utf16_buf_used = 0; \
} \ } \
} while (0) } while (0)
@@ -1802,21 +1803,21 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
case 'c': case 'c':
/* Full console reset. */ /* Full console reset. */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_reset(handle, error); uv__tty_reset(handle, error);
ansi_parser_state = ANSI_NORMAL; ansi_parser_state = ANSI_NORMAL;
continue; continue;
case '7': case '7':
/* Save the cursor position and text attributes. */ /* Save the cursor position and text attributes. */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_save_state(handle, 1, error); uv__tty_save_state(handle, 1, error);
ansi_parser_state = ANSI_NORMAL; ansi_parser_state = ANSI_NORMAL;
continue; continue;
case '8': case '8':
/* Restore the cursor position and text attributes */ /* Restore the cursor position and text attributes */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_restore_state(handle, 1, error); uv__tty_restore_state(handle, 1, error);
ansi_parser_state = ANSI_NORMAL; ansi_parser_state = ANSI_NORMAL;
continue; continue;
@@ -1849,7 +1850,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
? handle->tty.wr.ansi_csi_argv[0] : 1; ? handle->tty.wr.ansi_csi_argv[0] : 1;
if (style >= 0 && style <= 6) { if (style >= 0 && style <= 6) {
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_set_cursor_shape(handle, style, error); uv__tty_set_cursor_shape(handle, style, error);
} }
} }
@@ -1947,7 +1948,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
if (handle->tty.wr.ansi_csi_argc == 1 && if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) { handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 0, error); uv__tty_set_cursor_visibility(handle, 0, error);
} }
break; break;
@@ -1956,7 +1957,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
if (handle->tty.wr.ansi_csi_argc == 1 && if (handle->tty.wr.ansi_csi_argc == 1 &&
handle->tty.wr.ansi_csi_argv[0] == 25) { handle->tty.wr.ansi_csi_argv[0] == 25) {
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_set_cursor_visibility(handle, 1, error); uv__tty_set_cursor_visibility(handle, 1, error);
} }
break; break;
} }
@@ -1970,7 +1971,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
y = -(handle->tty.wr.ansi_csi_argc y = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1); ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 1, y, 1, error); uv__tty_move_caret(handle, 0, 1, y, 1, error);
break; break;
case 'B': case 'B':
@@ -1978,7 +1979,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
y = handle->tty.wr.ansi_csi_argc y = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1; ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 1, y, 1, error); uv__tty_move_caret(handle, 0, 1, y, 1, error);
break; break;
case 'C': case 'C':
@@ -1986,7 +1987,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
x = handle->tty.wr.ansi_csi_argc x = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1; ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, x, 1, 0, 1, error); uv__tty_move_caret(handle, x, 1, 0, 1, error);
break; break;
case 'D': case 'D':
@@ -1994,7 +1995,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
x = -(handle->tty.wr.ansi_csi_argc x = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1); ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, x, 1, 0, 1, error); uv__tty_move_caret(handle, x, 1, 0, 1, error);
break; break;
case 'E': case 'E':
@@ -2002,7 +2003,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
y = handle->tty.wr.ansi_csi_argc y = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1; ? handle->tty.wr.ansi_csi_argv[0] : 1;
uv_tty_move_caret(handle, 0, 0, y, 1, error); uv__tty_move_caret(handle, 0, 0, y, 1, error);
break; break;
case 'F': case 'F':
@@ -2010,7 +2011,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
FLUSH_TEXT(); FLUSH_TEXT();
y = -(handle->tty.wr.ansi_csi_argc y = -(handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 1); ? handle->tty.wr.ansi_csi_argv[0] : 1);
uv_tty_move_caret(handle, 0, 0, y, 1, error); uv__tty_move_caret(handle, 0, 0, y, 1, error);
break; break;
case 'G': case 'G':
@@ -2019,7 +2020,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
x = (handle->tty.wr.ansi_csi_argc >= 1 && x = (handle->tty.wr.ansi_csi_argc >= 1 &&
handle->tty.wr.ansi_csi_argv[0]) handle->tty.wr.ansi_csi_argv[0])
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0; ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
uv_tty_move_caret(handle, x, 0, 0, 1, error); uv__tty_move_caret(handle, x, 0, 0, 1, error);
break; break;
case 'H': case 'H':
@@ -2032,7 +2033,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
x = (handle->tty.wr.ansi_csi_argc >= 2 && x = (handle->tty.wr.ansi_csi_argc >= 2 &&
handle->tty.wr.ansi_csi_argv[1]) handle->tty.wr.ansi_csi_argv[1])
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0; ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
uv_tty_move_caret(handle, x, 0, y, 0, error); uv__tty_move_caret(handle, x, 0, y, 0, error);
break; break;
case 'J': case 'J':
@@ -2041,7 +2042,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
d = handle->tty.wr.ansi_csi_argc d = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 0; ? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) { if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 1, error); uv__tty_clear(handle, d, 1, error);
} }
break; break;
@@ -2051,26 +2052,26 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
d = handle->tty.wr.ansi_csi_argc d = handle->tty.wr.ansi_csi_argc
? handle->tty.wr.ansi_csi_argv[0] : 0; ? handle->tty.wr.ansi_csi_argv[0] : 0;
if (d >= 0 && d <= 2) { if (d >= 0 && d <= 2) {
uv_tty_clear(handle, d, 0, error); uv__tty_clear(handle, d, 0, error);
} }
break; break;
case 'm': case 'm':
/* Set style */ /* Set style */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_set_style(handle, error); uv__tty_set_style(handle, error);
break; break;
case 's': case 's':
/* Save the cursor position. */ /* Save the cursor position. */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_save_state(handle, 0, error); uv__tty_save_state(handle, 0, error);
break; break;
case 'u': case 'u':
/* Restore the cursor position */ /* Restore the cursor position */
FLUSH_TEXT(); FLUSH_TEXT();
uv_tty_restore_state(handle, 0, error); uv__tty_restore_state(handle, 0, error);
break; break;
} }
} }
@@ -2179,7 +2180,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
} }
int uv_tty_write(uv_loop_t* loop, int uv__tty_write(uv_loop_t* loop,
uv_write_t* req, uv_write_t* req,
uv_tty_t* handle, uv_tty_t* handle,
const uv_buf_t bufs[], const uv_buf_t bufs[],
@@ -2197,13 +2198,13 @@ int uv_tty_write(uv_loop_t* loop,
req->u.io.queued_bytes = 0; req->u.io.queued_bytes = 0;
if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) { if (!uv__tty_write_bufs(handle, bufs, nbufs, &error)) {
SET_REQ_SUCCESS(req); SET_REQ_SUCCESS(req);
} else { } else {
SET_REQ_ERROR(req, error); SET_REQ_ERROR(req, error);
} }
uv_insert_pending_req(loop, (uv_req_t*) req); uv__insert_pending_req(loop, (uv_req_t*) req);
return 0; return 0;
} }
@@ -2217,14 +2218,14 @@ int uv__tty_try_write(uv_tty_t* handle,
if (handle->stream.conn.write_reqs_pending > 0) if (handle->stream.conn.write_reqs_pending > 0)
return UV_EAGAIN; return UV_EAGAIN;
if (uv_tty_write_bufs(handle, bufs, nbufs, &error)) if (uv__tty_write_bufs(handle, bufs, nbufs, &error))
return uv_translate_sys_error(error); return uv_translate_sys_error(error);
return uv__count_bufs(bufs, nbufs); return uv__count_bufs(bufs, nbufs);
} }
void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
uv_write_t* req) { uv_write_t* req) {
int err; int err;
@@ -2236,20 +2237,22 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
req->cb(req, uv_translate_sys_error(err)); req->cb(req, uv_translate_sys_error(err));
} }
handle->stream.conn.write_reqs_pending--; handle->stream.conn.write_reqs_pending--;
if (handle->stream.conn.shutdown_req != NULL && if (handle->stream.conn.write_reqs_pending == 0)
handle->stream.conn.write_reqs_pending == 0) { if (handle->flags & UV_HANDLE_SHUTTING)
uv_want_endgame(loop, (uv_handle_t*)handle); uv__process_tty_shutdown_req(loop,
} handle,
handle->stream.conn.shutdown_req);
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_tty_close(uv_tty_t* handle) { void uv__tty_close(uv_tty_t* handle) {
assert(handle->u.fd == -1 || handle->u.fd > 2); assert(handle->u.fd == -1 || handle->u.fd > 2);
if (handle->flags & UV_HANDLE_READING) if (handle->flags & UV_HANDLE_READING)
uv_tty_read_stop(handle); uv__tty_read_stop(handle);
if (handle->u.fd == -1) if (handle->u.fd == -1)
CloseHandle(handle->handle); CloseHandle(handle->handle);
@@ -2261,61 +2264,61 @@ void uv_tty_close(uv_tty_t* handle) {
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
uv__handle_closing(handle); uv__handle_closing(handle);
if (handle->reqs_pending == 0) { if (handle->reqs_pending == 0)
uv_want_endgame(handle->loop, (uv_handle_t*) handle); uv__want_endgame(handle->loop, (uv_handle_t*) handle);
}
} }
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown_t* req) {
if (!(handle->flags & UV_HANDLE_TTY_READABLE) && assert(stream->stream.conn.write_reqs_pending == 0);
handle->stream.conn.shutdown_req != NULL && assert(req);
handle->stream.conn.write_reqs_pending == 0) {
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
/* TTY shutdown is really just a no-op */ stream->stream.conn.shutdown_req = NULL;
if (handle->stream.conn.shutdown_req->cb) { stream->flags &= ~UV_HANDLE_SHUTTING;
if (handle->flags & UV_HANDLE_CLOSING) { UNREGISTER_HANDLE_REQ(loop, stream, req);
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
} else { /* TTY shutdown is really just a no-op */
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); if (req->cb) {
} if (stream->flags & UV_HANDLE_CLOSING) {
req->cb(req, UV_ECANCELED);
} else {
req->cb(req, 0);
} }
handle->stream.conn.shutdown_req = NULL;
DECREASE_PENDING_REQ_COUNT(handle);
return;
} }
if (handle->flags & UV_HANDLE_CLOSING && DECREASE_PENDING_REQ_COUNT(stream);
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); void uv__tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
} assert(handle->flags & UV_HANDLE_CLOSING);
assert(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);
} }
/* /*
* uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working * uv__process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it * TODO: find a way to remove it
*/ */
void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle, void uv__process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
uv_req_t* raw_req) { uv_req_t* raw_req) {
abort(); abort();
} }
/* /*
* uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working * uv__process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
* TODO: find a way to remove it * TODO: find a way to remove it
*/ */
void uv_process_tty_connect_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) { uv_connect_t* req) {
abort(); abort();
} }

View File

@@ -60,7 +60,7 @@ int uv_udp_getsockname(const uv_udp_t* handle,
} }
static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, static int uv__udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
int family) { int family) {
DWORD yes = 1; DWORD yes = 1;
WSAPROTOCOL_INFOW info; WSAPROTOCOL_INFOW info;
@@ -106,8 +106,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_SET_EVENT_ON_HANDLE |
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
handle->func_wsarecv = uv_wsarecv_workaround; handle->func_wsarecv = uv__wsarecv_workaround;
handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; handle->func_wsarecvfrom = uv__wsarecvfrom_workaround;
} else if (GetLastError() != ERROR_INVALID_FUNCTION) { } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
return GetLastError(); return GetLastError();
} }
@@ -155,7 +155,7 @@ int uv__udp_init_ex(uv_loop_t* loop,
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
err = uv_udp_set_socket(handle->loop, handle, sock, domain); err = uv__udp_set_socket(handle->loop, handle, sock, domain);
if (err) { if (err) {
closesocket(sock); closesocket(sock);
QUEUE_REMOVE(&handle->handle_queue); QUEUE_REMOVE(&handle->handle_queue);
@@ -167,7 +167,7 @@ int uv__udp_init_ex(uv_loop_t* loop,
} }
void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { void uv__udp_close(uv_loop_t* loop, uv_udp_t* handle) {
uv_udp_recv_stop(handle); uv_udp_recv_stop(handle);
closesocket(handle->socket); closesocket(handle->socket);
handle->socket = INVALID_SOCKET; handle->socket = INVALID_SOCKET;
@@ -175,12 +175,12 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
uv__handle_closing(handle); uv__handle_closing(handle);
if (handle->reqs_pending == 0) { if (handle->reqs_pending == 0) {
uv_want_endgame(loop, (uv_handle_t*) handle); uv__want_endgame(loop, (uv_handle_t*) handle);
} }
} }
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { void uv__udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
if (handle->flags & UV_HANDLE_CLOSING && if (handle->flags & UV_HANDLE_CLOSING &&
handle->reqs_pending == 0) { handle->reqs_pending == 0) {
assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(!(handle->flags & UV_HANDLE_CLOSED));
@@ -194,10 +194,10 @@ int uv_udp_using_recvmmsg(const uv_udp_t* handle) {
} }
static int uv_udp_maybe_bind(uv_udp_t* handle, static int uv__udp_maybe_bind(uv_udp_t* handle,
const struct sockaddr* addr, const struct sockaddr* addr,
unsigned int addrlen, unsigned int addrlen,
unsigned int flags) { unsigned int flags) {
int r; int r;
int err; int err;
DWORD no = 0; DWORD no = 0;
@@ -216,7 +216,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
return WSAGetLastError(); return WSAGetLastError();
} }
err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family); err = uv__udp_set_socket(handle->loop, handle, sock, addr->sa_family);
if (err) { if (err) {
closesocket(sock); closesocket(sock);
return err; return err;
@@ -264,7 +264,7 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
} }
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
uv_req_t* req; uv_req_t* req;
uv_buf_t buf; uv_buf_t buf;
DWORD bytes, flags; DWORD bytes, flags;
@@ -311,7 +311,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes; req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++; handle->reqs_pending++;
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */ /* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
@@ -319,7 +319,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
} else { } else {
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
handle->reqs_pending++; handle->reqs_pending++;
} }
@@ -343,7 +343,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
req->u.io.overlapped.InternalHigh = bytes; req->u.io.overlapped.InternalHigh = bytes;
handle->reqs_pending++; handle->reqs_pending++;
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* The req will be processed with IOCP. */ /* The req will be processed with IOCP. */
handle->flags |= UV_HANDLE_READ_PENDING; handle->flags |= UV_HANDLE_READ_PENDING;
@@ -351,7 +351,7 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
} else { } else {
/* Make this req pending reporting an error. */ /* Make this req pending reporting an error. */
SET_REQ_ERROR(req, WSAGetLastError()); SET_REQ_ERROR(req, WSAGetLastError());
uv_insert_pending_req(loop, req); uv__insert_pending_req(loop, req);
handle->reqs_pending++; handle->reqs_pending++;
} }
} }
@@ -367,10 +367,10 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
return UV_EALREADY; return UV_EALREADY;
} }
err = uv_udp_maybe_bind(handle, err = uv__udp_maybe_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_, (const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_), sizeof(uv_addr_ip4_any_),
0); 0);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -384,7 +384,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
/* If reading was stopped and then started again, there could still be a recv /* If reading was stopped and then started again, there could still be a recv
* request pending. */ * request pending. */
if (!(handle->flags & UV_HANDLE_READ_PENDING)) if (!(handle->flags & UV_HANDLE_READ_PENDING))
uv_udp_queue_recv(loop, handle); uv__udp_queue_recv(loop, handle);
return 0; return 0;
} }
@@ -433,7 +433,7 @@ static int uv__send(uv_udp_send_t* req,
handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_size += req->u.io.queued_bytes;
handle->send_queue_count++; handle->send_queue_count++;
REGISTER_HANDLE_REQ(loop, handle, req); REGISTER_HANDLE_REQ(loop, handle, req);
uv_insert_pending_req(loop, (uv_req_t*)req); uv__insert_pending_req(loop, (uv_req_t*)req);
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
/* Request queued by the kernel. */ /* Request queued by the kernel. */
req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
@@ -450,7 +450,7 @@ static int uv__send(uv_udp_send_t* req,
} }
void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
uv_req_t* req) { uv_req_t* req) {
uv_buf_t buf; uv_buf_t buf;
int partial; int partial;
@@ -554,14 +554,14 @@ done:
/* Post another read if still reading and not closing. */ /* Post another read if still reading and not closing. */
if ((handle->flags & UV_HANDLE_READING) && if ((handle->flags & UV_HANDLE_READING) &&
!(handle->flags & UV_HANDLE_READ_PENDING)) { !(handle->flags & UV_HANDLE_READ_PENDING)) {
uv_udp_queue_recv(loop, handle); uv__udp_queue_recv(loop, handle);
} }
DECREASE_PENDING_REQ_COUNT(handle); DECREASE_PENDING_REQ_COUNT(handle);
} }
void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, void uv__process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
uv_udp_send_t* req) { uv_udp_send_t* req) {
int err; int err;
@@ -598,10 +598,10 @@ static int uv__udp_set_membership4(uv_udp_t* handle,
return UV_EINVAL; return UV_EINVAL;
/* If the socket is unbound, bind to inaddr_any. */ /* If the socket is unbound, bind to inaddr_any. */
err = uv_udp_maybe_bind(handle, err = uv__udp_maybe_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_, (const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_), sizeof(uv_addr_ip4_any_),
UV_UDP_REUSEADDR); UV_UDP_REUSEADDR);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -652,10 +652,10 @@ int uv__udp_set_membership6(uv_udp_t* handle,
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
return UV_EINVAL; return UV_EINVAL;
err = uv_udp_maybe_bind(handle, err = uv__udp_maybe_bind(handle,
(const struct sockaddr*) &uv_addr_ip6_any_, (const struct sockaddr*) &uv_addr_ip6_any_,
sizeof(uv_addr_ip6_any_), sizeof(uv_addr_ip6_any_),
UV_UDP_REUSEADDR); UV_UDP_REUSEADDR);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -708,10 +708,10 @@ static int uv__udp_set_source_membership4(uv_udp_t* handle,
return UV_EINVAL; return UV_EINVAL;
/* If the socket is unbound, bind to inaddr_any. */ /* If the socket is unbound, bind to inaddr_any. */
err = uv_udp_maybe_bind(handle, err = uv__udp_maybe_bind(handle,
(const struct sockaddr*) &uv_addr_ip4_any_, (const struct sockaddr*) &uv_addr_ip4_any_,
sizeof(uv_addr_ip4_any_), sizeof(uv_addr_ip4_any_),
UV_UDP_REUSEADDR); UV_UDP_REUSEADDR);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -763,10 +763,10 @@ int uv__udp_set_source_membership6(uv_udp_t* handle,
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6)) if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
return UV_EINVAL; return UV_EINVAL;
err = uv_udp_maybe_bind(handle, err = uv__udp_maybe_bind(handle,
(const struct sockaddr*) &uv_addr_ip6_any_, (const struct sockaddr*) &uv_addr_ip6_any_,
sizeof(uv_addr_ip6_any_), sizeof(uv_addr_ip6_any_),
UV_UDP_REUSEADDR); UV_UDP_REUSEADDR);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -962,10 +962,10 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
return uv_translate_sys_error(GetLastError()); return uv_translate_sys_error(GetLastError());
} }
err = uv_udp_set_socket(handle->loop, err = uv__udp_set_socket(handle->loop,
handle, handle,
sock, sock,
protocol_info.iAddressFamily); protocol_info.iAddressFamily);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -1044,7 +1044,7 @@ int uv__udp_bind(uv_udp_t* handle,
unsigned int flags) { unsigned int flags) {
int err; int err;
err = uv_udp_maybe_bind(handle, addr, addrlen, flags); err = uv__udp_maybe_bind(handle, addr, addrlen, flags);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
@@ -1066,7 +1066,7 @@ int uv__udp_connect(uv_udp_t* handle,
else else
return UV_EINVAL; return UV_EINVAL;
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
@@ -1117,7 +1117,7 @@ int uv__udp_send(uv_udp_send_t* req,
else else
return UV_EINVAL; return UV_EINVAL;
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
@@ -1146,6 +1146,7 @@ int uv__udp_try_send(uv_udp_t* handle,
err = uv__convert_to_localhost_if_unspecified(addr, &converted); err = uv__convert_to_localhost_if_unspecified(addr, &converted);
if (err) if (err)
return err; return err;
addr = (const struct sockaddr*) &converted;
} }
/* Already sending a message.*/ /* Already sending a message.*/
@@ -1159,7 +1160,7 @@ int uv__udp_try_send(uv_udp_t* handle,
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_; bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
else else
return UV_EINVAL; return UV_EINVAL;
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0); err = uv__udp_maybe_bind(handle, bind_addr, addrlen, 0);
if (err) if (err)
return uv_translate_sys_error(err); return uv_translate_sys_error(err);
} }
@@ -1169,7 +1170,7 @@ int uv__udp_try_send(uv_udp_t* handle,
nbufs, nbufs,
&bytes, &bytes,
0, 0,
(const struct sockaddr*) &converted, addr,
addrlen, addrlen,
NULL, NULL,
NULL); NULL);

View File

@@ -531,103 +531,25 @@ int uv_resident_set_memory(size_t* rss) {
int uv_uptime(double* uptime) { int uv_uptime(double* uptime) {
BYTE stack_buffer[4096]; *uptime = GetTickCount64() / 1000.0;
BYTE* malloced_buffer = NULL; return 0;
BYTE* buffer = (BYTE*) stack_buffer; }
size_t buffer_size = sizeof(stack_buffer);
DWORD data_size;
PERF_DATA_BLOCK* data_block;
PERF_OBJECT_TYPE* object_type;
PERF_COUNTER_DEFINITION* counter_definition;
DWORD i; unsigned int uv_available_parallelism(void) {
SYSTEM_INFO info;
unsigned rc;
for (;;) { /* TODO(bnoordhuis) Use GetLogicalProcessorInformationEx() to support systems
LONG result; * with > 64 CPUs? See https://github.com/libuv/libuv/pull/3458
*/
GetSystemInfo(&info);
data_size = (DWORD) buffer_size; rc = info.dwNumberOfProcessors;
result = RegQueryValueExW(HKEY_PERFORMANCE_DATA, if (rc < 1)
L"2", rc = 1;
NULL,
NULL,
buffer,
&data_size);
if (result == ERROR_SUCCESS) {
break;
} else if (result != ERROR_MORE_DATA) {
*uptime = 0;
return uv_translate_sys_error(result);
}
buffer_size *= 2; return rc;
/* Don't let the buffer grow infinitely. */
if (buffer_size > 1 << 20) {
goto internalError;
}
uv__free(malloced_buffer);
buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
if (malloced_buffer == NULL) {
*uptime = 0;
return UV_ENOMEM;
}
}
if (data_size < sizeof(*data_block))
goto internalError;
data_block = (PERF_DATA_BLOCK*) buffer;
if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
goto internalError;
if (data_size < data_block->HeaderLength + sizeof(*object_type))
goto internalError;
object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
if (object_type->NumInstances != PERF_NO_INSTANCES)
goto internalError;
counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
data_block->HeaderLength + object_type->HeaderLength);
for (i = 0; i < object_type->NumCounters; i++) {
if ((BYTE*) counter_definition + sizeof(*counter_definition) >
buffer + data_size) {
break;
}
if (counter_definition->CounterNameTitleIndex == 674 &&
counter_definition->CounterSize == sizeof(uint64_t)) {
if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
!(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
goto internalError;
} else {
BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
counter_definition->CounterOffset;
uint64_t value = *((uint64_t*) address);
*uptime = floor((double) (object_type->PerfTime.QuadPart - value) /
(double) object_type->PerfFreq.QuadPart);
uv__free(malloced_buffer);
return 0;
}
}
counter_definition = (PERF_COUNTER_DEFINITION*)
((BYTE*) counter_definition + counter_definition->ByteLength);
}
/* If we get here, the uptime value was not found. */
uv__free(malloced_buffer);
*uptime = 0;
return UV_ENOSYS;
internalError:
uv__free(malloced_buffer);
*uptime = 0;
return UV_EIO;
} }

View File

@@ -48,7 +48,7 @@ sSetWinEventHook pSetWinEventHook;
/* ws2_32.dll function pointer */ /* ws2_32.dll function pointer */
uv_sGetHostNameW pGetHostNameW; uv_sGetHostNameW pGetHostNameW;
void uv_winapi_init(void) { void uv__winapi_init(void) {
HMODULE ntdll_module; HMODULE ntdll_module;
HMODULE powrprof_module; HMODULE powrprof_module;
HMODULE user32_module; HMODULE user32_module;
@@ -126,19 +126,19 @@ void uv_winapi_init(void) {
kernel32_module, kernel32_module,
"GetQueuedCompletionStatusEx"); "GetQueuedCompletionStatusEx");
powrprof_module = LoadLibraryA("powrprof.dll"); powrprof_module = LoadLibraryExA("powrprof.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (powrprof_module != NULL) { if (powrprof_module != NULL) {
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
} }
user32_module = LoadLibraryA("user32.dll"); user32_module = GetModuleHandleA("user32.dll");
if (user32_module != NULL) { if (user32_module != NULL) {
pSetWinEventHook = (sSetWinEventHook) pSetWinEventHook = (sSetWinEventHook)
GetProcAddress(user32_module, "SetWinEventHook"); GetProcAddress(user32_module, "SetWinEventHook");
} }
ws2_32_module = LoadLibraryA("ws2_32.dll"); ws2_32_module = GetModuleHandleA("ws2_32.dll");
if (ws2_32_module != NULL) { if (ws2_32_module != NULL) {
pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( pGetHostNameW = (uv_sGetHostNameW) GetProcAddress(
ws2_32_module, ws2_32_module,

View File

@@ -38,7 +38,7 @@ struct sockaddr_in6 uv_addr_ip6_any_;
/* /*
* Retrieves the pointer to a winsock extension function. * Retrieves the pointer to a winsock extension function.
*/ */
static BOOL uv_get_extension_function(SOCKET socket, GUID guid, static BOOL uv__get_extension_function(SOCKET socket, GUID guid,
void **target) { void **target) {
int result; int result;
DWORD bytes; DWORD bytes;
@@ -62,20 +62,20 @@ static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
} }
BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
const GUID wsaid_acceptex = WSAID_ACCEPTEX; const GUID wsaid_acceptex = WSAID_ACCEPTEX;
return uv_get_extension_function(socket, wsaid_acceptex, (void**)target); return uv__get_extension_function(socket, wsaid_acceptex, (void**)target);
} }
BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
const GUID wsaid_connectex = WSAID_CONNECTEX; const GUID wsaid_connectex = WSAID_CONNECTEX;
return uv_get_extension_function(socket, wsaid_connectex, (void**)target); return uv__get_extension_function(socket, wsaid_connectex, (void**)target);
} }
void uv_winsock_init(void) { void uv__winsock_init(void) {
WSADATA wsa_data; WSADATA wsa_data;
int errorno; int errorno;
SOCKET dummy; SOCKET dummy;
@@ -134,7 +134,7 @@ void uv_winsock_init(void) {
} }
int uv_ntstatus_to_winsock_error(NTSTATUS status) { int uv__ntstatus_to_winsock_error(NTSTATUS status) {
switch (status) { switch (status) {
case STATUS_SUCCESS: case STATUS_SUCCESS:
return ERROR_SUCCESS; return ERROR_SUCCESS;
@@ -267,7 +267,7 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
* the user to use the default msafd driver, doesn't work when other LSPs are * the user to use the default msafd driver, doesn't work when other LSPs are
* stacked on top of it. * stacked on top of it.
*/ */
int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers, int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
NTSTATUS status; NTSTATUS status;
@@ -346,7 +346,7 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
break; break;
default: default:
error = uv_ntstatus_to_winsock_error(status); error = uv__ntstatus_to_winsock_error(status);
break; break;
} }
@@ -360,8 +360,8 @@ int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
} }
/* See description of uv_wsarecv_workaround. */ /* See description of uv__wsarecv_workaround. */
int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, int WSAAPI uv__wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr, DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
int* addr_len, WSAOVERLAPPED *overlapped, int* addr_len, WSAOVERLAPPED *overlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) { LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
@@ -444,7 +444,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
break; break;
default: default:
error = uv_ntstatus_to_winsock_error(status); error = uv__ntstatus_to_winsock_error(status);
break; break;
} }
@@ -458,7 +458,7 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
} }
int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, int WSAAPI uv__msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) { AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
IO_STATUS_BLOCK* iosb_ptr; IO_STATUS_BLOCK* iosb_ptr;
@@ -531,7 +531,7 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
break; break;
default: default:
error = uv_ntstatus_to_winsock_error(status); error = uv__ntstatus_to_winsock_error(status);
break; break;
} }