diff options
Diffstat (limited to 'Utilities/cmlibuv')
94 files changed, 3371 insertions, 3123 deletions
diff --git a/Utilities/cmlibuv/include/pthread-barrier.h b/Utilities/cmlibuv/include/pthread-barrier.h deleted file mode 100644 index 07db9b8a..0000000 --- a/Utilities/cmlibuv/include/pthread-barrier.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef _UV_PTHREAD_BARRIER_ -#define _UV_PTHREAD_BARRIER_ -#include <errno.h> -#include <pthread.h> -#if !defined(__MVS__) -#include <semaphore.h> /* sem_t */ -#endif - -#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 -#define UV__PTHREAD_BARRIER_FALLBACK 1 - -/* - * To maintain ABI compatibility with - * libuv v1.x struct is padded according - * to target platform - */ -#if defined(__ANDROID__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - sizeof(pthread_cond_t) + \ - sizeof(unsigned int) - \ - sizeof(void *) -#elif defined(__APPLE__) -# define UV_BARRIER_STRUCT_PADDING \ - sizeof(pthread_mutex_t) + \ - 2 * sizeof(sem_t) + \ - 2 * sizeof(unsigned int) - \ - sizeof(void *) -#else -# define UV_BARRIER_STRUCT_PADDING 0 -#endif - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned threshold; - unsigned in; - unsigned out; -} _uv_barrier; - -typedef struct { - _uv_barrier* b; - char _pad[UV_BARRIER_STRUCT_PADDING]; -} pthread_barrier_t; - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count); - -int pthread_barrier_wait(pthread_barrier_t* barrier); -int pthread_barrier_destroy(pthread_barrier_t *barrier); - -#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h index 74fa00d..e6dc736 100644 --- a/Utilities/cmlibuv/include/uv.h +++ b/Utilities/cmlibuv/include/uv.h @@ -49,21 +49,21 @@ extern "C" { # define UV_EXTERN /* nothing */ #endif -#include "uv-errno.h" -#include "uv-version.h" +#include "uv/errno.h" +#include "uv/version.h" #include <stddef.h> #include <stdio.h> #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include <stdint.h> #endif #if defined(_WIN32) -# include "uv-win.h" +# include "uv/win.h" #else -# include "uv-unix.h" +# include "uv/unix.h" #endif /* Expand this list if necessary. */ @@ -146,6 +146,7 @@ extern "C" { XX(EHOSTDOWN, "host is down") \ XX(EREMOTEIO, "remote I/O error") \ XX(ENOTTY, "inappropriate ioctl for device") \ + XX(EFTYPE, "inappropriate file type or format") \ #define UV_HANDLE_TYPE_MAP(XX) \ XX(ASYNC, async) \ @@ -237,6 +238,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; typedef struct uv_passwd_s uv_passwd_t; +typedef struct uv_utsname_s uv_utsname_t; typedef enum { UV_LOOP_BLOCK_SIGNAL @@ -373,7 +375,10 @@ typedef enum { UV_EXTERN int uv_translate_sys_error(int sys_errno); UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen); + UV_EXTERN const char* uv_err_name(int err); +UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen); #define UV_REQ_FIELDS \ @@ -507,7 +512,7 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle, struct uv_write_s { UV_REQ_FIELDS uv_write_cb cb; - uv_stream_t* send_handle; + uv_stream_t* send_handle; /* TODO: make private and unix-only in v2.x. */ uv_stream_t* handle; UV_WRITE_PRIVATE_FIELDS }; @@ -869,7 +874,13 @@ typedef enum { * flags may be specified to create a duplex data stream. */ UV_READABLE_PIPE = 0x10, - UV_WRITABLE_PIPE = 0x20 + UV_WRITABLE_PIPE = 0x20, + + /* + * Open the child pipe handle in overlapped mode on Windows. + * On Unix it is silently ignored. + */ + UV_OVERLAPPED_PIPE = 0x40 } uv_stdio_flags; typedef struct uv_stdio_container_s { @@ -970,11 +981,22 @@ enum uv_process_flags { */ UV_PROCESS_DETACHED = (1 << 3), /* + * Hide the subprocess window that would normally be created. This option is + * only meaningful on Windows systems. On Unix it is silently ignored. + */ + UV_PROCESS_WINDOWS_HIDE = (1 << 4), + /* * Hide the subprocess console window that would normally be created. This * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ - UV_PROCESS_WINDOWS_HIDE = (1 << 4) + UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5), + /* + * Hide the subprocess GUI window that would normally be created. This + * option is only meaningful on Windows systems. On Unix it is silently + * ignored. + */ + UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6) }; /* @@ -1014,16 +1036,18 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop, UV_EXTERN int uv_cancel(uv_req_t* req); +struct uv_cpu_times_s { + uint64_t user; + uint64_t nice; + uint64_t sys; + uint64_t idle; + uint64_t irq; +}; + struct uv_cpu_info_s { char* model; int speed; - struct uv_cpu_times_s { - uint64_t user; - uint64_t nice; - uint64_t sys; - uint64_t idle; - uint64_t irq; - } cpu_times; + struct uv_cpu_times_s cpu_times; }; struct uv_interface_address_s { @@ -1048,6 +1072,16 @@ struct uv_passwd_s { char* homedir; }; +struct uv_utsname_s { + char sysname[256]; + char release[256]; + char version[256]; + char machine[256]; + /* This struct does not contain the nodename and domainname fields present in + the utsname type. domainname is a GNU extension. Both fields are referred + to as meaningless in the docs. */ +}; + typedef enum { UV_DIRENT_UNKNOWN, UV_DIRENT_FILE, @@ -1070,6 +1104,7 @@ UV_EXTERN int uv_set_process_title(const char* title); UV_EXTERN int uv_resident_set_memory(size_t* rss); UV_EXTERN int uv_uptime(double* uptime); UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd); +UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd); typedef struct { long tv_sec; @@ -1104,6 +1139,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd); UV_EXTERN uv_pid_t uv_os_getpid(void); UV_EXTERN uv_pid_t uv_os_getppid(void); +#define UV_PRIORITY_LOW 19 +#define UV_PRIORITY_BELOW_NORMAL 10 +#define UV_PRIORITY_NORMAL 0 +#define UV_PRIORITY_ABOVE_NORMAL -7 +#define UV_PRIORITY_HIGH -14 +#define UV_PRIORITY_HIGHEST -20 + +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_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); @@ -1119,6 +1164,8 @@ UV_EXTERN int uv_os_unsetenv(const char* name); UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); +UV_EXTERN int uv_os_uname(uv_utsname_t* buffer); + typedef enum { UV_FS_UNKNOWN = -1, @@ -1151,7 +1198,8 @@ typedef enum { UV_FS_CHOWN, UV_FS_FCHOWN, UV_FS_REALPATH, - UV_FS_COPYFILE + UV_FS_COPYFILE, + UV_FS_LCHOWN } uv_fs_type; /* uv_fs_t is a subclass of uv_req_t. */ @@ -1354,6 +1402,12 @@ UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); +UV_EXTERN int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb); enum uv_fs_event { diff --git a/Utilities/cmlibuv/include/uv-aix.h b/Utilities/cmlibuv/include/uv/aix.h index 7dc992f..7dc992f 100644 --- a/Utilities/cmlibuv/include/uv-aix.h +++ b/Utilities/cmlibuv/include/uv/aix.h diff --git a/Utilities/cmlibuv/include/android-ifaddrs.h b/Utilities/cmlibuv/include/uv/android-ifaddrs.h index 9cd19fe..9cd19fe 100644 --- a/Utilities/cmlibuv/include/android-ifaddrs.h +++ b/Utilities/cmlibuv/include/uv/android-ifaddrs.h diff --git a/Utilities/cmlibuv/include/uv-bsd.h b/Utilities/cmlibuv/include/uv/bsd.h index 2d72b3d..2d72b3d 100644 --- a/Utilities/cmlibuv/include/uv-bsd.h +++ b/Utilities/cmlibuv/include/uv/bsd.h diff --git a/Utilities/cmlibuv/include/uv-darwin.h b/Utilities/cmlibuv/include/uv/darwin.h index d226415..d226415 100644 --- a/Utilities/cmlibuv/include/uv-darwin.h +++ b/Utilities/cmlibuv/include/uv/darwin.h diff --git a/Utilities/cmlibuv/include/uv-errno.h b/Utilities/cmlibuv/include/uv/errno.h index aa4d450..8eeb95d 100644 --- a/Utilities/cmlibuv/include/uv-errno.h +++ b/Utilities/cmlibuv/include/uv/errno.h @@ -433,5 +433,11 @@ # define UV__ENOTTY (-4029) #endif +#if defined(EFTYPE) && !defined(_WIN32) +# define UV__EFTYPE UV__ERR(EFTYPE) +#else +# define UV__EFTYPE (-4028) +#endif + #endif /* UV_ERRNO_H_ */ diff --git a/Utilities/cmlibuv/include/uv-linux.h b/Utilities/cmlibuv/include/uv/linux.h index 9b38405..9b38405 100644 --- a/Utilities/cmlibuv/include/uv-linux.h +++ b/Utilities/cmlibuv/include/uv/linux.h diff --git a/Utilities/cmlibuv/include/uv-os390.h b/Utilities/cmlibuv/include/uv/os390.h index 0267d74..0267d74 100644 --- a/Utilities/cmlibuv/include/uv-os390.h +++ b/Utilities/cmlibuv/include/uv/os390.h diff --git a/Utilities/cmlibuv/include/uv-posix.h b/Utilities/cmlibuv/include/uv/posix.h index 9a96634..9a96634 100644 --- a/Utilities/cmlibuv/include/uv-posix.h +++ b/Utilities/cmlibuv/include/uv/posix.h diff --git a/Utilities/cmlibuv/include/stdint-msvc2008.h b/Utilities/cmlibuv/include/uv/stdint-msvc2008.h index d02608a..d02608a 100644 --- a/Utilities/cmlibuv/include/stdint-msvc2008.h +++ b/Utilities/cmlibuv/include/uv/stdint-msvc2008.h diff --git a/Utilities/cmlibuv/include/uv-sunos.h b/Utilities/cmlibuv/include/uv/sunos.h index 0421664..0421664 100644 --- a/Utilities/cmlibuv/include/uv-sunos.h +++ b/Utilities/cmlibuv/include/uv/sunos.h diff --git a/Utilities/cmlibuv/include/uv-threadpool.h b/Utilities/cmlibuv/include/uv/threadpool.h index 9708ebd..9708ebd 100644 --- a/Utilities/cmlibuv/include/uv-threadpool.h +++ b/Utilities/cmlibuv/include/uv/threadpool.h diff --git a/Utilities/cmlibuv/include/tree.h b/Utilities/cmlibuv/include/uv/tree.h index f936416..f936416 100644 --- a/Utilities/cmlibuv/include/tree.h +++ b/Utilities/cmlibuv/include/uv/tree.h diff --git a/Utilities/cmlibuv/include/uv-unix.h b/Utilities/cmlibuv/include/uv/unix.h index 455674d..d10c9bd 100644 --- a/Utilities/cmlibuv/include/uv-unix.h +++ b/Utilities/cmlibuv/include/uv/unix.h @@ -42,34 +42,32 @@ #include <pthread.h> #include <signal.h> -#include "uv-threadpool.h" +#include "uv/threadpool.h" #ifdef CMAKE_BOOTSTRAP -# include "uv-posix.h" +# include "uv/posix.h" #elif defined(__linux__) -# include "uv-linux.h" +# include "uv/linux.h" #elif defined (__MVS__) -# include "uv-os390.h" +# include "uv/os390.h" #elif defined(__PASE__) -# include "uv-posix.h" +# include "uv/posix.h" #elif defined(_AIX) -# include "uv-aix.h" +# include "uv/aix.h" #elif defined(__sun) -# include "uv-sunos.h" +# include "uv/sunos.h" #elif defined(__APPLE__) -# include "uv-darwin.h" +# include "uv/darwin.h" #elif defined(__DragonFly__) || \ defined(__FreeBSD__) || \ defined(__FreeBSD_kernel__) || \ defined(__OpenBSD__) || \ defined(__NetBSD__) -# include "uv-bsd.h" +# include "uv/bsd.h" #elif defined(__CYGWIN__) || defined(__MSYS__) -# include "uv-posix.h" -#endif - -#ifndef PTHREAD_BARRIER_SERIAL_THREAD -# include "pthread-barrier.h" +# include "uv/posix.h" +#elif defined(__GNU__) +# include "uv/posix.h" #endif #ifndef NI_MAXHOST @@ -149,9 +147,30 @@ typedef pthread_rwlock_t uv_rwlock_t; typedef UV_PLATFORM_SEM_T uv_sem_t; typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; + +/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */ +#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */ +struct _uv_barrier { + uv_mutex_t mutex; + uv_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +}; + +typedef struct { + struct _uv_barrier* b; +# if defined(PTHREAD_BARRIER_SERIAL_THREAD) + /* TODO(bnoordhuis) Remove padding in v2. */ + char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)]; +# endif +} uv_barrier_t; +#else typedef pthread_barrier_t uv_barrier_t; #endif +#endif /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/Utilities/cmlibuv/include/uv-version.h b/Utilities/cmlibuv/include/uv/version.h index 06c6711..abc140a 100644 --- a/Utilities/cmlibuv/include/uv-version.h +++ b/Utilities/cmlibuv/include/uv/version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 20 -#define UV_VERSION_PATCH 3 +#define UV_VERSION_MINOR 24 +#define UV_VERSION_PATCH 2 #define UV_VERSION_IS_RELEASE 0 #define UV_VERSION_SUFFIX "dev" diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv/win.h index 6486aab..ff24ea0 100644 --- a/Utilities/cmlibuv/include/uv-win.h +++ b/Utilities/cmlibuv/include/uv/win.h @@ -25,6 +25,7 @@ #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) typedef intptr_t ssize_t; +# define SSIZE_MAX INTPTR_MAX # define _SSIZE_T_ # define _SSIZE_T_DEFINED #endif @@ -53,13 +54,13 @@ typedef struct pollfd { #include <sys/stat.h> #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include <stdint.h> #endif -#include "tree.h" -#include "uv-threadpool.h" +#include "uv/tree.h" +#include "uv/threadpool.h" #define MAX_PIPENAME_LEN 256 @@ -86,8 +87,16 @@ typedef struct pollfd { #define SIGKILL 9 #define SIGWINCH 28 -/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */ -/* unix-like platforms. However MinGW doesn't define it, so we do. */ +/* Redefine NSIG to take SIGWINCH into consideration */ +#if defined(NSIG) && NSIG <= SIGWINCH +# undef NSIG +#endif +#ifndef NSIG +# define NSIG SIGWINCH + 1 +#endif + +/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like + * platforms. However MinGW doesn't define it, so we do. */ #ifndef SIGABRT_COMPAT # define SIGABRT_COMPAT 6 #endif @@ -255,7 +264,7 @@ typedef union { CRITICAL_SECTION waiters_count_lock; HANDLE signal_event; HANDLE broadcast_event; - } fallback; + } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */ } uv_cond_t; typedef union { @@ -319,8 +328,6 @@ typedef struct { char* errmsg; } uv_lib_t; -RB_HEAD(uv_timer_tree_s, uv_timer_s); - #define UV_LOOP_PRIVATE_FIELDS \ /* The loop's I/O completion port */ \ HANDLE iocp; \ @@ -332,8 +339,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_req_t* pending_reqs_tail; \ /* Head of a single-linked list of closed handles */ \ uv_handle_t* endgame_handles; \ - /* The head of the timers tree */ \ - struct uv_timer_tree_s timers; \ + /* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */ \ + void* timer_heap; \ /* Lists of active loop (prepare / check / idle) watchers */ \ uv_prepare_t* prepare_handles; \ uv_check_t* check_handles; \ @@ -379,10 +386,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); } u; \ struct uv_req_s* next_req; -#define UV_WRITE_PRIVATE_FIELDS \ - int ipc_header; \ - uv_buf_t write_buffer; \ - HANDLE event_handle; \ +#define UV_WRITE_PRIVATE_FIELDS \ + int coalesced; \ + uv_buf_t write_buffer; \ + HANDLE event_handle; \ HANDLE wait_handle; #define UV_CONNECT_PRIVATE_FIELDS \ @@ -470,16 +477,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define uv_pipe_connection_fields \ uv_timer_t* eof_timer; \ - uv_write_t ipc_header_write_req; \ - int ipc_pid; \ - uint64_t remaining_ipc_rawdata_bytes; \ - struct { \ - void* queue[2]; \ - int queue_len; \ - } pending_ipc_info; \ + uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \ + DWORD ipc_remote_pid; \ + union { \ + uint32_t payload_remaining; \ + uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \ + } ipc_data_frame; \ + void* ipc_xfer_queue[2]; \ + int ipc_xfer_queue_length; \ uv_write_t* non_overlapped_writes_tail; \ - uv_mutex_t readfile_mutex; \ - volatile HANDLE readfile_thread; + CRITICAL_SECTION readfile_thread_lock; \ + volatile HANDLE readfile_thread_handle; #define UV_PIPE_PRIVATE_FIELDS \ HANDLE handle; \ @@ -489,8 +497,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); struct { uv_pipe_connection_fields } conn; \ } pipe; -/* TODO: put the parser states in an union - TTY handles are always */ -/* half-duplex so read-state can safely overlap write-state. */ +/* TODO: put the parser states in an union - TTY handles are always half-duplex + * so read-state can safely overlap write-state. */ #define UV_TTY_PRIVATE_FIELDS \ HANDLE handle; \ union { \ @@ -539,8 +547,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); unsigned char events; #define UV_TIMER_PRIVATE_FIELDS \ - RB_ENTRY(uv_timer_s) tree_entry; \ - uint64_t due; \ + void* heap_node[3]; \ + int unused; \ + uint64_t timeout; \ uint64_t repeat; \ uint64_t start_id; \ uv_timer_cb timer_cb; diff --git a/Utilities/cmlibuv/src/fs-poll.c b/Utilities/cmlibuv/src/fs-poll.c index ee73d5a..6c82dfc 100644 --- a/Utilities/cmlibuv/src/fs-poll.c +++ b/Utilities/cmlibuv/src/fs-poll.c @@ -83,7 +83,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle, if (err < 0) goto error; - ctx->timer_handle.flags |= UV__HANDLE_INTERNAL; + ctx->timer_handle.flags |= UV_HANDLE_INTERNAL; uv__handle_unref(&ctx->timer_handle); err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb); @@ -248,7 +248,7 @@ static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) { #include "win/handle-inl.h" void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) { - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); } diff --git a/Utilities/cmlibuv/src/idna.c b/Utilities/cmlibuv/src/idna.c new file mode 100644 index 0000000..13ffac6 --- /dev/null +++ b/Utilities/cmlibuv/src/idna.c @@ -0,0 +1,291 @@ +/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Derived from https://github.com/bnoordhuis/punycode + * but updated to support IDNA 2008. + */ + +#include "uv.h" +#include "idna.h" +#include <string.h> + +static unsigned uv__utf8_decode1_slow(const char** p, + const char* pe, + unsigned a) { + unsigned b; + unsigned c; + unsigned d; + unsigned min; + + if (a > 0xF7) + return -1; + + switch (*p - pe) { + default: + if (a > 0xEF) { + min = 0x10000; + a = a & 7; + b = (unsigned char) *(*p)++; + c = (unsigned char) *(*p)++; + d = (unsigned char) *(*p)++; + break; + } + /* Fall through. */ + case 2: + if (a > 0xDF) { + min = 0x800; + b = 0x80 | (a & 15); + c = (unsigned char) *(*p)++; + d = (unsigned char) *(*p)++; + a = 0; + break; + } + /* Fall through. */ + case 1: + if (a > 0xBF) { + min = 0x80; + b = 0x80; + c = 0x80 | (a & 31); + d = (unsigned char) *(*p)++; + a = 0; + break; + } + return -1; /* Invalid continuation byte. */ + } + + if (0x80 != (0xC0 & (b ^ c ^ d))) + return -1; /* Invalid sequence. */ + + b &= 63; + c &= 63; + d &= 63; + a = (a << 18) | (b << 12) | (c << 6) | d; + + if (a < min) + return -1; /* Overlong sequence. */ + + if (a > 0x10FFFF) + return -1; /* Four-byte sequence > U+10FFFF. */ + + if (a >= 0xD800 && a <= 0xDFFF) + return -1; /* Surrogate pair. */ + + return a; +} + +unsigned uv__utf8_decode1(const char** p, const char* pe) { + unsigned a; + + a = (unsigned char) *(*p)++; + + if (a < 128) + return a; /* ASCII, common case. */ + + return uv__utf8_decode1_slow(p, pe, a); +} + +#define foreach_codepoint(c, p, pe) \ + for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;) + +static int uv__idna_toascii_label(const char* s, const char* se, + char** d, char* de) { + static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789"; + const char* ss; + unsigned c; + unsigned h; + unsigned k; + unsigned n; + unsigned m; + unsigned q; + unsigned t; + unsigned x; + unsigned y; + unsigned bias; + unsigned delta; + unsigned todo; + int first; + + h = 0; + ss = s; + todo = 0; + + foreach_codepoint(c, &s, se) { + if (c < 128) + h++; + else if (c == (unsigned) -1) + return UV_EINVAL; + else + todo++; + } + + if (todo > 0) { + if (*d < de) *(*d)++ = 'x'; + if (*d < de) *(*d)++ = 'n'; + if (*d < de) *(*d)++ = '-'; + if (*d < de) *(*d)++ = '-'; + } + + x = 0; + s = ss; + foreach_codepoint(c, &s, se) { + if (c > 127) + continue; + + if (*d < de) + *(*d)++ = c; + + if (++x == h) + break; /* Visited all ASCII characters. */ + } + + if (todo == 0) + return h; + + /* Only write separator when we've written ASCII characters first. */ + if (h > 0) + if (*d < de) + *(*d)++ = '-'; + + n = 128; + bias = 72; + delta = 0; + first = 1; + + while (todo > 0) { + m = -1; + s = ss; + foreach_codepoint(c, &s, se) + if (c >= n) + if (c < m) + m = c; + + x = m - n; + y = h + 1; + + if (x > ~delta / y) + return UV_E2BIG; /* Overflow. */ + + delta += x * y; + n = m; + + s = ss; + foreach_codepoint(c, &s, se) { + if (c < n) + if (++delta == 0) + return UV_E2BIG; /* Overflow. */ + + if (c != n) + continue; + + for (k = 36, q = delta; /* empty */; k += 36) { + t = 1; + + if (k > bias) + t = k - bias; + + if (t > 26) + t = 26; + + if (q < t) + break; + + /* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore + * 10 <= y <= 35, we can optimize the long division + * into a table-based reciprocal multiplication. + */ + x = q - t; + y = 36 - t; /* 10 <= y <= 35 since 1 <= t <= 26. */ + q = x / y; + t = t + x % y; /* 1 <= t <= 35 because of y. */ + + if (*d < de) + *(*d)++ = alphabet[t]; + } + + if (*d < de) + *(*d)++ = alphabet[q]; + + delta /= 2; + + if (first) { + delta /= 350; + first = 0; + } + + /* No overflow check is needed because |delta| was just + * divided by 2 and |delta+delta >= delta + delta/h|. + */ + h++; + delta += delta / h; + + for (bias = 0; delta > 35 * 26 / 2; bias += 36) + delta /= 35; + + bias += 36 * delta / (delta + 38); + delta = 0; + todo--; + } + + delta++; + n++; + } + + return 0; +} + +#undef foreach_codepoint + +long uv__idna_toascii(const char* s, const char* se, char* d, char* de) { + const char* si; + const char* st; + unsigned c; + char* ds; + int rc; + + ds = d; + + for (si = s; si < se; /* empty */) { + st = si; + c = uv__utf8_decode1(&si, se); + + if (c != '.') + if (c != 0x3002) /* 。 */ + if (c != 0xFF0E) /* . */ + if (c != 0xFF61) /* 。 */ + continue; + + rc = uv__idna_toascii_label(s, st, &d, de); + + if (rc < 0) + return rc; + + if (d < de) + *d++ = '.'; + + s = si; + } + + if (s < se) { + rc = uv__idna_toascii_label(s, se, &d, de); + + if (rc < 0) + return rc; + } + + if (d < de) + *d++ = '\0'; + + return d - ds; /* Number of bytes written. */ +} diff --git a/Utilities/cmlibuv/src/idna.h b/Utilities/cmlibuv/src/idna.h new file mode 100644 index 0000000..8e0c592 --- /dev/null +++ b/Utilities/cmlibuv/src/idna.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef UV_SRC_IDNA_H_ +#define UV_SRC_IDNA_H_ + +/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error. + * |p| is updated on success _and_ error, i.e., bad multi-byte sequences are + * skipped in their entirety, not just the first bad byte. + */ +unsigned uv__utf8_decode1(const char** p, const char* pe); + +/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0 + * is the number of bytes written to |d|, including the trailing nul byte. + * A return value < 0 is a libuv error code. |s| and |d| can not overlap. + */ +long uv__idna_toascii(const char* s, const char* se, char* d, char* de); + +#endif /* UV_SRC_IDNA_H_ */ diff --git a/Utilities/cmlibuv/src/inet.c b/Utilities/cmlibuv/src/inet.c index 7c75e43..58238dc 100644 --- a/Utilities/cmlibuv/src/inet.c +++ b/Utilities/cmlibuv/src/inet.c @@ -22,7 +22,7 @@ #include <string.h> #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include <stdint.h> #endif @@ -59,8 +59,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { if (l <= 0 || (size_t) l >= size) { return UV_ENOSPC; } - strncpy(dst, tmp, size); - dst[size - 1] = '\0'; + uv__strscpy(dst, tmp, size); return 0; } @@ -142,14 +141,8 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) *tp++ = ':'; *tp++ = '\0'; - - /* - * Check for overflow, copy, and we're done. - */ - if ((size_t)(tp - tmp) > size) { + if (UV_E2BIG == uv__strscpy(dst, tmp, size)) return UV_ENOSPC; - } - strcpy(dst, tmp); return 0; } diff --git a/Utilities/cmlibuv/src/strscpy.c b/Utilities/cmlibuv/src/strscpy.c new file mode 100644 index 0000000..2a2bdce --- /dev/null +++ b/Utilities/cmlibuv/src/strscpy.c @@ -0,0 +1,17 @@ +#include "strscpy.h" +#include <limits.h> /* SSIZE_MAX */ + +ssize_t uv__strscpy(char* d, const char* s, size_t n) { + size_t i; + + for (i = 0; i < n; i++) + if ('\0' == (d[i] = s[i])) + return i > SSIZE_MAX ? UV_E2BIG : (ssize_t) i; + + if (i == 0) + return 0; + + d[--i] = '\0'; + + return UV_E2BIG; +} diff --git a/Utilities/cmlibuv/src/strscpy.h b/Utilities/cmlibuv/src/strscpy.h new file mode 100644 index 0000000..fbe0a39 --- /dev/null +++ b/Utilities/cmlibuv/src/strscpy.h @@ -0,0 +1,18 @@ +#ifndef UV_STRSCPY_H_ +#define UV_STRSCPY_H_ + +/* Include uv.h for its definitions of size_t and ssize_t. + * size_t can be obtained directly from <stddef.h> but ssize_t requires + * some hoop jumping on Windows that I didn't want to duplicate here. + */ +#include "uv.h" + +/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates + * the result, except when |n==0|. Returns the number of bytes copied + * or UV_E2BIG if |d| is too small. + * + * See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html + */ +ssize_t uv__strscpy(char* d, const char* s, size_t n); + +#endif /* UV_STRSCPY_H_ */ diff --git a/Utilities/cmlibuv/src/threadpool.c b/Utilities/cmlibuv/src/threadpool.c index 413d1c2..4258933 100644 --- a/Utilities/cmlibuv/src/threadpool.c +++ b/Utilities/cmlibuv/src/threadpool.c @@ -33,12 +33,18 @@ static uv_once_t once = UV_ONCE_INIT; static uv_cond_t cond; static uv_mutex_t mutex; static unsigned int idle_threads; +static unsigned int slow_io_work_running; static unsigned int nthreads; static uv_thread_t* threads; static uv_thread_t default_threads[4]; static QUEUE exit_message; static QUEUE wq; +static QUEUE run_slow_work_message; +static QUEUE slow_io_pending_wq; +static unsigned int slow_work_thread_threshold(void) { + return (nthreads + 1) / 2; +} static void uv__cancelled(struct uv__work* w) { abort(); @@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) { static void worker(void* arg) { struct uv__work* w; QUEUE* q; + int is_slow_work; uv_sem_post((uv_sem_t*) arg); arg = NULL; + uv_mutex_lock(&mutex); for (;;) { - uv_mutex_lock(&mutex); - - while (QUEUE_EMPTY(&wq)) { + /* `mutex` should always be locked at this point. */ + + /* Keep waiting while either no work is present or only slow I/O + and we're at the threshold for that. */ + while (QUEUE_EMPTY(&wq) || + (QUEUE_HEAD(&wq) == &run_slow_work_message && + QUEUE_NEXT(&run_slow_work_message) == &wq && + slow_io_work_running >= slow_work_thread_threshold())) { idle_threads += 1; uv_cond_wait(&cond, &mutex); idle_threads -= 1; } q = QUEUE_HEAD(&wq); - - if (q == &exit_message) + if (q == &exit_message) { uv_cond_signal(&cond); - else { + uv_mutex_unlock(&mutex); + break; + } + + QUEUE_REMOVE(q); + QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */ + + is_slow_work = 0; + if (q == &run_slow_work_message) { + /* If we're at the slow I/O threshold, re-schedule until after all + other work in the queue is done. */ + if (slow_io_work_running >= slow_work_thread_threshold()) { + QUEUE_INSERT_TAIL(&wq, q); + continue; + } + + /* If we encountered a request to run slow I/O work but there is none + to run, that means it's cancelled => Start over. */ + if (QUEUE_EMPTY(&slow_io_pending_wq)) + continue; + + is_slow_work = 1; + slow_io_work_running++; + + q = QUEUE_HEAD(&slow_io_pending_wq); QUEUE_REMOVE(q); - QUEUE_INIT(q); /* Signal uv_cancel() that the work req is - executing. */ + QUEUE_INIT(q); + + /* If there is more slow I/O work, schedule it to be run as well. */ + if (!QUEUE_EMPTY(&slow_io_pending_wq)) { + QUEUE_INSERT_TAIL(&wq, &run_slow_work_message); + if (idle_threads > 0) + uv_cond_signal(&cond); + } } uv_mutex_unlock(&mutex); - if (q == &exit_message) - break; - w = QUEUE_DATA(q, struct uv__work, wq); w->work(w); @@ -88,12 +127,32 @@ static void worker(void* arg) { QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq); uv_async_send(&w->loop->wq_async); uv_mutex_unlock(&w->loop->wq_mutex); + + /* Lock `mutex` since that is expected at the start of the next + * iteration. */ + uv_mutex_lock(&mutex); + if (is_slow_work) { + /* `slow_io_work_running` is protected by `mutex`. */ + slow_io_work_running--; + } } } -static void post(QUEUE* q) { +static void post(QUEUE* q, enum uv__work_kind kind) { uv_mutex_lock(&mutex); + if (kind == UV__WORK_SLOW_IO) { + /* Insert into a separate queue. */ + QUEUE_INSERT_TAIL(&slow_io_pending_wq, q); + if (!QUEUE_EMPTY(&run_slow_work_message)) { + /* Running slow I/O tasks is already scheduled => Nothing to do here. + The worker that runs said other task will schedule this one as well. */ + uv_mutex_unlock(&mutex); + return; + } + q = &run_slow_work_message; + } + QUEUE_INSERT_TAIL(&wq, q); if (idle_threads > 0) uv_cond_signal(&cond); @@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) { if (nthreads == 0) return; - post(&exit_message); + post(&exit_message, UV__WORK_CPU); for (i = 0; i < nthreads; i++) if (uv_thread_join(threads + i)) @@ -156,6 +215,8 @@ static void init_threads(void) { abort(); QUEUE_INIT(&wq); + QUEUE_INIT(&slow_io_pending_wq); + QUEUE_INIT(&run_slow_work_message); if (uv_sem_init(&sem, 0)) abort(); @@ -194,13 +255,14 @@ static void init_once(void) { void uv__work_submit(uv_loop_t* loop, struct uv__work* w, + enum uv__work_kind kind, void (*work)(struct uv__work* w), void (*done)(struct uv__work* w, int status)) { uv_once(&once, init_once); w->loop = loop; w->work = work; w->done = done; - post(&w->wq); + post(&w->wq, kind); } @@ -284,7 +346,11 @@ int uv_queue_work(uv_loop_t* loop, req->loop = loop; req->work_cb = work_cb; req->after_work_cb = after_work_cb; - uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done); + uv__work_submit(loop, + &req->work_req, + UV__WORK_CPU, + uv__queue_work, + uv__queue_done); return 0; } diff --git a/Utilities/cmlibuv/src/unix/timer.c b/Utilities/cmlibuv/src/timer.c index 54dabfe..dd78bcb 100644 --- a/Utilities/cmlibuv/src/unix/timer.c +++ b/Utilities/cmlibuv/src/timer.c @@ -19,13 +19,22 @@ */ #include "uv.h" -#include "internal.h" +#include "uv-common.h" #include "heap-inl.h" #include <assert.h> #include <limits.h> +static struct heap *timer_heap(const uv_loop_t* loop) { +#ifdef _WIN32 + return (struct heap*) loop->timer_heap; +#else + return (struct heap*) &loop->timer_heap; +#endif +} + + static int timer_less_than(const struct heap_node* ha, const struct heap_node* hb) { const uv_timer_t* a; @@ -81,7 +90,7 @@ int uv_timer_start(uv_timer_t* handle, /* start_id is the second index to be compared in uv__timer_cmp() */ handle->start_id = handle->loop->timer_counter++; - heap_insert((struct heap*) &handle->loop->timer_heap, + heap_insert(timer_heap(handle->loop), (struct heap_node*) &handle->heap_node, timer_less_than); uv__handle_start(handle); @@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) { if (!uv__is_active(handle)) return 0; - heap_remove((struct heap*) &handle->loop->timer_heap, + heap_remove(timer_heap(handle->loop), (struct heap_node*) &handle->heap_node, timer_less_than); uv__handle_stop(handle); @@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) { const uv_timer_t* handle; uint64_t diff; - heap_node = heap_min((const struct heap*) &loop->timer_heap); + heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) return -1; /* block indefinitely */ @@ -143,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) { if (diff > INT_MAX) diff = INT_MAX; - return diff; + return (int) diff; } @@ -152,7 +161,7 @@ void uv__run_timers(uv_loop_t* loop) { uv_timer_t* handle; for (;;) { - heap_node = heap_min((struct heap*) &loop->timer_heap); + heap_node = heap_min(timer_heap(loop)); if (heap_node == NULL) break; diff --git a/Utilities/cmlibuv/src/unix/aix-common.c b/Utilities/cmlibuv/src/unix/aix-common.c index 9c11c5d..e9697e9 100644 --- a/Utilities/cmlibuv/src/unix/aix-common.c +++ b/Utilities/cmlibuv/src/unix/aix-common.c @@ -166,8 +166,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { } -int uv_interface_addresses(uv_interface_address_t** addresses, - int* count) { +int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; int sockfd, inet6, size = 1; struct ifconf ifc; @@ -175,6 +174,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, struct sockaddr_dl* sa_addr; *count = 0; + *addresses = NULL; if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) { return UV__ERR(errno); @@ -217,6 +217,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, (*count)++; } + if (*count == 0) { + uv__close(sockfd); + return 0; + } + /* Alloc the return interface structs */ *addresses = uv__malloc(*count * sizeof(uv_interface_address_t)); if (!(*addresses)) { @@ -290,3 +295,4 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, uv__free(addresses); } + diff --git a/Utilities/cmlibuv/src/unix/aix.c b/Utilities/cmlibuv/src/unix/aix.c index 92de814..337e58e 100644 --- a/Utilities/cmlibuv/src/unix/aix.c +++ b/Utilities/cmlibuv/src/unix/aix.c @@ -358,19 +358,15 @@ void uv_loadavg(double avg[3]) { #ifdef HAVE_SYS_AHAFS_EVPRODS_H -static char *uv__rawname(char *cp) { - static char rawbuf[FILENAME_MAX+1]; - char *dp = rindex(cp, '/'); +static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) { + char* dp; + dp = rindex(cp, '/'); if (dp == 0) return 0; - *dp = 0; - strcpy(rawbuf, cp); - *dp = '/'; - strcat(rawbuf, "/r"); - strcat(rawbuf, dp+1); - return rawbuf; + snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1); + return *dst; } @@ -399,6 +395,7 @@ static int uv__path_is_a_directory(char* filename) { * Returns 0 if AHAFS is mounted, or an error code < 0 on failure */ static int uv__is_ahafs_mounted(void){ + char rawbuf[FILENAME_MAX+1]; int rv, i = 2; struct vmount *p; int size_multiplier = 10; @@ -432,7 +429,7 @@ static int uv__is_ahafs_mounted(void){ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */ - if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) { + if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) { uv__free(p); /* Found a match */ return 0; } @@ -453,7 +450,8 @@ static int uv__makedir_p(const char *dir) { size_t len; int err; - snprintf(tmp, sizeof(tmp),"%s",dir); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(tmp, dir, sizeof(tmp)); len = strlen(tmp); if (tmp[len - 1] == '/') tmp[len - 1] = 0; @@ -557,7 +555,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); - if (rc < 0) + if (rc < 0 && errno != EBUSY) return UV__ERR(errno); return 0; @@ -702,9 +700,9 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int else p++; } - strncpy(fname, p, sizeof(fname) - 1); - /* Just in case */ - fname[sizeof(fname) - 1] = '\0'; + + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(fname, p, sizeof(fname)); handle->cb(handle, fname, events, 0); } @@ -730,12 +728,19 @@ int uv_fs_event_start(uv_fs_event_t* handle, char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; char readlink_cwd[PATH_MAX]; + struct timeval zt; + fd_set pollfd; /* Figure out whether filename is absolute or not */ - if (filename[0] == '/') { + if (filename[0] == '\0') { + /* Missing a pathname */ + return UV_ENOENT; + } + else if (filename[0] == '/') { /* We have absolute pathname */ - snprintf(absolute_path, sizeof(absolute_path), "%s", filename); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(absolute_path, filename, sizeof(absolute_path)); } else { /* We have a relative pathname, compose the absolute pathname */ snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); @@ -769,6 +774,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + /* AHAFS wants someone to poll for it to start mointoring. + * so kick-start it so that we don't miss an event in the + * eventuality of an event that occurs in the current loop. */ + do { + memset(&zt, 0, sizeof(zt)); + FD_ZERO(&pollfd); + FD_SET(fd, &pollfd); + rc = select(fd + 1, &pollfd, NULL, NULL, &zt); + } while (rc == -1 && errno == EINTR); return 0; #else return UV_ENOSYS; @@ -886,16 +900,20 @@ int uv_set_process_title(const char* title) { int uv_get_process_title(char* buffer, size_t size) { size_t len; - len = strlen(process_argv[0]); if (buffer == NULL || size == 0) return UV_EINVAL; - else if (size <= len) - return UV_ENOBUFS; uv_once(&process_title_mutex_once, init_process_title_mutex_once); uv_mutex_lock(&process_title_mutex); - memcpy(buffer, process_argv[0], len + 1); + len = strlen(process_argv[0]); + if (size <= len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_argv[0], len); + buffer[len] = '\0'; uv_mutex_unlock(&process_title_mutex); @@ -982,7 +1000,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return UV_ENOMEM; } - strcpy(cpu_id.name, FIRST_CPU); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name)); result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus); if (result == -1) { uv__free(ps_cpus); diff --git a/Utilities/cmlibuv/src/unix/android-ifaddrs.c b/Utilities/cmlibuv/src/unix/android-ifaddrs.c index bf30b14..99fb25a 100644 --- a/Utilities/cmlibuv/src/unix/android-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c @@ -23,7 +23,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "android-ifaddrs.h" +#include "uv/android-ifaddrs.h" #include "uv-common.h" #include <string.h> diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c index 0d02154..3c2253f 100644 --- a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c +++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c @@ -52,13 +52,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { */ if (ent->ifa_addr->sa_family == AF_LINK) return 1; -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) if (ent->ifa_addr->sa_family != PF_INET && ent->ifa_addr->sa_family != PF_INET6) return 1; -#elif defined(__OpenBSD__) - if (ent->ifa_addr->sa_family != PF_INET) - return 1; #endif return 0; } @@ -69,11 +66,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { uv_interface_address_t* address; int i; + *count = 0; + *addresses = NULL; + if (getifaddrs(&addrs) != 0) return UV__ERR(errno); - *count = 0; - /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) @@ -81,6 +79,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } + if (*count == 0) { + freeifaddrs(addrs); + return 0; + } + *addresses = uv__malloc(*count * sizeof(**addresses)); if (*addresses == NULL) { @@ -121,15 +124,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { address = *addresses; for (i = 0; i < *count; i++) { - if (strcmp(address->name, ent->ifa_name) == 0) { #if defined(__CYGWIN__) || defined(__MSYS__) - memset(address->phys_addr, 0, sizeof(address->phys_addr)); + memset(address->phys_addr, 0, sizeof(address->phys_addr)); #else + if (strcmp(address->name, ent->ifa_name) == 0) { struct sockaddr_dl* sa_addr; sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); -#endif + } else { + memset(address->phys_addr, 0, sizeof(address->phys_addr)); } +#endif address++; } } diff --git a/Utilities/cmlibuv/src/unix/bsd-proctitle.c b/Utilities/cmlibuv/src/unix/bsd-proctitle.c new file mode 100644 index 0000000..0ce47c8 --- /dev/null +++ b/Utilities/cmlibuv/src/unix/bsd-proctitle.c @@ -0,0 +1,93 @@ +/* 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 "uv.h" +#include "internal.h" + +#include <sys/types.h> +#include <unistd.h> + + +static uv_mutex_t process_title_mutex; +static uv_once_t process_title_mutex_once = UV_ONCE_INIT; +static char* process_title; + + +static void init_process_title_mutex_once(void) { + if (uv_mutex_init(&process_title_mutex)) + abort(); +} + + +char** uv_setup_args(int argc, char** argv) { + process_title = argc > 0 ? uv__strdup(argv[0]) : NULL; + return argv; +} + + +int uv_set_process_title(const char* title) { + char* new_title; + + new_title = uv__strdup(title); + if (new_title == NULL) + return UV_ENOMEM; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + uv__free(process_title); + process_title = new_title; + setproctitle("%s", title); + + uv_mutex_unlock(&process_title_mutex); + + return 0; +} + + +int uv_get_process_title(char* buffer, size_t size) { + size_t len; + + if (buffer == NULL || size == 0) + return UV_EINVAL; + + uv_once(&process_title_mutex_once, init_process_title_mutex_once); + uv_mutex_lock(&process_title_mutex); + + if (process_title != NULL) { + len = strlen(process_title) + 1; + + if (size < len) { + uv_mutex_unlock(&process_title_mutex); + return UV_ENOBUFS; + } + + memcpy(buffer, process_title, len); + } else { + len = 0; + } + + uv_mutex_unlock(&process_title_mutex); + + buffer[len] = '\0'; + + return 0; +} diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c index a357ef3..a8d6adb 100644 --- a/Utilities/cmlibuv/src/unix/core.c +++ b/Utilities/cmlibuv/src/unix/core.c @@ -41,6 +41,7 @@ #include <sys/resource.h> /* getrusage */ #include <pwd.h> #include <sched.h> +#include <sys/utsname.h> #ifdef __sun # include <netdb.h> /* MAXHOSTNAMELEN on Solaris */ @@ -119,7 +120,7 @@ uint64_t uv_hrtime(void) { void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { assert(!uv__is_closing(handle)); - handle->flags |= UV_CLOSING; + handle->flags |= UV_HANDLE_CLOSING; handle->close_cb = close_cb; switch (handle->type) { @@ -177,8 +178,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { case UV_SIGNAL: uv__signal_close((uv_signal_t*) handle); - /* Signal handles may not be closed immediately. The signal code will */ - /* itself close uv__make_close_pending whenever appropriate. */ + /* Signal handles may not be closed immediately. The signal code will + * itself close uv__make_close_pending whenever appropriate. */ return; default: @@ -217,8 +218,8 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) { } void uv__make_close_pending(uv_handle_t* handle) { - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->next_closing = handle->loop->closing_handles; handle->loop->closing_handles = handle; } @@ -244,15 +245,17 @@ int uv__getiovmax(void) { static void uv__finish_close(uv_handle_t* handle) { - /* Note: while the handle is in the UV_CLOSING state now, it's still possible - * for it to be active in the sense that uv__is_active() returns true. + /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still + * possible for it to be active in the sense that uv__is_active() returns + * true. + * * A good example is when the user calls uv_shutdown(), immediately followed * by uv_close(). The handle is considered active at this point because the * completion of the shutdown req is still pending. */ - assert(handle->flags & UV_CLOSING); - assert(!(handle->flags & UV_CLOSED)); - handle->flags |= UV_CLOSED; + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; switch (handle->type) { case UV_PREPARE: @@ -637,27 +640,6 @@ int uv__cloexec_fcntl(int fd, int set) { } -/* This function is not execve-safe, there is a race window - * between the call to dup() and fcntl(FD_CLOEXEC). - */ -int uv__dup(int fd) { - int err; - - fd = dup(fd); - - if (fd == -1) - return UV__ERR(errno); - - err = uv__cloexec(fd, 1); - if (err) { - uv__close(fd); - return err; - } - - return fd; -} - - ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { struct cmsghdr* cmsg; ssize_t rc; @@ -930,6 +912,11 @@ int uv__io_active(const uv__io_t* w, unsigned int events) { } +int uv__fd_exists(uv_loop_t* loop, int fd) { + return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL; +} + + int uv_getrusage(uv_rusage_t* rusage) { struct rusage usage; @@ -1343,6 +1330,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) { return fd; } +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return os_fd; +} uv_pid_t uv_os_getpid(void) { return getpid(); @@ -1352,3 +1342,87 @@ uv_pid_t uv_os_getpid(void) { uv_pid_t uv_os_getppid(void) { return getppid(); } + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + int r; + + if (priority == NULL) + return UV_EINVAL; + + errno = 0; + r = getpriority(PRIO_PROCESS, (int) pid); + + if (r == -1 && errno != 0) + return UV__ERR(errno); + + *priority = r; + return 0; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + + if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0) + return UV__ERR(errno); + + return 0; +} + + +int uv_os_uname(uv_utsname_t* buffer) { + struct utsname buf; + int r; + + if (buffer == NULL) + return UV_EINVAL; + + if (uname(&buf) == -1) { + r = UV__ERR(errno); + goto error; + } + + r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname)); + if (r == UV_E2BIG) + goto error; + +#ifdef _AIX + r = snprintf(buffer->release, + sizeof(buffer->release), + "%s.%s", + buf.version, + buf.release); + if (r >= sizeof(buffer->release)) { + r = UV_E2BIG; + goto error; + } +#else + r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release)); + if (r == UV_E2BIG) + goto error; +#endif + + r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version)); + if (r == UV_E2BIG) + goto error; + +#if defined(_AIX) || defined(__PASE__) + r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine)); +#else + r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine)); +#endif + + if (r == UV_E2BIG) + goto error; + + return 0; + +error: + buffer->sysname[0] = '\0'; + buffer->release[0] = '\0'; + buffer->version[0] = '\0'; + buffer->machine[0] = '\0'; + return r; +} diff --git a/Utilities/cmlibuv/src/unix/cygwin.c b/Utilities/cmlibuv/src/unix/cygwin.c index 9fe4093..9da20e2 100644 --- a/Utilities/cmlibuv/src/unix/cygwin.c +++ b/Utilities/cmlibuv/src/unix/cygwin.c @@ -38,7 +38,7 @@ int uv_uptime(double* uptime) { int uv_resident_set_memory(size_t* rss) { /* FIXME: read /proc/meminfo? */ *rss = 0; - return UV_ENOSYS; + return 0; } int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { diff --git a/Utilities/cmlibuv/src/unix/darwin-proctitle.c b/Utilities/cmlibuv/src/unix/darwin-proctitle.c index dabde22..e505bdd 100644 --- a/Utilities/cmlibuv/src/unix/darwin-proctitle.c +++ b/Utilities/cmlibuv/src/unix/darwin-proctitle.c @@ -33,61 +33,56 @@ # include <ApplicationServices/ApplicationServices.h> #endif +#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) -static int uv__pthread_setname_np(const char* name) { - int (*dynamic_pthread_setname_np)(const char* name); - char namebuf[64]; /* MAXTHREADNAMESIZE */ - int err; - - /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ - *(void **)(&dynamic_pthread_setname_np) = - dlsym(RTLD_DEFAULT, "pthread_setname_np"); - - if (dynamic_pthread_setname_np == NULL) - return UV_ENOSYS; - - strncpy(namebuf, name, sizeof(namebuf) - 1); - namebuf[sizeof(namebuf) - 1] = '\0'; - err = dynamic_pthread_setname_np(namebuf); - if (err) - return UV__ERR(err); +static int (*dynamic_pthread_setname_np)(const char* name); +#if !TARGET_OS_IPHONE +static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, + const char*, + CFStringEncoding); +static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); +static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); +static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); +static CFTypeRef (*pLSGetCurrentApplicationASN)(void); +static OSStatus (*pLSSetApplicationInformationItem)(int, + CFTypeRef, + CFStringRef, + CFStringRef, + CFDictionaryRef*); +static void* application_services_handle; +static void* core_foundation_handle; +static CFBundleRef launch_services_bundle; +static CFStringRef* display_name_key; +static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); +static CFBundleRef (*pCFBundleGetMainBundle)(void); +static CFBundleRef hi_services_bundle; +static OSStatus (*pSetApplicationIsDaemon)(int); +static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); +static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, + void*); + + +UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) { + if (core_foundation_handle != NULL) { + dlclose(core_foundation_handle); + core_foundation_handle = NULL; + } - return 0; + if (application_services_handle != NULL) { + dlclose(application_services_handle); + application_services_handle = NULL; + } } +#endif /* !TARGET_OS_IPHONE */ -int uv__set_process_title(const char* title) { -#if TARGET_OS_IPHONE - return uv__pthread_setname_np(title); -#else - CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef, - const char*, - CFStringEncoding); - CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef); - void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef); - void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef); - CFTypeRef (*pLSGetCurrentApplicationASN)(void); - OSStatus (*pLSSetApplicationInformationItem)(int, - CFTypeRef, - CFStringRef, - CFStringRef, - CFDictionaryRef*); - void* application_services_handle; - void* core_foundation_handle; - CFBundleRef launch_services_bundle; - CFStringRef* display_name_key; - CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef); - CFBundleRef (*pCFBundleGetMainBundle)(void); - CFBundleRef hi_services_bundle; - OSStatus (*pSetApplicationIsDaemon)(int); - CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef); - void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t, - void*); - CFTypeRef asn; - int err; - - err = UV_ENOENT; +void uv__set_process_title_platform_init(void) { + /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */ + *(void **)(&dynamic_pthread_setname_np) = + dlsym(RTLD_DEFAULT, "pthread_setname_np"); + +#if !TARGET_OS_IPHONE application_services_handle = dlopen("/System/Library/Frameworks/" "ApplicationServices.framework/" "Versions/A/ApplicationServices", @@ -116,8 +111,6 @@ int uv__set_process_title(const char* title) { goto out; } -#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8) - launch_services_bundle = pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices")); @@ -148,13 +141,14 @@ int uv__set_process_title(const char* title) { "CFBundleGetInfoDictionary"); *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle, "CFBundleGetMainBundle"); + if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL) goto out; /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */ hi_services_bundle = pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices")); - err = UV_ENOENT; + if (hi_services_bundle == NULL) goto out; @@ -168,42 +162,37 @@ int uv__set_process_title(const char* title) { pCFBundleGetFunctionPointerForName( launch_services_bundle, S("_LSSetApplicationLaunchServicesServerConnectionStatus")); + if (pSetApplicationIsDaemon == NULL || pLSApplicationCheckIn == NULL || pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) { goto out; } - if (pSetApplicationIsDaemon(1) != noErr) - goto out; - - pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); - - /* Check into process manager?! */ - pLSApplicationCheckIn(-2, - pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); - - asn = pLSGetCurrentApplicationASN(); - - err = UV_EINVAL; - if (pLSSetApplicationInformationItem(-2, /* Magic value. */ - asn, - *display_name_key, - S(title), - NULL) != noErr) { - goto out; - } - - uv__pthread_setname_np(title); /* Don't care if it fails. */ - err = 0; + return; out: - if (core_foundation_handle != NULL) - dlclose(core_foundation_handle); + uv__set_process_title_platform_fini(); +#endif /* !TARGET_OS_IPHONE */ +} - if (application_services_handle != NULL) - dlclose(application_services_handle); - return err; +void uv__set_process_title(const char* title) { +#if !TARGET_OS_IPHONE + if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) { + CFTypeRef asn; + pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL); + pLSApplicationCheckIn(/* Magic value */ -2, + pCFBundleGetInfoDictionary(pCFBundleGetMainBundle())); + asn = pLSGetCurrentApplicationASN(); + pLSSetApplicationInformationItem(/* Magic value */ -2, asn, + *display_name_key, S(title), NULL); + } #endif /* !TARGET_OS_IPHONE */ + + if (dynamic_pthread_setname_np != NULL) { + char namebuf[64]; /* MAXTHREADNAMESIZE */ + uv__strscpy(namebuf, title, sizeof(namebuf)); + dynamic_pthread_setname_np(namebuf); + } } diff --git a/Utilities/cmlibuv/src/unix/freebsd.c b/Utilities/cmlibuv/src/unix/freebsd.c index 70ccb13..0f729cf 100644 --- a/Utilities/cmlibuv/src/unix/freebsd.c +++ b/Utilities/cmlibuv/src/unix/freebsd.c @@ -47,15 +47,6 @@ # define CP_INTR 4 #endif -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); @@ -159,76 +150,6 @@ void uv_loadavg(double avg[3]) { } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - int oid[4]; - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_title; - - oid[0] = CTL_KERN; - oid[1] = KERN_PROC; - oid[2] = KERN_PROC_ARGS; - oid[3] = getpid(); - - sysctl(oid, - ARRAY_SIZE(oid), - NULL, - NULL, - process_title, - strlen(process_title) + 1); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\0'; - - return 0; -} - int uv_resident_set_memory(size_t* rss) { struct kinfo_proc kinfo; size_t page_size; diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c index a6cc6db..bffc956 100644 --- a/Utilities/cmlibuv/src/unix/fs.c +++ b/Utilities/cmlibuv/src/unix/fs.c @@ -43,7 +43,6 @@ #include <pthread.h> #include <unistd.h> #include <fcntl.h> -#include <utime.h> #include <poll.h> #if defined(__DragonFly__) || \ @@ -62,11 +61,20 @@ #if defined(__APPLE__) # include <copyfile.h> +# include <sys/sysctl.h> #elif defined(__linux__) && !defined(FICLONE) # include <sys/ioctl.h> # define FICLONE _IOW(0x94, 9, int) #endif +#if defined(_AIX) && !defined(_AIX71) +# include <utime.h> +#endif + +#if defined(_AIX) && _XOPEN_SOURCE <= 600 +extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */ +#endif + #define INIT(subtype) \ do { \ if (req == NULL) \ @@ -120,7 +128,11 @@ do { \ if (cb != NULL) { \ uv__req_register(loop, req); \ - uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + uv__work_submit(loop, \ + &req->work_req, \ + UV__WORK_FAST_IO, \ + uv__fs_work, \ + uv__fs_done); \ return 0; \ } \ else { \ @@ -143,7 +155,7 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) { int r; r = fcntl(req->file, F_FULLFSYNC); - if (r != 0 && errno == ENOTTY) + if (r != 0) r = fsync(req->file); return r; #else @@ -165,59 +177,17 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) { static ssize_t uv__fs_futime(uv_fs_t* req) { -#if defined(__linux__) +#if defined(__linux__) \ + || defined(_AIX71) /* utimesat() has nanosecond resolution but we stick to microseconds * for the sake of consistency with other platforms. */ - static int no_utimesat; struct timespec ts[2]; - struct timeval tv[2]; - char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)]; - int r; - - if (no_utimesat) - goto skip; - ts[0].tv_sec = req->atime; ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; ts[1].tv_sec = req->mtime; ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - - r = uv__utimesat(req->file, NULL, ts, 0); - if (r == 0) - return r; - - if (errno != ENOSYS) - return r; - - no_utimesat = 1; - -skip: - - tv[0].tv_sec = req->atime; - tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; - tv[1].tv_sec = req->mtime; - tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; - snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file); - - r = utimes(path, tv); - if (r == 0) - return r; - - switch (errno) { - case ENOENT: - if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF) - break; - /* Fall through. */ - - case EACCES: - case ENOTDIR: - errno = ENOSYS; - break; - } - - return r; - + return futimens(req->file, ts); #elif defined(__APPLE__) \ || defined(__DragonFly__) \ || defined(__FreeBSD__) \ @@ -235,13 +205,6 @@ skip: # else return futimes(req->file, tv); # endif -#elif defined(_AIX71) - struct timespec ts[2]; - ts[0].tv_sec = req->atime; - ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; - ts[1].tv_sec = req->mtime; - ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; - return futimens(req->file, ts); #elif defined(__MVS__) attrib_t atr; memset(&atr, 0, sizeof(atr)); @@ -314,17 +277,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { #if defined(__linux__) static int no_preadv; #endif + unsigned int iovmax; ssize_t result; -#if defined(_AIX) - struct stat buf; - if(fstat(req->file, &buf)) - return -1; - if(S_ISDIR(buf.st_mode)) { - errno = EISDIR; - return -1; - } -#endif /* defined(_AIX) */ + iovmax = uv__getiovmax(); + if (req->nbufs > iovmax) + req->nbufs = iovmax; + if (req->off < 0) { if (req->nbufs == 1) result = read(req->file, req->bufs[0].base, req->bufs[0].len); @@ -343,25 +302,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) { if (no_preadv) retry: # endif { - off_t nread; - size_t index; - - nread = 0; - index = 0; - result = 1; - do { - if (req->bufs[index].len > 0) { - result = pread(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + nread); - if (result > 0) - nread += result; - } - index++; - } while (index < req->nbufs && result > 0); - if (nread > 0) - result = nread; + result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -379,6 +320,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } done: + /* Early cleanup of bufs allocation, since we're done with it. */ + if (req->bufs != req->bufsml) + uv__free(req->bufs); + + req->bufs = NULL; + req->nbufs = 0; + return result; } @@ -446,8 +394,10 @@ static ssize_t uv__fs_pathmax_size(const char* path) { } static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t maxlen; ssize_t len; char* buf; + char* newbuf; #if defined(UV__FS_PATH_MAX_FALLBACK) /* We may not have a real PATH_MAX. Read size of link. */ @@ -461,17 +411,17 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { return -1; } - len = st.st_size; + maxlen = st.st_size; /* According to readlink(2) lstat can report st_size == 0 for some symlinks, such as those in /proc or /sys. */ - if (len == 0) - len = uv__fs_pathmax_size(req->path); + if (maxlen == 0) + maxlen = uv__fs_pathmax_size(req->path); #else - len = uv__fs_pathmax_size(req->path); + maxlen = uv__fs_pathmax_size(req->path); #endif - buf = uv__malloc(len + 1); + buf = uv__malloc(maxlen); if (buf == NULL) { errno = ENOMEM; @@ -479,17 +429,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { } #if defined(__MVS__) - len = os390_readlink(req->path, buf, len); + len = os390_readlink(req->path, buf, maxlen); #else - len = readlink(req->path, buf, len); + len = readlink(req->path, buf, maxlen); #endif - if (len == -1) { uv__free(buf); return -1; } + /* Uncommon case: resize to make room for the trailing nul byte. */ + if (len == maxlen) { + newbuf = uv__realloc(buf, len + 1); + + if (newbuf == NULL) { + uv__free(buf); + return -1; + } + + buf = newbuf; + } + buf[len] = '\0'; req->ptr = buf; @@ -739,10 +700,48 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { static ssize_t uv__fs_utime(uv_fs_t* req) { +#if defined(__linux__) \ + || defined(_AIX71) \ + || defined(__sun) + /* utimesat() has nanosecond resolution but we stick to microseconds + * for the sake of consistency with other platforms. + */ + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000; + return utimensat(AT_FDCWD, req->path, ts, 0); +#elif defined(__APPLE__) \ + || defined(__DragonFly__) \ + || defined(__FreeBSD__) \ + || defined(__FreeBSD_kernel__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) + struct timeval tv[2]; + tv[0].tv_sec = req->atime; + tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000; + tv[1].tv_sec = req->mtime; + tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000; + return utimes(req->path, tv); +#elif defined(_AIX) \ + && !defined(_AIX71) struct utimbuf buf; buf.actime = req->atime; buf.modtime = req->mtime; - return utime(req->path, &buf); /* TODO use utimes() where available */ + return utime(req->path, &buf); +#elif defined(__MVS__) + attrib_t atr; + memset(&atr, 0, sizeof(atr)); + atr.att_mtimechg = 1; + atr.att_atimechg = 1; + atr.att_mtime = req->mtime; + atr.att_atime = req->atime; + return __lchattr((char*) req->path, &atr, sizeof(atr)); +#else + errno = ENOSYS; + return -1; +#endif } @@ -780,25 +779,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) { if (no_pwritev) retry: # endif { - off_t written; - size_t index; - - written = 0; - index = 0; - r = 0; - do { - if (req->bufs[index].len > 0) { - r = pwrite(req->file, - req->bufs[index].base, - req->bufs[index].len, - req->off + written); - if (r > 0) - written += r; - } - index++; - } while (index < req->nbufs && r >= 0); - if (written > 0) - r = written; + r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off); } # if defined(__linux__) else { @@ -827,26 +808,41 @@ done: static ssize_t uv__fs_copyfile(uv_fs_t* req) { #if defined(__APPLE__) && !TARGET_OS_IPHONE /* On macOS, use the native copyfile(3). */ + static int can_clone; copyfile_flags_t flags; + char buf[64]; + size_t len; + int major; flags = COPYFILE_ALL; if (req->flags & UV_FS_COPYFILE_EXCL) flags |= COPYFILE_EXCL; -#ifdef COPYFILE_CLONE - if (req->flags & UV_FS_COPYFILE_FICLONE) - flags |= COPYFILE_CLONE; -#endif - + /* Check OS version. Cloning is only supported on macOS >= 10.12. */ if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { -#ifdef COPYFILE_CLONE_FORCE - flags |= COPYFILE_CLONE_FORCE; -#else - return UV_ENOSYS; -#endif + if (can_clone == 0) { + len = sizeof(buf); + if (sysctlbyname("kern.osrelease", buf, &len, NULL, 0)) + return UV__ERR(errno); + + if (1 != sscanf(buf, "%d", &major)) + abort(); + + can_clone = -1 + 2 * (major >= 16); /* macOS >= 10.12 */ + } + + if (can_clone < 0) + return UV_ENOSYS; } + /* copyfile() simply ignores COPYFILE_CLONE if it's not supported. */ + if (req->flags & UV_FS_COPYFILE_FICLONE) + flags |= 1 << 24; /* COPYFILE_CLONE */ + + if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) + flags |= 1 << 25; /* COPYFILE_CLONE_FORCE */ + return copyfile(req->path, req->new_path, NULL, flags); #else uv_fs_t fs_req; @@ -906,9 +902,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) { /* If an error occurred that the sendfile fallback also won't handle, or this is a force clone then exit. Otherwise, fall through to try using sendfile(). */ - if ((errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) || - req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { - err = -errno; + if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) { + err = UV__ERR(errno); + goto out; + } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) { + err = UV_ENOTSUP; goto out; } } else { @@ -968,7 +966,11 @@ out: } } - return result; + if (result == 0) + return 0; + + errno = UV__ERR(result); + return -1; #endif } @@ -1084,9 +1086,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) { return ret; } +static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) { + size_t offset; + /* Figure out which bufs are done */ + for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset) + size -= bufs[offset].len; + + /* Fix a partial read/write */ + if (size > 0) { + bufs[offset].base += size; + bufs[offset].len -= size; + } + return offset; +} -typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req); -static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) { +static ssize_t uv__fs_write_all(uv_fs_t* req) { unsigned int iovmax; unsigned int nbufs; uv_buf_t* bufs; @@ -1103,7 +1117,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->nbufs > iovmax) req->nbufs = iovmax; - result = process(req); + do + result = uv__fs_write(req); + while (result < 0 && errno == EINTR); + if (result <= 0) { if (total == 0) total = result; @@ -1113,14 +1130,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) if (req->off >= 0) req->off += result; + req->nbufs = uv__fs_buf_offset(req->bufs, result); req->bufs += req->nbufs; nbufs -= req->nbufs; total += result; } - if (errno == EINTR && total == -1) - return total; - if (bufs != req->bufsml) uv__free(bufs); @@ -1137,7 +1152,8 @@ static void uv__fs_work(struct uv__work* w) { ssize_t r; req = container_of(w, uv_fs_t, work_req); - retry_on_eintr = !(req->fs_type == UV_FS_CLOSE); + retry_on_eintr = !(req->fs_type == UV_FS_CLOSE || + req->fs_type == UV_FS_READ); do { errno = 0; @@ -1155,6 +1171,7 @@ static void uv__fs_work(struct uv__work* w) { X(COPYFILE, uv__fs_copyfile(req)); X(FCHMOD, fchmod(req->file, req->mode)); X(FCHOWN, fchown(req->file, req->uid, req->gid)); + X(LCHOWN, lchown(req->path, req->uid, req->gid)); X(FDATASYNC, uv__fs_fdatasync(req)); X(FSTAT, uv__fs_fstat(req->file, &req->statbuf)); X(FSYNC, uv__fs_fsync(req)); @@ -1165,7 +1182,7 @@ static void uv__fs_work(struct uv__work* w) { X(MKDIR, mkdir(req->path, req->mode)); X(MKDTEMP, uv__fs_mkdtemp(req)); X(OPEN, uv__fs_open(req)); - X(READ, uv__fs_buf_iter(req, uv__fs_read)); + X(READ, uv__fs_read(req)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); X(REALPATH, uv__fs_realpath(req)); @@ -1176,7 +1193,7 @@ static void uv__fs_work(struct uv__work* w) { X(SYMLINK, symlink(req->path, req->new_path)); X(UNLINK, unlink(req->path)); X(UTIME, uv__fs_utime(req)); - X(WRITE, uv__fs_buf_iter(req, uv__fs_write)); + X(WRITE, uv__fs_write_all(req)); default: abort(); } #undef X @@ -1281,6 +1298,20 @@ int uv_fs_fchown(uv_loop_t* loop, } +int uv_fs_lchown(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_uid_t uid, + uv_gid_t gid, + uv_fs_cb cb) { + INIT(LCHOWN); + PATH; + req->uid = uid; + req->gid = gid; + POST; +} + + int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { INIT(FDATASYNC); req->file = file; diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c index 47d8024..c430562 100644 --- a/Utilities/cmlibuv/src/unix/fsevents.c +++ b/Utilities/cmlibuv/src/unix/fsevents.c @@ -255,42 +255,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, path = paths[i]; len = strlen(path); + if (handle->realpath_len == 0) + continue; /* This should be unreachable */ + /* Filter out paths that are outside handle's request */ - if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + if (len < handle->realpath_len) + continue; + + if (handle->realpath_len != len && + path[handle->realpath_len] != '/') + /* Make sure that realpath actually named a directory, + * or that we matched the whole string */ continue; - if (handle->realpath_len > 1 || *handle->realpath != '/') { + if (memcmp(path, handle->realpath, handle->realpath_len) != 0) + continue; + + if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) { + /* Remove common prefix, unless the watched folder is "/" */ path += handle->realpath_len; len -= handle->realpath_len; - /* Skip forward slash */ - if (*path != '\0') { + /* Ignore events with path equal to directory itself */ + if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir)) + continue; + + if (len == 0) { + /* Since we're using fsevents to watch the file itself, + * realpath == path, and we now need to get the basename of the file back + * (for commonality with other codepaths and platforms). */ + while (len < handle->realpath_len && path[-1] != '/') { + path--; + len++; + } + /* Created and Removed seem to be always set, but don't make sense */ + flags &= ~kFSEventsRenamed; + } else { + /* Skip forward slash */ path++; len--; } } -#ifdef MAC_OS_X_VERSION_10_7 - /* Ignore events with path equal to directory itself */ - if (len == 0) - continue; -#else - if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) - continue; -#endif /* MAC_OS_X_VERSION_10_7 */ - /* Do not emit events from subdirectories (without option set) */ - if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') { pos = strchr(path + 1, '/'); if (pos != NULL) continue; } -#ifndef MAC_OS_X_VERSION_10_7 - path = ""; - len = 0; -#endif /* MAC_OS_X_VERSION_10_7 */ - event = uv__malloc(sizeof(*event) + len); if (event == NULL) break; @@ -299,22 +312,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, memcpy(event->path, path, len + 1); event->events = UV_RENAME; -#ifdef MAC_OS_X_VERSION_10_7 - if (0 != (flags & kFSEventsModified) && - 0 == (flags & kFSEventsRenamed)) { - event->events = UV_CHANGE; - } -#else - if (0 != (flags & kFSEventsModified) && - 0 != (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; - } - if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; + if (0 == (flags & kFSEventsRenamed)) { + if (0 != (flags & kFSEventsModified) || + 0 == (flags & kFSEventStreamEventFlagItemIsDir)) + event->events = UV_CHANGE; } -#endif /* MAC_OS_X_VERSION_10_7 */ QUEUE_INSERT_TAIL(&head, &event->member); } @@ -836,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { handle->cf_cb->data = handle; uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb); - handle->cf_cb->flags |= UV__HANDLE_INTERNAL; + handle->cf_cb->flags |= UV_HANDLE_INTERNAL; uv_unref((uv_handle_t*) handle->cf_cb); err = uv_mutex_init(&handle->cf_mutex); diff --git a/Utilities/cmlibuv/src/unix/getaddrinfo.c b/Utilities/cmlibuv/src/unix/getaddrinfo.c index 10e8afd..6d23fbe 100644 --- a/Utilities/cmlibuv/src/unix/getaddrinfo.c +++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c @@ -27,6 +27,7 @@ #include "uv.h" #include "internal.h" +#include "idna.h" #include <errno.h> #include <stddef.h> /* NULL */ @@ -141,15 +142,34 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* hostname, const char* service, const struct addrinfo* hints) { + char hostname_ascii[256]; size_t hostname_len; size_t service_len; size_t hints_len; size_t len; char* buf; + long rc; if (req == NULL || (hostname == NULL && service == NULL)) return UV_EINVAL; + /* FIXME(bnoordhuis) IDNA does not seem to work z/OS, + * probably because it uses EBCDIC rather than ASCII. + */ +#ifdef __MVS__ + (void) &hostname_ascii; +#else + if (hostname != NULL) { + rc = uv__idna_toascii(hostname, + hostname + strlen(hostname), + hostname_ascii, + hostname_ascii + sizeof(hostname_ascii)); + if (rc < 0) + return rc; + hostname = hostname_ascii; + } +#endif + hostname_len = hostname ? strlen(hostname) + 1 : 0; service_len = service ? strlen(service) + 1 : 0; hints_len = hints ? sizeof(*hints) : 0; @@ -186,6 +206,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; diff --git a/Utilities/cmlibuv/src/unix/getnameinfo.c b/Utilities/cmlibuv/src/unix/getnameinfo.c index d9e6f79..b695081 100644 --- a/Utilities/cmlibuv/src/unix/getnameinfo.c +++ b/Utilities/cmlibuv/src/unix/getnameinfo.c @@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop, if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; diff --git a/Utilities/cmlibuv/src/unix/ibmi.c b/Utilities/cmlibuv/src/unix/ibmi.c index 02e90fb..13fed6c 100644 --- a/Utilities/cmlibuv/src/unix/ibmi.c +++ b/Utilities/cmlibuv/src/unix/ibmi.c @@ -72,7 +72,8 @@ void uv_loadavg(double avg[3]) { int uv_resident_set_memory(size_t* rss) { - return UV_ENOSYS; + *rss = 0; + return 0; } diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h index 89c6eb1..48fe6e8 100644 --- a/Utilities/cmlibuv/src/unix/internal.h +++ b/Utilities/cmlibuv/src/unix/internal.h @@ -137,26 +137,6 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; -/* handle flags */ -enum { - UV_CLOSING = 0x01, /* uv_close() called but not finished. */ - UV_CLOSED = 0x02, /* close(2) finished. */ - UV_STREAM_READING = 0x04, /* uv_read_start() called. */ - UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ - UV_STREAM_SHUT = 0x10, /* Write side closed. */ - UV_STREAM_READABLE = 0x20, /* The stream is readable */ - UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ - UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */ - UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */ - UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */ - UV_TCP_NODELAY = 0x400, /* Disable Nagle. */ - UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */ - UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */ - UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */ - UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */ - UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */ -}; - /* loop flags */ enum { UV_LOOP_BLOCK_SIGPROF = 1 @@ -215,7 +195,6 @@ int uv__nonblock_fcntl(int fd, int set); int uv__close(int fd); /* preserves errno */ int uv__close_nocheckstdio(int fd); int uv__socket(int domain, int type, int protocol); -int uv__dup(int fd); ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags); void uv__make_close_pending(uv_handle_t* handle); int uv__getiovmax(void); @@ -229,6 +208,7 @@ int uv__io_active(const uv__io_t* w, unsigned int events); int uv__io_check_fd(uv_loop_t* loop, int fd); void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */ int uv__io_fork(uv_loop_t* loop); +int uv__fd_exists(uv_loop_t* loop, int fd); /* async */ void uv__async_stop(uv_loop_t* loop); @@ -261,10 +241,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay); /* pipe */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); -/* timer */ -void uv__run_timers(uv_loop_t* loop); -int uv__next_timeout(const uv_loop_t* loop); - /* signal */ void uv__signal_close(uv_signal_t* handle); void uv__signal_global_once_init(void); @@ -289,7 +265,6 @@ void uv__prepare_close(uv_prepare_t* handle); void uv__process_close(uv_process_t* handle); void uv__stream_close(uv_stream_t* handle); void uv__tcp_close(uv_tcp_t* handle); -void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); uv_handle_type uv__handle_type(int fd); @@ -319,24 +294,6 @@ int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); void uv__fsevents_loop_delete(uv_loop_t* loop); -/* OSX < 10.7 has no file events, polyfill them */ -#ifndef MAC_OS_X_VERSION_10_7 - -static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; -static const int kFSEventStreamEventFlagItemCreated = 0x00000100; -static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; -static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; -static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; -static const int kFSEventStreamEventFlagItemModified = 0x00001000; -static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; -static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; -static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; -static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; -static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; -static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; - -#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ - #endif /* defined(__APPLE__) */ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { diff --git a/Utilities/cmlibuv/src/unix/kqueue.c b/Utilities/cmlibuv/src/unix/kqueue.c index a30fd73..c24f96e 100644 --- a/Utilities/cmlibuv/src/unix/kqueue.c +++ b/Utilities/cmlibuv/src/unix/kqueue.c @@ -261,8 +261,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w = loop->watchers[fd]; if (w == NULL) { - /* File descriptor that we've stopped watching, disarm it. */ - /* TODO batch up */ + /* File descriptor that we've stopped watching, disarm it. + * TODO: batch up. */ struct kevent events[1]; EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0); @@ -452,49 +452,48 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { -#if defined(__APPLE__) - struct stat statbuf; -#endif /* defined(__APPLE__) */ int fd; if (uv__is_active(handle)) return UV_EINVAL; - /* TODO open asynchronously - but how do we report back errors? */ - fd = open(path, O_RDONLY); - if (fd == -1) - return UV__ERR(errno); - - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - handle->path = uv__strdup(path); - handle->cb = cb; - #if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop) - goto fallback; - /* Nullify field to perform checks later */ handle->cf_cb = NULL; handle->realpath = NULL; handle->realpath_len = 0; handle->cf_flags = flags; - if (fstat(fd, &statbuf)) - goto fallback; - /* FSEvents works only with directories */ - if (!(statbuf.st_mode & S_IFDIR)) - goto fallback; - - /* The fallback fd is no longer needed */ - uv__close(fd); - handle->event_watcher.fd = -1; - - return uv__fsevents_init(handle); - -fallback: + if (!uv__has_forked_with_cfrunloop) { + int r; + /* The fallback fd is not used */ + handle->event_watcher.fd = -1; + handle->path = uv__strdup(path); + if (handle->path == NULL) + return UV_ENOMEM; + handle->cb = cb; + r = uv__fsevents_init(handle); + if (r == 0) { + uv__handle_start(handle); + } else { + uv__free(handle->path); + handle->path = NULL; + } + return r; + } #endif /* defined(__APPLE__) */ + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return UV__ERR(errno); + + handle->path = uv__strdup(path); + if (handle->path == NULL) + return UV_ENOMEM; + handle->cb = cb; + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; @@ -502,29 +501,29 @@ fallback: int uv_fs_event_stop(uv_fs_event_t* handle) { + int r; + r = 0; + if (!uv__is_active(handle)) return 0; uv__handle_stop(handle); #if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle)) -#endif /* defined(__APPLE__) */ - { - uv__io_close(handle->loop, &handle->event_watcher); - } - - uv__free(handle->path); - handle->path = NULL; + if (!uv__has_forked_with_cfrunloop) + r = uv__fsevents_close(handle); +#endif if (handle->event_watcher.fd != -1) { - /* When FSEvents is used, we don't use the event_watcher's fd under certain - * confitions. (see uv_fs_event_start) */ + uv__io_close(handle->loop, &handle->event_watcher); uv__close(handle->event_watcher.fd); handle->event_watcher.fd = -1; } - return 0; + uv__free(handle->path); + handle->path = NULL; + + return r; } diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c index b63c25f..3341b94 100644 --- a/Utilities/cmlibuv/src/unix/linux-core.c +++ b/Utilities/cmlibuv/src/unix/linux-core.c @@ -20,7 +20,7 @@ /* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their * EPOLL* counterparts. We use the POLL* variants in this file because that - * is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>. + * is what libuv uses elsewhere. */ #include "uv.h" @@ -34,6 +34,7 @@ #include <errno.h> #include <net/if.h> +#include <sys/epoll.h> #include <sys/param.h> #include <sys/prctl.h> #include <sys/sysinfo.h> @@ -51,7 +52,7 @@ #ifdef HAVE_IFADDRS_H # if defined(__ANDROID__) -# include "android-ifaddrs.h" +# include "uv/android-ifaddrs.h" # else # include <ifaddrs.h> # endif @@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum); int uv__platform_loop_init(uv_loop_t* loop) { int fd; - fd = uv__epoll_create1(UV__EPOLL_CLOEXEC); + fd = epoll_create1(EPOLL_CLOEXEC); /* epoll_create1() can fail either because it's not implemented (old kernel) * or because it doesn't understand the EPOLL_CLOEXEC flag. */ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) { - fd = uv__epoll_create(256); + fd = epoll_create(256); if (fd != -1) uv__cloexec(fd, 1); @@ -134,20 +135,20 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event* events; - struct uv__epoll_event dummy; + struct epoll_event* events; + struct epoll_event dummy; uintptr_t i; uintptr_t nfds; assert(loop->watchers != NULL); - events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + events = (struct epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events != NULL) /* Invalidate events with same file descriptor */ for (i = 0; i < nfds; i++) - if ((int) events[i].data == fd) - events[i].data = -1; + if (events[i].data.fd == fd) + events[i].data.fd = -1; /* Remove the file descriptor from the epoll. * This avoids a problem where the same file description remains open @@ -160,25 +161,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings. */ memset(&dummy, 0, sizeof(dummy)); - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy); } } int uv__io_check_fd(uv_loop_t* loop, int fd) { - struct uv__epoll_event e; + struct epoll_event e; int rc; + memset(&e, 0, sizeof(e)); e.events = POLLIN; - e.data = -1; + e.data.fd = -1; rc = 0; - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e)) if (errno != EEXIST) rc = UV__ERR(errno); if (rc == 0) - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e)) abort(); return rc; @@ -195,16 +197,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * that being the largest value I have seen in the wild (and only once.) */ static const int max_safe_timeout = 1789569; - static int no_epoll_pwait; - static int no_epoll_wait; - struct uv__epoll_event events[1024]; - struct uv__epoll_event* pe; - struct uv__epoll_event e; + struct epoll_event events[1024]; + struct epoll_event* pe; + struct epoll_event e; int real_timeout; QUEUE* q; uv__io_t* w; sigset_t sigset; - uint64_t sigmask; + sigset_t* psigset; uint64_t base; int have_signals; int nevents; @@ -219,6 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + memset(&e, 0, sizeof(e)); + while (!QUEUE_EMPTY(&loop->watcher_queue)) { q = QUEUE_HEAD(&loop->watcher_queue); QUEUE_REMOVE(q); @@ -230,35 +232,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd < (int) loop->nwatchers); e.events = w->pevents; - e.data = w->fd; + e.data.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). */ - if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) { + if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e)) abort(); } w->events = w->pevents; } - sigmask = 0; + psigset = NULL; if (loop->flags & UV_LOOP_BLOCK_SIGPROF) { sigemptyset(&sigset); sigaddset(&sigset, SIGPROF); - sigmask |= 1 << (SIGPROF - 1); + psigset = &sigset; } assert(timeout >= -1); @@ -273,30 +275,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout) timeout = max_safe_timeout; - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) - abort(); - - if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) { - nfds = uv__epoll_pwait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout, - sigmask); - if (nfds == -1 && errno == ENOSYS) - no_epoll_pwait = 1; - } else { - nfds = uv__epoll_wait(loop->backend_fd, - events, - ARRAY_SIZE(events), - timeout); - if (nfds == -1 && errno == ENOSYS) - no_epoll_wait = 1; - } - - if (sigmask != 0 && no_epoll_pwait != 0) - if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)) - abort(); + nfds = epoll_pwait(loop->backend_fd, + events, + ARRAY_SIZE(events), + timeout, + psigset); /* Update loop->time unconditionally. It's tempting to skip the update when * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the @@ -317,12 +300,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (nfds == -1) { - if (errno == ENOSYS) { - /* epoll_wait() or epoll_pwait() failed, try the other system call. */ - assert(no_epoll_wait == 0 || no_epoll_pwait == 0); - continue; - } - if (errno != EINTR) abort(); @@ -344,7 +321,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds; for (i = 0; i < nfds; i++) { pe = events + i; - fd = pe->data; + fd = pe->data.fd; /* Skip invalidated events, see uv__platform_invalidate_fd */ if (fd == -1) @@ -361,7 +338,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe); continue; } @@ -388,7 +365,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * free when we switch over to edge-triggered I/O. */ if (pe->events == POLLERR || pe->events == POLLHUP) - pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI); + pe->events |= + w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI); if (pe->events != 0) { /* Run signal watchers last. This also affects child process watchers @@ -851,9 +829,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { return !exclude_type; } -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 + *count = 0; + *addresses = NULL; return UV_ENOSYS; #else struct ifaddrs *addrs, *ent; @@ -861,12 +840,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int i; struct sockaddr_ll *sll; - if (getifaddrs(&addrs)) - return UV__ERR(errno); - *count = 0; *addresses = NULL; + if (getifaddrs(&addrs)) + return UV__ERR(errno); + /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR)) @@ -875,8 +854,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, (*count)++; } - if (*count == 0) + if (*count == 0) { + freeifaddrs(addrs); return 0; + } *addresses = uv__malloc(*count * sizeof(**addresses)); if (!(*addresses)) { @@ -920,6 +901,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, if (strcmp(address->name, ent->ifa_name) == 0) { sll = (struct sockaddr_ll*)ent->ifa_addr; memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr)); + } else { + memset(address->phys_addr, 0, sizeof(address->phys_addr)); } address++; } diff --git a/Utilities/cmlibuv/src/unix/linux-inotify.c b/Utilities/cmlibuv/src/unix/linux-inotify.c index bcad630..9b26202 100644 --- a/Utilities/cmlibuv/src/unix/linux-inotify.c +++ b/Utilities/cmlibuv/src/unix/linux-inotify.c @@ -19,7 +19,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include <stdint.h> @@ -278,6 +278,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* path, unsigned int flags) { struct watcher_list* w; + size_t len; int events; int err; int wd; @@ -306,12 +307,13 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (w) goto no_insert; - w = uv__malloc(sizeof(*w) + strlen(path) + 1); + len = strlen(path) + 1; + w = uv__malloc(sizeof(*w) + len); if (w == NULL) return UV_ENOMEM; w->wd = wd; - w->path = strcpy((char*)(w + 1), path); + w->path = memcpy(w + 1, path, len); QUEUE_INIT(&w->watchers); w->iterating = 0; RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.c b/Utilities/cmlibuv/src/unix/linux-syscalls.c index 89998de..bfd7544 100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.c +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c @@ -77,56 +77,6 @@ # endif #endif /* __NR_eventfd2 */ -#ifndef __NR_epoll_create -# if defined(__x86_64__) -# define __NR_epoll_create 213 -# elif defined(__i386__) -# define __NR_epoll_create 254 -# elif defined(__arm__) -# define __NR_epoll_create (UV_SYSCALL_BASE + 250) -# endif -#endif /* __NR_epoll_create */ - -#ifndef __NR_epoll_create1 -# if defined(__x86_64__) -# define __NR_epoll_create1 291 -# elif defined(__i386__) -# define __NR_epoll_create1 329 -# elif defined(__arm__) -# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357) -# endif -#endif /* __NR_epoll_create1 */ - -#ifndef __NR_epoll_ctl -# if defined(__x86_64__) -# define __NR_epoll_ctl 233 /* used to be 214 */ -# elif defined(__i386__) -# define __NR_epoll_ctl 255 -# elif defined(__arm__) -# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251) -# endif -#endif /* __NR_epoll_ctl */ - -#ifndef __NR_epoll_wait -# if defined(__x86_64__) -# define __NR_epoll_wait 232 /* used to be 215 */ -# elif defined(__i386__) -# define __NR_epoll_wait 256 -# elif defined(__arm__) -# define __NR_epoll_wait (UV_SYSCALL_BASE + 252) -# endif -#endif /* __NR_epoll_wait */ - -#ifndef __NR_epoll_pwait -# if defined(__x86_64__) -# define __NR_epoll_pwait 281 -# elif defined(__i386__) -# define __NR_epoll_pwait 319 -# elif defined(__arm__) -# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346) -# endif -#endif /* __NR_epoll_pwait */ - #ifndef __NR_inotify_init # if defined(__x86_64__) # define __NR_inotify_init 253 @@ -285,76 +235,6 @@ int uv__eventfd2(unsigned int count, int flags) { } -int uv__epoll_create(int size) { -#if defined(__NR_epoll_create) - return syscall(__NR_epoll_create, size); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_create1(int flags) { -#if defined(__NR_epoll_create1) - return syscall(__NR_epoll_create1, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) { -#if defined(__NR_epoll_ctl) - return syscall(__NR_epoll_ctl, epfd, op, fd, events); -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout) { -#if defined(__NR_epoll_wait) - int result; - result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask) { -#if defined(__NR_epoll_pwait) - int result; - result = syscall(__NR_epoll_pwait, - epfd, - events, - nevents, - timeout, - &sigmask, - sizeof(sigmask)); -#if MSAN_ACTIVE - if (result > 0) - __msan_unpoison(events, sizeof(events[0]) * result); -#endif - return result; -#else - return errno = ENOSYS, -1; -#endif -} - - int uv__inotify_init(void) { #if defined(__NR_inotify_init) return syscall(__NR_inotify_init); @@ -431,19 +311,6 @@ int uv__recvmmsg(int fd, } -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags) -{ -#if defined(__NR_utimensat) - return syscall(__NR_utimensat, dirfd, path, times, flags); -#else - return errno = ENOSYS, -1; -#endif -} - - ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_preadv) return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.h b/Utilities/cmlibuv/src/unix/linux-syscalls.h index 4c095e9..3dfd329 100644 --- a/Utilities/cmlibuv/src/unix/linux-syscalls.h +++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h @@ -66,12 +66,6 @@ # define UV__SOCK_NONBLOCK UV__O_NONBLOCK #endif -/* epoll flags */ -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD 1 -#define UV__EPOLL_CTL_DEL 2 -#define UV__EPOLL_CTL_MOD 3 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 @@ -86,18 +80,6 @@ #define UV__IN_DELETE_SELF 0x400 #define UV__IN_MOVE_SELF 0x800 -#if defined(__x86_64__) -struct uv__epoll_event { - uint32_t events; - uint64_t data; -} __attribute__((packed)); -#else -struct uv__epoll_event { - uint32_t events; - uint64_t data; -}; -#endif - struct uv__inotify_event { int32_t wd; uint32_t mask; @@ -113,18 +95,6 @@ struct uv__mmsghdr { int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags); int uv__eventfd(unsigned int count); -int uv__epoll_create(int size); -int uv__epoll_create1(int flags); -int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev); -int uv__epoll_wait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout); -int uv__epoll_pwait(int epfd, - struct uv__epoll_event* events, - int nevents, - int timeout, - uint64_t sigmask); int uv__eventfd2(unsigned int count, int flags); int uv__inotify_init(void); int uv__inotify_init1(int flags); @@ -140,10 +110,6 @@ int uv__sendmmsg(int fd, struct uv__mmsghdr* mmsg, unsigned int vlen, unsigned int flags); -int uv__utimesat(int dirfd, - const char* path, - const struct timespec times[2], - int flags); ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); diff --git a/Utilities/cmlibuv/src/unix/loop.c b/Utilities/cmlibuv/src/unix/loop.c index 99ead6c..c2a03d7 100644 --- a/Utilities/cmlibuv/src/unix/loop.c +++ b/Utilities/cmlibuv/src/unix/loop.c @@ -20,7 +20,7 @@ */ #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "internal.h" #include "heap-inl.h" #include <stdlib.h> @@ -74,7 +74,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_signal_init; uv__handle_unref(&loop->child_watcher); - loop->child_watcher.flags |= UV__HANDLE_INTERNAL; + loop->child_watcher.flags |= UV_HANDLE_INTERNAL; QUEUE_INIT(&loop->process_handles); err = uv_rwlock_init(&loop->cloexec_lock); @@ -90,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_async_init; uv__handle_unref(&loop->wq_async); - loop->wq_async.flags |= UV__HANDLE_INTERNAL; + loop->wq_async.flags |= UV_HANDLE_INTERNAL; return 0; diff --git a/Utilities/cmlibuv/src/unix/netbsd.c b/Utilities/cmlibuv/src/unix/netbsd.c index 2605c11..a2a4e52 100644 --- a/Utilities/cmlibuv/src/unix/netbsd.c +++ b/Utilities/cmlibuv/src/unix/netbsd.c @@ -40,15 +40,6 @@ #include <unistd.h> #include <time.h> -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); @@ -96,7 +87,8 @@ int uv_exepath(char* buffer, size_t* size) { /* Copy string from the intermediate buffer to outer one with appropriate * length. */ - strlcpy(buffer, int_buf, *size); + /* TODO(bnoordhuis) Check uv__strscpy() return value. */ + uv__strscpy(buffer, int_buf, *size); /* Set new size. */ *size = strlen(buffer); @@ -134,65 +126,6 @@ uint64_t uv_get_total_memory(void) { } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_title; - setproctitle("%s", title); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\0'; - - return 0; -} - - int uv_resident_set_memory(size_t* rss) { kvm_t *kd = NULL; struct kinfo_proc2 *kinfo = NULL; diff --git a/Utilities/cmlibuv/src/unix/openbsd.c b/Utilities/cmlibuv/src/unix/openbsd.c index ce937cd..bffb58b 100644 --- a/Utilities/cmlibuv/src/unix/openbsd.c +++ b/Utilities/cmlibuv/src/unix/openbsd.c @@ -36,16 +36,6 @@ #include <unistd.h> -static uv_mutex_t process_title_mutex; -static uv_once_t process_title_mutex_once = UV_ONCE_INIT; -static char *process_title; - - -static void init_process_title_mutex_once(void) { - uv_mutex_init(&process_title_mutex); -} - - int uv__platform_loop_init(uv_loop_t* loop) { return uv__kqueue_init(loop); } @@ -146,65 +136,6 @@ uint64_t uv_get_total_memory(void) { } -char** uv_setup_args(int argc, char** argv) { - process_title = argc ? uv__strdup(argv[0]) : NULL; - return argv; -} - - -int uv_set_process_title(const char* title) { - char* new_title; - - new_title = uv__strdup(title); - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title == NULL) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOMEM; - } - - uv__free(process_title); - process_title = new_title; - setproctitle("%s", title); - - uv_mutex_unlock(&process_title_mutex); - - return 0; -} - - -int uv_get_process_title(char* buffer, size_t size) { - size_t len; - - if (buffer == NULL || size == 0) - return UV_EINVAL; - - uv_once(&process_title_mutex_once, init_process_title_mutex_once); - uv_mutex_lock(&process_title_mutex); - - if (process_title) { - len = strlen(process_title) + 1; - - if (size < len) { - uv_mutex_unlock(&process_title_mutex); - return UV_ENOBUFS; - } - - memcpy(buffer, process_title, len); - } else { - len = 0; - } - - uv_mutex_unlock(&process_title_mutex); - - buffer[len] = '\0'; - - return 0; -} - - int uv_resident_set_memory(size_t* rss) { struct kinfo_proc kinfo; size_t page_size = getpagesize(); diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.c b/Utilities/cmlibuv/src/unix/os390-syscalls.c index a5dd344..1040d66 100644 --- a/Utilities/cmlibuv/src/unix/os390-syscalls.c +++ b/Utilities/cmlibuv/src/unix/os390-syscalls.c @@ -141,7 +141,7 @@ static void init_message_queue(uv__os390_epoll* lst) { } msg; /* initialize message queue */ - lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT); + lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT); if (lst->msg_queue == -1) abort(); @@ -255,12 +255,13 @@ int epoll_ctl(uv__os390_epoll* lst, lst->items[fd].events = event->events; lst->items[fd].revents = 0; } else if (op == EPOLL_CTL_MOD) { - if (fd >= lst->size || lst->items[fd].fd == -1) { + if (fd >= lst->size - 1 || lst->items[fd].fd == -1) { uv_mutex_unlock(&global_epoll_lock); errno = ENOENT; return -1; } lst->items[fd].events = event->events; + lst->items[fd].revents = 0; } else abort(); @@ -275,8 +276,9 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, struct pollfd* pfds; int pollret; int reventcount; + int nevents; - size = _SET_FDS_MSGS(size, 1, lst->size - 1); + _SET_FDS_MSGS(size, 1, lst->size - 1); pfds = lst->items; pollret = poll(pfds, size, timeout); if (pollret <= 0) @@ -285,19 +287,28 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events, pollret = _NFDS(pollret) + _NMSGS(pollret); reventcount = 0; + nevents = 0; for (int i = 0; i < lst->size && i < maxevents && reventcount < pollret; ++i) { struct epoll_event ev; + struct pollfd* pfd; - if (pfds[i].fd == -1 || pfds[i].revents == 0) + pfd = &pfds[i]; + if (pfd->fd == -1 || pfd->revents == 0) continue; - ev.fd = pfds[i].fd; - ev.events = pfds[i].revents; - events[reventcount++] = ev; + ev.fd = pfd->fd; + ev.events = pfd->revents; + if (pfd->revents & POLLIN && pfd->revents & POLLOUT) + reventcount += 2; + else if (pfd->revents & (POLLIN | POLLOUT)) + ++reventcount; + + pfd->revents = 0; + events[nevents++] = ev; } - return reventcount; + return nevents; } @@ -493,7 +504,7 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) { size_t strnlen(const char* str, size_t maxlen) { - void* p = memchr(str, 0, maxlen); + char* p = memchr(str, 0, maxlen); if (p == NULL) return maxlen; else diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.h b/Utilities/cmlibuv/src/unix/os390-syscalls.h index 6e34a88..ea59910 100644 --- a/Utilities/cmlibuv/src/unix/os390-syscalls.h +++ b/Utilities/cmlibuv/src/unix/os390-syscalls.h @@ -36,10 +36,6 @@ #define MAX_ITEMS_PER_EPOLL 1024 #define UV__O_CLOEXEC 0x80000 -#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC -#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD -#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL -#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD struct epoll_event { int events; diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c index f766b39..dc146e3 100644 --- a/Utilities/cmlibuv/src/unix/os390.c +++ b/Utilities/cmlibuv/src/unix/os390.c @@ -229,15 +229,15 @@ static int getexe(const int pid, char* buf, size_t len) { assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A'); /* Get the offset from the lowest 3 bytes */ - Output_path = (char*)(&Output_buf) + - (Output_buf.Output_data.offsetPath & 0x00FFFFFF); + Output_path = (struct Output_path_type*) ((char*) (&Output_buf) + + (Output_buf.Output_data.offsetPath & 0x00FFFFFF)); if (Output_path->len >= len) { errno = ENOBUFS; return -1; } - strncpy(buf, Output_path->path, len); + uv__strscpy(buf, Output_path->path, len); return 0; } @@ -357,13 +357,11 @@ uint64_t uv_get_total_memory(void) { int uv_resident_set_memory(size_t* rss) { - char* psa; char* ascb; char* rax; size_t nframes; - psa = PSA_PTR; - ascb = *(char* __ptr32 *)(psa + PSAAOLD); + ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD); rax = *(char* __ptr32 *)(ascb + ASCBRSME); nframes = *(unsigned int*)(rax + RAXFMCT); @@ -512,7 +510,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses, /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */ address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0; - + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -531,12 +529,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifreq* p; int count_v6; + *count = 0; + *addresses = NULL; + /* get the ipv6 addresses first */ uv_interface_address_t* addresses_v6; uv__interface_addresses_v6(&addresses_v6, &count_v6); /* now get the ipv4 addresses */ - *count = 0; /* Assume maximum buffer size allowable */ maxsize = 16384; @@ -578,6 +578,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } + if (*count == 0) { + uv__close(sockfd); + return 0; + } + /* Alloc the return interface structs */ *addresses = uv__malloc((*count + count_v6) * sizeof(uv_interface_address_t)); @@ -624,6 +629,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0; + memset(address->phys_addr, 0, sizeof(address->phys_addr)); address++; } @@ -662,7 +668,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { /* Remove the file descriptor from the epoll. */ if (loop->ep != NULL) - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy); } @@ -751,7 +757,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok, sizeof(handle->rfis_rftok)); - /* + /* * This call will take "/" as the path argument in case we * don't care to supply the correct path. The system will simply * ignore it. @@ -838,9 +844,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { e.fd = w->fd; if (w->events == 0) - op = UV__EPOLL_CTL_ADD; + op = EPOLL_CTL_ADD; else - op = UV__EPOLL_CTL_MOD; + op = EPOLL_CTL_MOD; /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching * events, skip the syscall and squelch the events after epoll_wait(). @@ -849,10 +855,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (errno != EEXIST) abort(); - assert(op == UV__EPOLL_CTL_ADD); + assert(op == EPOLL_CTL_ADD); /* We've reactivated a file descriptor that's been watched before. */ - if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e)) + if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e)) abort(); } @@ -934,7 +940,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * Ignore all errors because we may be racing with another thread * when the file descriptor is closed. */ - epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe); + epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe); continue; } @@ -987,7 +993,7 @@ void uv__set_process_title(const char* title) { } int uv__io_fork(uv_loop_t* loop) { - /* + /* Nullify the msg queue but don't close it because it is still being used by the parent. */ diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c index 42846b9..9657bc9 100644 --- a/Utilities/cmlibuv/src/unix/pipe.c +++ b/Utilities/cmlibuv/src/unix/pipe.c @@ -64,8 +64,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) { sockfd = err; memset(&saddr, 0, sizeof saddr); - strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1); - saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) { @@ -130,7 +129,20 @@ void uv__pipe_close(uv_pipe_t* handle) { int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { + int flags; + int mode; int err; + flags = 0; + + if (uv__fd_exists(handle->loop, fd)) + return UV_EEXIST; + + do + mode = fcntl(fd, F_GETFL); + while (mode == -1 && errno == EINTR); + + if (mode == -1) + return UV__ERR(errno); /* according to docs, must be EBADF */ err = uv__nonblock(fd, 1); if (err) @@ -142,9 +154,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { return err; #endif /* defined(__APPLE__) */ - return uv__stream_open((uv_stream_t*)handle, - fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + mode &= O_ACCMODE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; + + return uv__stream_open((uv_stream_t*)handle, fd, flags); } @@ -167,8 +183,7 @@ void uv_pipe_connect(uv_connect_t* req, } memset(&saddr, 0, sizeof saddr); - strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1); - saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0'; + uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path)); saddr.sun_family = AF_UNIX; do { @@ -194,7 +209,7 @@ void uv_pipe_connect(uv_connect_t* req, if (new_sock) { err = uv__stream_open((uv_stream_t*)handle, uv__stream_fd(handle), - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } if (err == 0) diff --git a/Utilities/cmlibuv/src/unix/poll.c b/Utilities/cmlibuv/src/unix/poll.c index f3b0bf4..3d5022b 100644 --- a/Utilities/cmlibuv/src/unix/poll.c +++ b/Utilities/cmlibuv/src/unix/poll.c @@ -68,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { int err; + if (uv__fd_exists(loop, fd)) + return UV_EEXIST; + err = uv__io_check_fd(loop, fd); if (err) return err; diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c index f2a5065..e9579f5 100644 --- a/Utilities/cmlibuv/src/unix/process.c +++ b/Utilities/cmlibuv/src/unix/process.c @@ -250,9 +250,9 @@ static int uv__process_open_stream(uv_stdio_container_t* container, flags = 0; if (container->flags & UV_WRITABLE_PIPE) - flags |= UV_STREAM_READABLE; + flags |= UV_HANDLE_READABLE; if (container->flags & UV_READABLE_PIPE) - flags |= UV_STREAM_WRITABLE; + flags |= UV_HANDLE_WRITABLE; return uv__stream_open(container->data.stream, pipefds[0], flags); } diff --git a/Utilities/cmlibuv/src/unix/proctitle.c b/Utilities/cmlibuv/src/unix/proctitle.c index 1a8c7a7..a5ce203 100644 --- a/Utilities/cmlibuv/src/unix/proctitle.c +++ b/Utilities/cmlibuv/src/unix/proctitle.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> +extern void uv__set_process_title_platform_init(void); extern void uv__set_process_title(const char* title); static uv_mutex_t process_title_mutex; @@ -38,6 +39,9 @@ static struct { static void init_process_title_mutex_once(void) { uv_mutex_init(&process_title_mutex); +#ifdef __APPLE__ + uv__set_process_title_platform_init(); +#endif } diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c index b9d0a56..01aa55f 100644 --- a/Utilities/cmlibuv/src/unix/signal.c +++ b/Utilities/cmlibuv/src/unix/signal.c @@ -54,8 +54,7 @@ static void uv__signal_unregister_handler(int signum); static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT; static struct uv__signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree); -static int uv__signal_lock_pipefd[2]; - +static int uv__signal_lock_pipefd[2] = { -1, -1 }; RB_GENERATE_STATIC(uv__signal_tree_s, uv_signal_s, tree_entry, @@ -64,7 +63,7 @@ RB_GENERATE_STATIC(uv__signal_tree_s, static void uv__signal_global_reinit(void); static void uv__signal_global_init(void) { - if (!uv__signal_lock_pipefd[0]) + if (uv__signal_lock_pipefd[0] == -1) /* pthread_atfork can register before and after handlers, one * for each child. This only registers one for the child. That * state is both persistent and cumulative, so if we keep doing @@ -74,15 +73,11 @@ static void uv__signal_global_init(void) { if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit)) abort(); - if (uv__make_pipe(uv__signal_lock_pipefd, 0)) - abort(); - - if (uv__signal_unlock()) - abort(); + uv__signal_global_reinit(); } -static void uv__signal_global_reinit(void) { +UV_DESTRUCTOR(static void uv__signal_global_fini(void)) { /* We can only use signal-safe functions here. * That includes read/write and close, fortunately. * We do all of this directly here instead of resetting @@ -90,11 +85,26 @@ static void uv__signal_global_reinit(void) { * uv__signal_global_once_init is only called from uv_loop_init * and this needs to function in existing loops. */ - uv__close(uv__signal_lock_pipefd[0]); - uv__signal_lock_pipefd[0] = -1; - uv__close(uv__signal_lock_pipefd[1]); - uv__signal_lock_pipefd[1] = -1; - uv__signal_global_init(); + if (uv__signal_lock_pipefd[0] != -1) { + uv__close(uv__signal_lock_pipefd[0]); + uv__signal_lock_pipefd[0] = -1; + } + + if (uv__signal_lock_pipefd[1] != -1) { + uv__close(uv__signal_lock_pipefd[1]); + uv__signal_lock_pipefd[1] = -1; + } +} + + +static void uv__signal_global_reinit(void) { + uv__signal_global_fini(); + + if (uv__make_pipe(uv__signal_lock_pipefd, 0)) + abort(); + + if (uv__signal_unlock()) + abort(); } @@ -103,7 +113,6 @@ void uv__signal_global_once_init(void) { } - static int uv__signal_lock(void) { int r; char data; @@ -387,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle, */ first_handle = uv__signal_first_handle(signum); if (first_handle == NULL || - (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) { + (!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) { err = uv__signal_register_handler(signum, oneshot); if (err) { /* Registering the signal handler failed. Must be an invalid signal. */ @@ -398,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle, handle->signum = signum; if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; + handle->flags |= UV_SIGNAL_ONE_SHOT; RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle); @@ -455,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop, handle = msg->handle; if (msg->signum == handle->signum) { - assert(!(handle->flags & UV_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); handle->signal_cb(handle, handle->signum); } handle->dispatched_signals++; - if (handle->flags & UV__SIGNAL_ONE_SHOT) + if (handle->flags & UV_SIGNAL_ONE_SHOT) uv__signal_stop(handle); /* If uv_close was called while there were caught signals that were not * yet dispatched, the uv__finish_close was deferred. Make close pending * now if this has happened. */ - if ((handle->flags & UV_CLOSING) && + if ((handle->flags & UV_HANDLE_CLOSING) && (handle->caught_signals == handle->dispatched_signals)) { uv__make_close_pending((uv_handle_t*) handle); } @@ -496,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { if (w1->signum < w2->signum) return -1; if (w1->signum > w2->signum) return 1; - /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first + /* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first * handler returned is a one-shot handler, the rest will be too. */ - f1 = w1->flags & UV__SIGNAL_ONE_SHOT; - f2 = w2->flags & UV__SIGNAL_ONE_SHOT; + f1 = w1->flags & UV_SIGNAL_ONE_SHOT; + f2 = w2->flags & UV_SIGNAL_ONE_SHOT; if (f1 < f2) return -1; if (f1 > f2) return 1; @@ -549,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) { if (first_handle == NULL) { uv__signal_unregister_handler(handle->signum); } else { - rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT; - first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT; + rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT; + first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT; if (first_oneshot && !rem_oneshot) { ret = uv__signal_register_handler(handle->signum, 1); assert(ret == 0); diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c index 9bdd1c5..4b9123f 100644 --- a/Utilities/cmlibuv/src/unix/stream.c +++ b/Utilities/cmlibuv/src/unix/stream.c @@ -58,11 +58,19 @@ struct uv__stream_select_s { fd_set* swrite; size_t swrite_sz; }; -# define WRITE_RETRY_ON_ERROR(send_handle) \ + +/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ - (errno == EMSGSIZE && send_handle)) + (errno == EMSGSIZE && send_handle != NULL)) #else -# define WRITE_RETRY_ON_ERROR(send_handle) \ +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) #endif /* defined(__APPLE__) */ @@ -220,7 +228,7 @@ static void uv__stream_osx_select(void* arg) { uv_sem_wait(&s->async_sem); /* Should be processed at this stage */ - assert((s->events == 0) || (stream->flags & UV_CLOSING)); + assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING)); } } } @@ -248,7 +256,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); - if (stream->flags & UV_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return; /* NOTE: It is important to do it here, otherwise `select()` might be called @@ -342,7 +350,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) { if (err) goto failed_async_init; - s->async.flags |= UV__HANDLE_INTERNAL; + s->async.flags |= UV_HANDLE_INTERNAL; uv__handle_unref(&s->async); err = uv_sem_init(&s->close_sem, 0); @@ -407,12 +415,14 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { stream->flags |= flags; if (stream->type == UV_TCP) { - if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) + if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1)) return UV__ERR(errno); /* TODO Use delay the user passed in. */ - if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60)) + if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) && + uv__tcp_keepalive(fd, 1, 60)) { return UV__ERR(errno); + } } #if defined(__APPLE__) @@ -447,7 +457,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); - assert(stream->flags & UV_CLOSED); + assert(stream->flags & UV_HANDLE_CLOSED); if (stream->connect_req) { uv__req_unregister(stream->loop, stream->connect_req); @@ -522,7 +532,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { stream = container_of(w, uv_stream_t, io_watcher); assert(events & POLLIN); assert(stream->accepted_fd == -1); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); uv__io_start(stream->loop, &stream->io_watcher, POLLIN); @@ -565,7 +575,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { return; } - if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) { + if (stream->type == UV_TCP && + (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) { /* Give other processes a chance to accept connections. */ struct timespec timeout = { 0, 1 }; nanosleep(&timeout, NULL); @@ -590,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { case UV_TCP: err = uv__stream_open(client, server->accepted_fd, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) { /* TODO handle error */ uv__close(server->accepted_fd); @@ -674,14 +685,14 @@ static void uv__drain(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); /* Shutdown? */ - if ((stream->flags & UV_STREAM_SHUTTING) && - !(stream->flags & UV_CLOSING) && - !(stream->flags & UV_STREAM_SHUT)) { + if ((stream->flags & UV_HANDLE_SHUTTING) && + !(stream->flags & UV_HANDLE_CLOSING) && + !(stream->flags & UV_HANDLE_SHUT)) { assert(stream->shutdown_req); req = stream->shutdown_req; stream->shutdown_req = NULL; - stream->flags &= ~UV_STREAM_SHUTTING; + stream->flags &= ~UV_HANDLE_SHUTTING; uv__req_unregister(stream->loop, req); err = 0; @@ -689,7 +700,7 @@ static void uv__drain(uv_stream_t* stream) { err = UV__ERR(errno); if (err == 0) - stream->flags |= UV_STREAM_SHUT; + stream->flags |= UV_HANDLE_SHUT; if (req->cb != NULL) req->cb(req, err); @@ -697,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) { } +static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) { + if (n == 1) + return write(fd, vec->iov_base, vec->iov_len); + else + return writev(fd, vec, n); +} + + static size_t uv__write_req_size(uv_write_t* req) { size_t size; @@ -709,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) { } +/* Returns 1 if all write request data has been written, or 0 if there is still + * more data to write. + * + * Note: the return value only says something about the *current* request. + * There may still be other write requests sitting in the queue. + */ +static int uv__write_req_update(uv_stream_t* stream, + uv_write_t* req, + size_t n) { + uv_buf_t* buf; + size_t len; + + assert(n <= stream->write_queue_size); + stream->write_queue_size -= n; + + buf = req->bufs + req->write_index; + + while (n > 0) { + len = n < buf->len ? n : buf->len; + buf->base += len; + buf->len -= len; + buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ + n -= len; + } + + req->write_index = buf - req->bufs; + + return req->write_index == req->nbufs; +} + + static void uv__write_req_finish(uv_write_t* req) { uv_stream_t* stream = req->handle; @@ -829,102 +879,32 @@ start: *pi = fd_to_send; } - do { + do n = sendmsg(uv__stream_fd(stream), &msg, 0); - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } else { - do { - if (iovcnt == 1) { - n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); - } else { - n = writev(uv__stream_fd(stream), iov, iovcnt); - } - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); - if (n < 0) { - if (!WRITE_RETRY_ON_ERROR(req->send_handle)) { - err = UV__ERR(errno); - goto error; - } else if (stream->flags & UV_STREAM_BLOCKING) { - /* If this is a blocking stream, try again. */ - goto start; - } + /* Ensure the handle isn't sent again in case this is a partial write. */ + if (n >= 0) + req->send_handle = NULL; } else { - /* Successful write */ - - while (n >= 0) { - uv_buf_t* buf = &(req->bufs[req->write_index]); - size_t len = buf->len; - - assert(req->write_index < req->nbufs); - - if ((size_t)n < len) { - buf->base += n; - buf->len -= n; - stream->write_queue_size -= n; - n = 0; - - /* There is more to write. */ - if (stream->flags & UV_STREAM_BLOCKING) { - /* - * If we're blocking then we should not be enabling the write - * watcher - instead we need to try again. - */ - goto start; - } else { - /* Break loop and ensure the watcher is pending. */ - break; - } - - } else { - /* Finished writing the buf at index req->write_index. */ - req->write_index++; - - assert((size_t)n >= len); - n -= len; - - assert(stream->write_queue_size >= len); - stream->write_queue_size -= len; + do + n = uv__writev(uv__stream_fd(stream), iov, iovcnt); + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); + } - if (req->write_index == req->nbufs) { - /* Then we're done! */ - assert(n == 0); - uv__write_req_finish(req); - /* TODO: start trying to write the next request. */ - return; - } - } - } + if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) { + err = UV__ERR(errno); + goto error; } - /* Either we've counted n down to zero or we've got EAGAIN. */ - assert(n == 0 || n == -1); + if (n > 0 && uv__write_req_update(stream, req, n)) { + uv__write_req_finish(req); + return; /* TODO(bnoordhuis) Start trying to write the next request. */ + } - /* Only non-blocking streams should use the write_watcher. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + /* If this is a blocking stream, try again. */ + if (stream->flags & UV_HANDLE_BLOCKING_WRITES) + goto start; /* We're not done. */ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); @@ -947,10 +927,16 @@ error: static void uv__write_callbacks(uv_stream_t* stream) { uv_write_t* req; QUEUE* q; + QUEUE pq; + + if (QUEUE_EMPTY(&stream->write_completed_queue)) + return; + + QUEUE_MOVE(&stream->write_completed_queue, &pq); - while (!QUEUE_EMPTY(&stream->write_completed_queue)) { + while (!QUEUE_EMPTY(&pq)) { /* Pop a req off write_completed_queue. */ - q = QUEUE_HEAD(&stream->write_completed_queue); + q = QUEUE_HEAD(&pq); req = QUEUE_DATA(q, uv_write_t, queue); QUEUE_REMOVE(q); uv__req_unregister(stream->loop, req); @@ -966,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) { if (req->cb) req->cb(req, req->error); } - - assert(QUEUE_EMPTY(&stream->write_completed_queue)); } @@ -1015,13 +999,13 @@ uv_handle_type uv__handle_type(int fd) { static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { - stream->flags |= UV_STREAM_READ_EOF; + stream->flags |= UV_HANDLE_READ_EOF; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; } @@ -1121,6 +1105,7 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wgnu-folding-constant" +# pragma clang diagnostic ignored "-Wvla-extension" #endif static void uv__read(uv_stream_t* stream) { @@ -1132,7 +1117,7 @@ static void uv__read(uv_stream_t* stream) { int err; int is_ipc; - stream->flags &= ~UV_STREAM_READ_PARTIAL; + stream->flags &= ~UV_HANDLE_READ_PARTIAL; /* Prevent loop starvation when the data comes in as fast as (or faster than) * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. @@ -1141,11 +1126,11 @@ static void uv__read(uv_stream_t* stream) { is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; - /* XXX: Maybe instead of having UV_STREAM_READING we just test if + /* XXX: Maybe instead of having UV_HANDLE_READING we just test if * tcp->read_cb is NULL or not? */ while (stream->read_cb - && (stream->flags & UV_STREAM_READING) + && (stream->flags & UV_HANDLE_READING) && (count-- > 0)) { assert(stream->alloc_cb != NULL); @@ -1186,7 +1171,7 @@ static void uv__read(uv_stream_t* stream) { /* Error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ - if (stream->flags & UV_STREAM_READING) { + if (stream->flags & UV_HANDLE_READING) { uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } @@ -1199,8 +1184,8 @@ static void uv__read(uv_stream_t* stream) { } else { /* Error. User should call uv_close(). */ stream->read_cb(stream, UV__ERR(errno), &buf); - if (stream->flags & UV_STREAM_READING) { - stream->flags &= ~UV_STREAM_READING; + if (stream->flags & UV_HANDLE_READING) { + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1250,7 +1235,7 @@ static void uv__read(uv_stream_t* stream) { /* Return if we didn't fill the buffer, there is no more data to read. */ if (nread < buflen) { - stream->flags |= UV_STREAM_READ_PARTIAL; + stream->flags |= UV_HANDLE_READ_PARTIAL; return; } } @@ -1271,9 +1256,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->type == UV_TTY || stream->type == UV_NAMED_PIPE); - if (!(stream->flags & UV_STREAM_WRITABLE) || - stream->flags & UV_STREAM_SHUT || - stream->flags & UV_STREAM_SHUTTING || + if (!(stream->flags & UV_HANDLE_WRITABLE) || + stream->flags & UV_HANDLE_SHUT || + stream->flags & UV_HANDLE_SHUTTING || uv__is_closing(stream)) { return UV_ENOTCONN; } @@ -1285,7 +1270,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - stream->flags |= UV_STREAM_SHUTTING; + stream->flags |= UV_HANDLE_SHUTTING; uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); @@ -1302,7 +1287,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - assert(!(stream->flags & UV_CLOSING)); + assert(!(stream->flags & UV_HANDLE_CLOSING)); if (stream->connect_req) { uv__stream_connect(stream); @@ -1311,7 +1296,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); - /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ + /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */ if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); @@ -1325,9 +1310,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * report the EOF yet because there is still data to read. */ if ((events & POLLHUP) && - (stream->flags & UV_STREAM_READING) && - (stream->flags & UV_STREAM_READ_PARTIAL) && - !(stream->flags & UV_STREAM_READ_EOF)) { + (stream->flags & UV_HANDLE_READING) && + (stream->flags & UV_HANDLE_READ_PARTIAL) && + !(stream->flags & UV_HANDLE_READ_EOF)) { uv_buf_t buf = { NULL, 0 }; uv__stream_eof(stream, &buf); } @@ -1417,7 +1402,7 @@ int uv_write2(uv_write_t* req, if (uv__stream_fd(stream) < 0) return UV_EBADF; - if (!(stream->flags & UV_STREAM_WRITABLE)) + if (!(stream->flags & UV_HANDLE_WRITABLE)) return -EPIPE; if (send_handle) { @@ -1487,7 +1472,7 @@ int uv_write2(uv_write_t* req, * if this assert fires then somehow the blocking stream isn't being * sufficiently flushed in uv__write. */ - assert(!(stream->flags & UV_STREAM_BLOCKING)); + assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1568,16 +1553,16 @@ int uv_read_start(uv_stream_t* stream, assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); - if (stream->flags & UV_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return UV_EINVAL; - if (!(stream->flags & UV_STREAM_READABLE)) + if (!(stream->flags & UV_HANDLE_READABLE)) return -ENOTCONN; - /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just + /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ - stream->flags |= UV_STREAM_READING; + stream->flags |= UV_HANDLE_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should @@ -1598,10 +1583,10 @@ int uv_read_start(uv_stream_t* stream, int uv_read_stop(uv_stream_t* stream) { - if (!(stream->flags & UV_STREAM_READING)) + if (!(stream->flags & UV_HANDLE_READING)) return 0; - stream->flags &= ~UV_STREAM_READING; + stream->flags &= ~UV_HANDLE_READING; uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); @@ -1614,12 +1599,12 @@ int uv_read_stop(uv_stream_t* stream) { int uv_is_readable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_READABLE); + return !!(stream->flags & UV_HANDLE_READABLE); } int uv_is_writable(const uv_stream_t* stream) { - return !!(stream->flags & UV_STREAM_WRITABLE); + return !!(stream->flags & UV_HANDLE_WRITABLE); } @@ -1668,6 +1653,7 @@ void uv__stream_close(uv_stream_t* handle) { uv__io_close(handle->loop, &handle->io_watcher); uv_read_stop(handle); uv__handle_stop(handle); + handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (handle->io_watcher.fd != -1) { /* Don't close stdio file descriptors. Nothing good comes from it. */ diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c index b92888e..aac6504 100644 --- a/Utilities/cmlibuv/src/unix/sunos.c +++ b/Utilities/cmlibuv/src/unix/sunos.c @@ -696,6 +696,8 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) { #ifdef SUNOS_NO_IFADDRS int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { + *count = 0; + *addresses = NULL; return UV_ENOSYS; } #else /* SUNOS_NO_IFADDRS */ @@ -709,13 +711,14 @@ static int uv__set_phys_addr(uv_interface_address_t* address, struct sockaddr_dl* sa_addr; int sockfd; - int i; + size_t i; struct arpreq arpreq; /* This appears to only work as root */ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr); memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr)); for (i = 0; i < sizeof(address->phys_addr); i++) { + /* Check that all bytes of phys_addr are zero. */ if (address->phys_addr[i] != 0) return 0; } @@ -762,11 +765,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { struct ifaddrs* addrs; struct ifaddrs* ent; + *count = 0; + *addresses = NULL; + if (getifaddrs(&addrs)) return UV__ERR(errno); - *count = 0; - /* Count the number of interfaces */ for (ent = addrs; ent != NULL; ent = ent->ifa_next) { if (uv__ifaddr_exclude(ent)) @@ -774,6 +778,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { (*count)++; } + if (*count == 0) { + freeifaddrs(addrs); + return 0; + } + *addresses = uv__malloc(*count * sizeof(**addresses)); if (!(*addresses)) { freeifaddrs(addrs); diff --git a/Utilities/cmlibuv/src/unix/tcp.c b/Utilities/cmlibuv/src/unix/tcp.c index 9a46793..2982851 100644 --- a/Utilities/cmlibuv/src/unix/tcp.c +++ b/Utilities/cmlibuv/src/unix/tcp.c @@ -216,7 +216,7 @@ int uv__tcp_connect(uv_connect_t* req, err = maybe_new_socket(handle, addr->sa_family, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); if (err) return err; @@ -263,13 +263,16 @@ int uv__tcp_connect(uv_connect_t* req, int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) { int err; + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; + err = uv__nonblock(sock, 1); if (err) return err; return uv__stream_open((uv_stream_t*)handle, sock, - UV_STREAM_READABLE | UV_STREAM_WRITABLE); + UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); } @@ -331,7 +334,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { } if (single_accept) - tcp->flags |= UV_TCP_SINGLE_ACCEPT; + tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; flags = 0; #if defined(__MVS__) @@ -398,9 +401,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) { } if (on) - handle->flags |= UV_TCP_NODELAY; + handle->flags |= UV_HANDLE_TCP_NODELAY; else - handle->flags &= ~UV_TCP_NODELAY; + handle->flags &= ~UV_HANDLE_TCP_NODELAY; return 0; } @@ -416,9 +419,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { } if (on) - handle->flags |= UV_TCP_KEEPALIVE; + handle->flags |= UV_HANDLE_TCP_KEEPALIVE; else - handle->flags &= ~UV_TCP_KEEPALIVE; + handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge * uv_tcp_t with an int that's almost never used... @@ -430,9 +433,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (enable) - handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT; else - handle->flags |= UV_TCP_SINGLE_ACCEPT; + handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT; return 0; } diff --git a/Utilities/cmlibuv/src/unix/thread.c b/Utilities/cmlibuv/src/unix/thread.c index 303bc6e..2900470 100644 --- a/Utilities/cmlibuv/src/unix/thread.c +++ b/Utilities/cmlibuv/src/unix/thread.c @@ -44,108 +44,119 @@ #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) +#if defined(PTHREAD_BARRIER_SERIAL_THREAD) +STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); +#endif -#if defined(UV__PTHREAD_BARRIER_FALLBACK) -/* TODO: support barrier_attr */ -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { +/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */ +#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + struct _uv_barrier* b; int rc; - _uv_barrier* b; if (barrier == NULL || count == 0) - return EINVAL; - - if (barrier_attr != NULL) - return ENOTSUP; + return UV_EINVAL; b = uv__malloc(sizeof(*b)); if (b == NULL) - return ENOMEM; + return UV_ENOMEM; b->in = 0; b->out = 0; b->threshold = count; - if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + rc = uv_mutex_init(&b->mutex); + if (rc != 0) goto error2; - if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + + rc = uv_cond_init(&b->cond); + if (rc != 0) goto error; barrier->b = b; return 0; error: - pthread_mutex_destroy(&b->mutex); + uv_mutex_destroy(&b->mutex); error2: uv__free(b); return rc; } -int pthread_barrier_wait(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; + +int uv_barrier_wait(uv_barrier_t* barrier) { + struct _uv_barrier* b; + int last; if (barrier == NULL || barrier->b == NULL) - return EINVAL; + return UV_EINVAL; b = barrier->b; - /* Lock the mutex*/ - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; + uv_mutex_lock(&b->mutex); - /* Increment the count. If this is the first thread to reach the threshold, - wake up waiters, unlock the mutex, then return - PTHREAD_BARRIER_SERIAL_THREAD. */ if (++b->in == b->threshold) { b->in = 0; - b->out = b->threshold - 1; - rc = pthread_cond_signal(&b->cond); - assert(rc == 0); - - pthread_mutex_unlock(&b->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; + b->out = b->threshold; + uv_cond_signal(&b->cond); + } else { + do + uv_cond_wait(&b->cond, &b->mutex); + while (b->in != 0); } - /* Otherwise, wait for other threads until in is set to 0, - then return 0 to indicate this is not the first thread. */ - do { - if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) - break; - } while (b->in != 0); - - /* mark thread exit */ - b->out--; - pthread_cond_signal(&b->cond); - pthread_mutex_unlock(&b->mutex); - return rc; + + last = (--b->out == 0); + if (!last) + uv_cond_signal(&b->cond); /* Not needed for last thread. */ + + uv_mutex_unlock(&b->mutex); + return last; } -int pthread_barrier_destroy(pthread_barrier_t* barrier) { - int rc; - _uv_barrier* b; - if (barrier == NULL || barrier->b == NULL) - return EINVAL; +void uv_barrier_destroy(uv_barrier_t* barrier) { + struct _uv_barrier* b; b = barrier->b; + uv_mutex_lock(&b->mutex); - if ((rc = pthread_mutex_lock(&b->mutex)) != 0) - return rc; + assert(b->in == 0); + assert(b->out == 0); - if (b->in > 0 || b->out > 0) - rc = EBUSY; - - pthread_mutex_unlock(&b->mutex); + if (b->in != 0 || b->out != 0) + abort(); - if (rc) - return rc; + uv_mutex_unlock(&b->mutex); + uv_mutex_destroy(&b->mutex); + uv_cond_destroy(&b->cond); - pthread_cond_destroy(&b->cond); - pthread_mutex_destroy(&b->mutex); uv__free(barrier->b); barrier->b = NULL; - return 0; } + +#else + +int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { + return UV__ERR(pthread_barrier_init(barrier, NULL, count)); +} + + +int uv_barrier_wait(uv_barrier_t* barrier) { + int rc; + + rc = pthread_barrier_wait(barrier); + if (rc != 0) + if (rc != PTHREAD_BARRIER_SERIAL_THREAD) + abort(); + + return rc == PTHREAD_BARRIER_SERIAL_THREAD; +} + + +void uv_barrier_destroy(uv_barrier_t* barrier) { + if (pthread_barrier_destroy(barrier)) + abort(); +} + #endif @@ -771,25 +782,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - return UV__ERR(pthread_barrier_init(barrier, NULL, count)); -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - if (pthread_barrier_destroy(barrier)) - abort(); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int r = pthread_barrier_wait(barrier); - if (r && r != PTHREAD_BARRIER_SERIAL_THREAD) - abort(); - return r == PTHREAD_BARRIER_SERIAL_THREAD; -} - - int uv_key_create(uv_key_t* key) { return UV__ERR(pthread_key_create(key, NULL)); } diff --git a/Utilities/cmlibuv/src/unix/tty.c b/Utilities/cmlibuv/src/unix/tty.c index e8ea302..b8bc283 100644 --- a/Utilities/cmlibuv/src/unix/tty.c +++ b/Utilities/cmlibuv/src/unix/tty.c @@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) { return result; } -int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) { uv_handle_type type; int flags = 0; int newfd = -1; int r; int saved_flags; + int mode; char path[256]; + (void)unused; /* deprecated parameter is no longer needed */ /* File descriptors that refer to files cannot be monitored with epoll. * That restriction also applies to character devices like /dev/random @@ -108,6 +110,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { if (type == UV_FILE || type == UV_UNKNOWN_HANDLE) return UV_EINVAL; + /* Save the fd flags in case we need to restore them due to an error. */ + do + saved_flags = fcntl(fd, F_GETFL); + while (saved_flags == -1 && errno == EINTR); + + if (saved_flags == -1) + return UV__ERR(errno); + mode = saved_flags & O_ACCMODE; + /* Reopen the file descriptor when it refers to a tty. This lets us put the * tty in non-blocking mode without affecting other processes that share it * with us. @@ -125,14 +136,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { * slave device. */ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0) - r = uv__open_cloexec(path, O_RDWR); + r = uv__open_cloexec(path, mode); else r = -1; if (r < 0) { /* fallback to using blocking writes */ - if (!readable) - flags |= UV_STREAM_BLOCKING; + if (mode != O_RDONLY) + flags |= UV_HANDLE_BLOCKING_WRITES; goto skip; } @@ -151,22 +162,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { fd = newfd; } -#if defined(__APPLE__) - /* Save the fd flags in case we need to restore them due to an error. */ - do - saved_flags = fcntl(fd, F_GETFL); - while (saved_flags == -1 && errno == EINTR); - - if (saved_flags == -1) { - if (newfd != -1) - uv__close(newfd); - return UV__ERR(errno); - } -#endif - - /* Pacify the compiler. */ - (void) &saved_flags; - skip: uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); @@ -174,7 +169,7 @@ skip: * the handle queue, since it was added by uv__handle_init in uv_stream_init. */ - if (!(flags & UV_STREAM_BLOCKING)) + if (!(flags & UV_HANDLE_BLOCKING_WRITES)) uv__nonblock(fd, 1); #if defined(__APPLE__) @@ -191,10 +186,10 @@ skip: } #endif - if (readable) - flags |= UV_STREAM_READABLE; - else - flags |= UV_STREAM_WRITABLE; + if (mode != O_WRONLY) + flags |= UV_HANDLE_READABLE; + if (mode != O_RDONLY) + flags |= UV_HANDLE_WRITABLE; uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = UV_TTY_MODE_NORMAL; diff --git a/Utilities/cmlibuv/src/unix/udp.c b/Utilities/cmlibuv/src/unix/udp.c index 74d613b..ec337ec 100644 --- a/Utilities/cmlibuv/src/unix/udp.c +++ b/Utilities/cmlibuv/src/unix/udp.c @@ -92,8 +92,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!(handle->flags & UV_UDP_PROCESSING)); - handle->flags |= UV_UDP_PROCESSING; + assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING)); + handle->flags |= UV_HANDLE_UDP_PROCESSING; while (!QUEUE_EMPTY(&handle->write_completed_queue)) { q = QUEUE_HEAD(&handle->write_completed_queue); @@ -128,7 +128,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) { uv__handle_stop(handle); } - handle->flags &= ~UV_UDP_PROCESSING; + handle->flags &= ~UV_HANDLE_UDP_PROCESSING; } @@ -427,7 +427,7 @@ int uv__udp_send(uv_udp_send_t* req, QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue); uv__handle_start(handle); - if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { + if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) { uv__udp_sendmsg(handle); /* `uv__udp_sendmsg` may not be able to do non-blocking write straight @@ -624,6 +624,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { if (handle->io_watcher.fd != -1) return UV_EBUSY; + if (uv__fd_exists(handle->loop, sock)) + return UV_EEXIST; + err = uv__nonblock(sock, 1); if (err) return err; @@ -757,14 +760,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -780,14 +785,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP, &on, sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) || + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, diff --git a/Utilities/cmlibuv/src/uv-common.c b/Utilities/cmlibuv/src/uv-common.c index 15dec08..907ebf2 100644 --- a/Utilities/cmlibuv/src/uv-common.c +++ b/Utilities/cmlibuv/src/uv-common.c @@ -72,7 +72,9 @@ char* uv__strndup(const char* s, size_t n) { } void* uv__malloc(size_t size) { - return uv__allocator.local_malloc(size); + if (size > 0) + return uv__allocator.local_malloc(size); + return NULL; } void uv__free(void* ptr) { @@ -91,7 +93,10 @@ void* uv__calloc(size_t count, size_t size) { } void* uv__realloc(void* ptr, size_t size) { - return uv__allocator.local_realloc(ptr, size); + if (size > 0) + return uv__allocator.local_realloc(ptr, size); + uv__free(ptr); + return NULL; } int uv_replace_allocator(uv_malloc_func malloc_func, @@ -155,6 +160,18 @@ static const char* uv__unknown_err_code(int err) { return copy != NULL ? copy : "Unknown system error"; } +#define UV_ERR_NAME_GEN_R(name, _) \ +case UV_## name: \ + uv__strscpy(buf, #name, buflen); break; +char* uv_err_name_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_ERR_NAME_GEN_R + #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; const char* uv_err_name(int err) { @@ -166,6 +183,19 @@ const char* uv_err_name(int err) { #undef UV_ERR_NAME_GEN +#define UV_STRERROR_GEN_R(name, msg) \ +case UV_ ## name: \ + snprintf(buf, buflen, "%s", msg); break; +char* uv_strerror_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_STRERROR_GEN_R + + #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; const char* uv_strerror(int err) { switch (err) { @@ -359,7 +389,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { QUEUE_REMOVE(q); QUEUE_INSERT_TAIL(&loop->handle_queue, q); - if (h->flags & UV__HANDLE_INTERNAL) continue; + if (h->flags & UV_HANDLE_INTERNAL) continue; walk_cb(h, arg); } } @@ -388,9 +418,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { fprintf(stream, "[%c%c%c] %-8s %p\n", - "R-"[!(h->flags & UV__HANDLE_REF)], - "A-"[!(h->flags & UV__HANDLE_ACTIVE)], - "I-"[!(h->flags & UV__HANDLE_INTERNAL)], + "R-"[!(h->flags & UV_HANDLE_REF)], + "A-"[!(h->flags & UV_HANDLE_ACTIVE)], + "I-"[!(h->flags & UV_HANDLE_INTERNAL)], type, (void*)h); } @@ -634,7 +664,7 @@ int uv_loop_close(uv_loop_t* loop) { QUEUE_FOREACH(q, &loop->handle_queue) { h = QUEUE_DATA(q, uv_handle_t, handle_queue); - if (!(h->flags & UV__HANDLE_INTERNAL)) + if (!(h->flags & UV_HANDLE_INTERNAL)) return UV_EBUSY; } diff --git a/Utilities/cmlibuv/src/uv-common.h b/Utilities/cmlibuv/src/uv-common.h index c497d01..15ac4d0 100644 --- a/Utilities/cmlibuv/src/uv-common.h +++ b/Utilities/cmlibuv/src/uv-common.h @@ -32,14 +32,15 @@ #include <stddef.h> #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include <stdint.h> #endif #include "uv.h" -#include "tree.h" +#include "uv/tree.h" #include "queue.h" +#include "strscpy.h" #if EDOM > 0 # define UV__ERR(x) (-(x)) @@ -59,22 +60,67 @@ extern int snprintf(char*, size_t, const char*, ...); #define STATIC_ASSERT(expr) \ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) -#ifndef _WIN32 +/* Handle flags. Some flags are specific to Windows or UNIX. */ enum { - UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */ - UV__HANDLE_INTERNAL = 0x8000, - UV__HANDLE_ACTIVE = 0x4000, - UV__HANDLE_REF = 0x2000, - UV__HANDLE_CLOSING = 0 /* no-op on unix */ + /* Used by all handles. */ + UV_HANDLE_CLOSING = 0x00000001, + UV_HANDLE_CLOSED = 0x00000002, + UV_HANDLE_ACTIVE = 0x00000004, + UV_HANDLE_REF = 0x00000008, + UV_HANDLE_INTERNAL = 0x00000010, + UV_HANDLE_ENDGAME_QUEUED = 0x00000020, + + /* Used by streams. */ + UV_HANDLE_LISTENING = 0x00000040, + UV_HANDLE_CONNECTION = 0x00000080, + UV_HANDLE_SHUTTING = 0x00000100, + UV_HANDLE_SHUT = 0x00000200, + UV_HANDLE_READ_PARTIAL = 0x00000400, + UV_HANDLE_READ_EOF = 0x00000800, + + /* Used by streams and UDP handles. */ + UV_HANDLE_READING = 0x00001000, + UV_HANDLE_BOUND = 0x00002000, + UV_HANDLE_READABLE = 0x00004000, + UV_HANDLE_WRITABLE = 0x00008000, + UV_HANDLE_READ_PENDING = 0x00010000, + UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000, + UV_HANDLE_ZERO_READ = 0x00040000, + UV_HANDLE_EMULATE_IOCP = 0x00080000, + UV_HANDLE_BLOCKING_WRITES = 0x00100000, + UV_HANDLE_CANCELLATION_PENDING = 0x00200000, + + /* Used by uv_tcp_t and uv_udp_t handles */ + UV_HANDLE_IPV6 = 0x00400000, + + /* Only used by uv_tcp_t handles. */ + UV_HANDLE_TCP_NODELAY = 0x01000000, + UV_HANDLE_TCP_KEEPALIVE = 0x02000000, + UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000, + UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000, + UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000, + UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000, + + /* Only used by uv_udp_t handles. */ + UV_HANDLE_UDP_PROCESSING = 0x01000000, + + /* Only used by uv_pipe_t handles. */ + UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000, + UV_HANDLE_PIPESERVER = 0x02000000, + + /* Only used by uv_tty_t handles. */ + UV_HANDLE_TTY_READABLE = 0x01000000, + UV_HANDLE_TTY_RAW = 0x02000000, + UV_HANDLE_TTY_SAVED_POSITION = 0x04000000, + UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000, + + /* Only used by uv_signal_t handles. */ + UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000, + UV_SIGNAL_ONE_SHOT = 0x02000000, + + /* Only used by uv_poll_t handles. */ + UV_HANDLE_POLL_SLOW = 0x01000000 }; -#else -# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200 -# define UV__SIGNAL_ONE_SHOT 0x100 -# define UV__HANDLE_INTERNAL 0x80 -# define UV__HANDLE_ACTIVE 0x40 -# define UV__HANDLE_REF 0x20 -# define UV__HANDLE_CLOSING 0x01 -#endif int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap); @@ -119,8 +165,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle); int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */ +enum uv__work_kind { + UV__WORK_CPU, + UV__WORK_FAST_IO, + UV__WORK_SLOW_IO +}; + void uv__work_submit(uv_loop_t* loop, struct uv__work *w, + enum uv__work_kind kind, void (*work)(struct uv__work *w), void (*done)(struct uv__work *w, int status)); @@ -132,6 +185,10 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value); void uv__fs_scandir_cleanup(uv_fs_t* req); +int uv__next_timeout(const uv_loop_t* loop); +void uv__run_timers(uv_loop_t* loop); +void uv__timer_close(uv_timer_t* handle); + #define uv__has_active_reqs(loop) \ ((loop)->active_reqs.count > 0) @@ -164,49 +221,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req); while (0) #define uv__is_active(h) \ - (((h)->flags & UV__HANDLE_ACTIVE) != 0) + (((h)->flags & UV_HANDLE_ACTIVE) != 0) #define uv__is_closing(h) \ - (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0) #define uv__handle_start(h) \ do { \ - assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \ - (h)->flags |= UV__HANDLE_ACTIVE; \ - if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \ + (h)->flags |= UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \ } \ while (0) #define uv__handle_stop(h) \ do { \ - assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ - if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \ - (h)->flags &= ~UV__HANDLE_ACTIVE; \ - if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \ + if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \ + (h)->flags &= ~UV_HANDLE_ACTIVE; \ + if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \ } \ while (0) #define uv__handle_ref(h) \ do { \ - if (((h)->flags & UV__HANDLE_REF) != 0) break; \ - (h)->flags |= UV__HANDLE_REF; \ - if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ + if (((h)->flags & UV_HANDLE_REF) != 0) break; \ + (h)->flags |= UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \ } \ while (0) #define uv__handle_unref(h) \ do { \ - if (((h)->flags & UV__HANDLE_REF) == 0) break; \ - (h)->flags &= ~UV__HANDLE_REF; \ - if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \ - if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ + if (((h)->flags & UV_HANDLE_REF) == 0) break; \ + (h)->flags &= ~UV_HANDLE_REF; \ + if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \ + if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \ } \ while (0) #define uv__has_ref(h) \ - (((h)->flags & UV__HANDLE_REF) != 0) + (((h)->flags & UV_HANDLE_REF) != 0) #if defined(_WIN32) # define uv__handle_platform_init(h) ((h)->u.fd = -1) @@ -218,7 +273,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req); do { \ (h)->loop = (loop_); \ (h)->type = (type_); \ - (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \ + (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \ uv__handle_platform_init(h); \ } \ diff --git a/Utilities/cmlibuv/src/uv-data-getter-setters.c b/Utilities/cmlibuv/src/uv-data-getter-setters.c index 533e4a2..b7fcd4a 100644 --- a/Utilities/cmlibuv/src/uv-data-getter-setters.c +++ b/Utilities/cmlibuv/src/uv-data-getter-setters.c @@ -3,11 +3,11 @@ const char* uv_handle_type_name(uv_handle_type type) { switch (type) { #define XX(uc,lc) case UV_##uc: return #lc; - UV_HANDLE_TYPE_MAP(XX) + UV_HANDLE_TYPE_MAP(XX) #undef XX - case UV_FILE: return "file"; - case UV_HANDLE_TYPE_MAX: - case UV_UNKNOWN_HANDLE: return NULL; + case UV_FILE: return "file"; + case UV_HANDLE_TYPE_MAX: + case UV_UNKNOWN_HANDLE: return NULL; } return NULL; } @@ -31,10 +31,12 @@ void uv_handle_set_data(uv_handle_t* handle, void* data) { const char* uv_req_type_name(uv_req_type type) { switch (type) { #define XX(uc,lc) case UV_##uc: return #lc; - UV_REQ_TYPE_MAP(XX) + UV_REQ_TYPE_MAP(XX) #undef XX - case UV_REQ_TYPE_MAX: - case UV_UNKNOWN_REQ: return NULL; + case UV_REQ_TYPE_MAX: + case UV_UNKNOWN_REQ: + default: /* UV_REQ_TYPE_PRIVATE */ + return NULL; } return NULL; } diff --git a/Utilities/cmlibuv/src/win/async.c b/Utilities/cmlibuv/src/win/async.c index 0b636ed..d787f66 100644 --- a/Utilities/cmlibuv/src/win/async.c +++ b/Utilities/cmlibuv/src/win/async.c @@ -29,7 +29,7 @@ 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) { assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); @@ -71,9 +71,9 @@ int uv_async_send(uv_async_t* handle) { return -1; } - /* The user should make sure never to call uv_async_send to a closing */ - /* or closed handle. */ - assert(!(handle->flags & UV__HANDLE_CLOSING)); + /* The user should make sure never to call uv_async_send to a closing or + * closed handle. */ + assert(!(handle->flags & UV_HANDLE_CLOSING)); if (!uv__atomic_exchange_set(&handle->async_sent)) { POST_COMPLETION_FOR_REQ(loop, &handle->async_req); @@ -90,7 +90,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, handle->async_sent = 0; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*)handle); } else if (handle->async_cb != NULL) { handle->async_cb(handle); diff --git a/Utilities/cmlibuv/src/win/atomicops-inl.h b/Utilities/cmlibuv/src/win/atomicops-inl.h index 6d8126f..52713cf 100644 --- a/Utilities/cmlibuv/src/win/atomicops-inl.h +++ b/Utilities/cmlibuv/src/win/atomicops-inl.h @@ -29,10 +29,10 @@ /* Atomic set operation on char */ #ifdef _MSC_VER /* MSVC */ -/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */ -/* efficient than InterlockedExchange, but InterlockedExchange8 does not */ -/* exist, and interlocked operations on larger targets might require the */ -/* target to be aligned. */ +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less + * efficient than InterlockedExchange, but InterlockedExchange8 does not exist, + * and interlocked operations on larger targets might require the target to be + * aligned. */ #pragma intrinsic(_InterlockedOr8) static char INLINE uv__atomic_exchange_set(char volatile* target) { diff --git a/Utilities/cmlibuv/src/win/core.c b/Utilities/cmlibuv/src/win/core.c index b8aad11..58309c6 100644 --- a/Utilities/cmlibuv/src/win/core.c +++ b/Utilities/cmlibuv/src/win/core.c @@ -33,6 +33,7 @@ #include "internal.h" #include "queue.h" #include "handle-inl.h" +#include "heap-inl.h" #include "req-inl.h" /* uv_once initialization guards */ @@ -221,6 +222,7 @@ static void uv_init(void) { int uv_loop_init(uv_loop_t* loop) { + struct heap* timer_heap; int err; /* Initialize libuv itself first */ @@ -246,7 +248,13 @@ int uv_loop_init(uv_loop_t* loop) { loop->endgame_handles = NULL; - RB_INIT(&loop->timers); + loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap)); + if (timer_heap == NULL) { + err = UV_ENOMEM; + goto fail_timers_alloc; + } + + heap_init(timer_heap); loop->check_handles = NULL; loop->prepare_handles = NULL; @@ -273,7 +281,7 @@ int uv_loop_init(uv_loop_t* loop) { goto fail_async_init; uv__handle_unref(&loop->wq_async); - loop->wq_async.flags |= UV__HANDLE_INTERNAL; + loop->wq_async.flags |= UV_HANDLE_INTERNAL; err = uv__loops_add(loop); if (err) @@ -285,6 +293,10 @@ fail_async_init: uv_mutex_destroy(&loop->wq_mutex); fail_mutex_init: + uv__free(timer_heap); + loop->timer_heap = NULL; + +fail_timers_alloc: CloseHandle(loop->iocp); loop->iocp = INVALID_HANDLE_VALUE; @@ -292,6 +304,13 @@ fail_mutex_init: } +void uv_update_time(uv_loop_t* loop) { + uint64_t new_time = uv__hrtime(1000); + assert(new_time >= loop->time); + loop->time = new_time; +} + + void uv__once_init(void) { uv_once(&uv_init_guard_, uv_init); } @@ -320,6 +339,9 @@ void uv__loop_close(uv_loop_t* loop) { uv_mutex_unlock(&loop->wq_mutex); uv_mutex_destroy(&loop->wq_mutex); + uv__free(loop->timer_heap); + loop->timer_heap = NULL; + CloseHandle(loop->iocp); } @@ -359,7 +381,7 @@ int uv_backend_timeout(const uv_loop_t* loop) { } -static void uv_poll(uv_loop_t* loop, DWORD timeout) { +static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) { DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; @@ -410,7 +432,7 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) { } -static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { +static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; @@ -422,12 +444,12 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { timeout_time = loop->time + timeout; for (repeat = 0; ; repeat++) { - success = pGetQueuedCompletionStatusEx(loop->iocp, - overlappeds, - ARRAY_SIZE(overlappeds), - &count, - timeout, - FALSE); + success = GetQueuedCompletionStatusEx(loop->iocp, + overlappeds, + ARRAY_SIZE(overlappeds), + &count, + timeout, + FALSE); if (success) { for (i = 0; i < count; i++) { @@ -485,12 +507,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; int ran_pending; - void (*poll)(uv_loop_t* loop, DWORD timeout); - - if (pGetQueuedCompletionStatusEx) - poll = &uv_poll_ex; - else - poll = &uv_poll; r = uv__loop_alive(loop); if (!r) @@ -498,7 +514,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { while (r != 0 && loop->stop_flag == 0) { uv_update_time(loop); - uv_process_timers(loop); + uv__run_timers(loop); ran_pending = uv_process_reqs(loop); uv_idle_invoke(loop); @@ -508,7 +524,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) { if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT) timeout = uv_backend_timeout(loop); - (*poll)(loop, timeout); + if (pGetQueuedCompletionStatusEx) + uv__poll(loop, timeout); + else + uv__poll_wine(loop, timeout); + uv_check_invoke(loop); uv_process_endgames(loop); @@ -522,7 +542,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 * the check. */ - uv_process_timers(loop); + uv__run_timers(loop); } r = uv__loop_alive(loop); diff --git a/Utilities/cmlibuv/src/win/dl.c b/Utilities/cmlibuv/src/win/dl.c index 97ac1c1..676be4d 100644 --- a/Utilities/cmlibuv/src/win/dl.c +++ b/Utilities/cmlibuv/src/win/dl.c @@ -64,7 +64,8 @@ void uv_dlclose(uv_lib_t* lib) { int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { - *ptr = (void*) GetProcAddress(lib->handle, name); + /* Cast though integer to suppress pedantic warning about forbidden cast. */ + *ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name); return uv__dlerror(lib, "", *ptr ? 0 : GetLastError()); } @@ -75,8 +76,9 @@ const char* uv_dlerror(const uv_lib_t* lib) { static void uv__format_fallback_error(uv_lib_t* lib, int errorno){ - DWORD_PTR args[1] = { (DWORD_PTR) errorno }; - LPSTR fallback_error = "error: %1!d!"; + static const CHAR fallback_error[] = "error: %1!d!"; + DWORD_PTR args[1]; + args[0] = (DWORD_PTR) errorno; FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | @@ -107,7 +109,8 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) { MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR) &lib->errmsg, 0, NULL); - if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) { + if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND || + GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) { res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, diff --git a/Utilities/cmlibuv/src/win/error.c b/Utilities/cmlibuv/src/win/error.c index 9b03bfe..24924ba 100644 --- a/Utilities/cmlibuv/src/win/error.c +++ b/Utilities/cmlibuv/src/win/error.c @@ -46,8 +46,8 @@ void uv_fatal_error(const int errorno, const char* syscall) { errmsg = "Unknown error"; } - /* FormatMessage messages include a newline character already, */ - /* so don't add another. */ + /* FormatMessage messages include a newline character already, so don't add + * another. */ if (syscall) { fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg); } else { diff --git a/Utilities/cmlibuv/src/win/fs-event.c b/Utilities/cmlibuv/src/win/fs-event.c index 14c9af9..acf8e11 100644 --- a/Utilities/cmlibuv/src/win/fs-event.c +++ b/Utilities/cmlibuv/src/win/fs-event.c @@ -83,7 +83,7 @@ static void uv_relative_path(const WCHAR* filename, static int uv_split_path(const WCHAR* filename, WCHAR** dir, WCHAR** file) { size_t len, i; - + if (filename == NULL) { if (dir != NULL) *dir = NULL; @@ -215,11 +215,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__free(long_path); long_path = NULL; } - } - if (long_path) { - uv__free(pathw); - pathw = long_path; + if (long_path) { + uv__free(pathw); + pathw = long_path; + } } dir_to_watch = pathw; @@ -230,8 +230,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, */ /* Convert to short path. */ - short_path = short_path_buffer; - if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + if (GetShortPathNameW(pathw, + short_path_buffer, + ARRAY_SIZE(short_path_buffer))) { + short_path = short_path_buffer; + } else { short_path = NULL; } @@ -419,7 +422,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, * - We are not active, just ignore the callback */ 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); } return; @@ -543,7 +546,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } offset = file_info->NextEntryOffset; - } while (offset && !(handle->flags & UV__HANDLE_CLOSING)); + } while (offset && !(handle->flags & UV_HANDLE_CLOSING)); } else { handle->cb(handle, NULL, UV_CHANGE, 0); } @@ -552,7 +555,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, handle->cb(handle, NULL, 0, uv_translate_sys_error(err)); } - if (!(handle->flags & UV__HANDLE_CLOSING)) { + if (!(handle->flags & UV_HANDLE_CLOSING)) { uv_fs_event_queue_readdirchanges(loop, handle); } else { uv_want_endgame(loop, (uv_handle_t*)handle); @@ -573,7 +576,7 @@ 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) { - if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) { + if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (handle->buffer) { diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c index 30b87ac..65d936b 100644 --- a/Utilities/cmlibuv/src/win/fs.c +++ b/Utilities/cmlibuv/src/win/fs.c @@ -55,7 +55,11 @@ do { \ if (cb != NULL) { \ uv__req_register(loop, req); \ - uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \ + uv__work_submit(loop, \ + &req->work_req, \ + UV__WORK_FAST_IO, \ + uv__fs_work, \ + uv__fs_done); \ return 0; \ } else { \ uv__fs_work(&req->work_req); \ @@ -92,14 +96,17 @@ return; \ } +#define MILLIONu (1000U * 1000U) +#define BILLIONu (1000U * 1000U * 1000U) + #define FILETIME_TO_UINT(filetime) \ - (*((uint64_t*) &(filetime)) - 116444736000000000ULL) + (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu) #define FILETIME_TO_TIME_T(filetime) \ - (FILETIME_TO_UINT(filetime) / 10000000ULL) + (FILETIME_TO_UINT(filetime) / (10u * MILLIONu)) #define FILETIME_TO_TIME_NS(filetime, secs) \ - ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100) + ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U) #define FILETIME_TO_TIMESPEC(ts, filetime) \ do { \ @@ -109,8 +116,8 @@ #define TIME_T_TO_FILETIME(time, filetime_ptr) \ do { \ - uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \ - 116444736000000000ULL; \ + uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \ + (uint64_t) 116444736 * BILLIONu; \ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \ } while(0) @@ -326,12 +333,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Real symlinks can contain pretty much everything, but the only thing */ - /* we really care about is undoing the implicit conversion to an NT */ - /* namespaced path that CreateSymbolicLink will perform on absolute */ - /* paths. If the path is win32-namespaced then the user must have */ - /* explicitly made it so, and we better just return the unmodified */ - /* reparse data. */ + /* Real symlinks can contain pretty much everything, but the only thing we + * really care about is undoing the implicit conversion to an NT namespaced + * path that CreateSymbolicLink will perform on absolute paths. If the path + * is win32-namespaced then the user must have explicitly made it so, and + * we better just return the unmodified reparse data. */ if (w_target_len >= 4 && w_target[0] == L'\\' && w_target[1] == L'?' && @@ -352,8 +358,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, (w_target[5] == L'N' || w_target[5] == L'n') && (w_target[6] == L'C' || w_target[6] == L'c') && w_target[7] == L'\\') { - /* \??\UNC\<server>\<share>\ - make sure the final path looks like */ - /* \\<server>\<share>\ */ + /* \??\UNC\<server>\<share>\ - make sure the final path looks like + * \\<server>\<share>\ */ w_target += 6; w_target[0] = L'\\'; w_target_len -= 6; @@ -368,11 +374,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR); - /* Only treat junctions that look like \??\<drive>:\ as symlink. */ - /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */ - /* but that's confusing for programs since they wouldn't be able to */ - /* actually understand such a path when returned by uv_readlink(). */ - /* UNC paths are never valid for junctions so we don't care about them. */ + /* Only treat junctions that look like \??\<drive>:\ as symlink. Junctions + * can also be used as mount points, like \??\Volume{<guid>}, but that's + * confusing for programs since they wouldn't be able to actually + * understand such a path when returned by uv_readlink(). UNC paths are + * never valid for junctions so we don't care about them. */ if (!(w_target_len >= 6 && w_target[0] == L'\\' && w_target[1] == L'?' && @@ -409,8 +415,8 @@ void fs__open(uv_fs_t* req) { int fd, current_umask; int flags = req->fs.info.file_flags; - /* Obtain the active umask. umask() never fails and returns the previous */ - /* umask. */ + /* Obtain the active umask. umask() never fails and returns the previous + * umask. */ current_umask = umask(0); umask(current_umask); @@ -502,6 +508,33 @@ void fs__open(uv_fs_t* req) { } if (flags & UV_FS_O_DIRECT) { + /* + * FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive. + * Windows returns 87, ERROR_INVALID_PARAMETER if these are combined. + * + * FILE_APPEND_DATA is included in FILE_GENERIC_WRITE: + * + * FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | + * FILE_WRITE_DATA | + * FILE_WRITE_ATTRIBUTES | + * FILE_WRITE_EA | + * FILE_APPEND_DATA | + * SYNCHRONIZE + * + * Note: Appends are also permitted by FILE_WRITE_DATA. + * + * In order for direct writes and direct appends to succeed, we therefore + * exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise + * fail if the user's sole permission is a direct append, since this + * particular combination is invalid. + */ + if (access & FILE_APPEND_DATA) { + if (access & FILE_WRITE_DATA) { + access &= ~FILE_APPEND_DATA; + } else { + goto einval; + } + } attributes |= FILE_FLAG_NO_BUFFERING; } @@ -530,8 +563,8 @@ void fs__open(uv_fs_t* req) { DWORD error = GetLastError(); if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) && !(flags & UV_FS_O_EXCL)) { - /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */ - /* specified, it means the path referred to a directory. */ + /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was + * specified, it means the path referred to a directory. */ SET_REQ_UV_ERROR(req, UV_EISDIR, error); } else { SET_REQ_WIN32_ERROR(req, GetLastError()); @@ -756,9 +789,9 @@ void fs__unlink(uv_fs_t* req) { } if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - /* Do not allow deletion of directories, unless it is a symlink. When */ - /* the path refers to a non-symlink directory, report EPERM as mandated */ - /* by POSIX.1. */ + /* Do not allow deletion of directories, unless it is a symlink. When the + * path refers to a non-symlink directory, report EPERM as mandated by + * POSIX.1. */ /* Check if it is a reparse point. If it's not, it's a normal directory. */ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { @@ -767,8 +800,8 @@ void fs__unlink(uv_fs_t* req) { return; } - /* Read the reparse point and check if it is a valid symlink. */ - /* If not, don't unlink. */ + /* Read the reparse point and check if it is a valid symlink. If not, don't + * unlink. */ if (fs__readlink_handle(handle, NULL, NULL) < 0) { DWORD error = GetLastError(); if (error == ERROR_SYMLINK_NOT_SUPPORTED) @@ -783,9 +816,8 @@ void fs__unlink(uv_fs_t* req) { /* Remove read-only attribute */ FILE_BASIC_INFORMATION basic = { 0 }; - basic.FileAttributes = info.dwFileAttributes - & ~(FILE_ATTRIBUTE_READONLY) - | FILE_ATTRIBUTE_ARCHIVE; + basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) | + FILE_ATTRIBUTE_ARCHIVE; status = pNtSetInformationFile(handle, &iosb, @@ -1196,7 +1228,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, /* st_blocks contains the on-disk allocation size in 512-byte units. */ statbuf->st_blocks = - file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL; + (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9; statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks; @@ -1490,6 +1522,7 @@ static void fs__chmod(uv_fs_t* req) { static void fs__fchmod(uv_fs_t* req) { int fd = req->file.fd; + int clear_archive_flag; HANDLE handle; NTSTATUS nt_status; IO_STATUS_BLOCK io_status; @@ -1497,7 +1530,11 @@ static void fs__fchmod(uv_fs_t* req) { VERIFY_FD(fd, req); - handle = uv__get_osfhandle(fd); + handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } nt_status = pNtQueryInformationFile(handle, &io_status, @@ -1507,7 +1544,27 @@ static void fs__fchmod(uv_fs_t* req) { if (!NT_SUCCESS(nt_status)) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); - return; + goto fchmod_cleanup; + } + + /* Test if the Archive attribute is cleared */ + if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) { + /* Set Archive flag, otherwise setting or clearing the read-only + flag will not work */ + file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + goto fchmod_cleanup; + } + /* Remeber to clear the flag later on */ + clear_archive_flag = 1; + } else { + clear_archive_flag = 0; } if (req->fs.info.mode & _S_IWRITE) { @@ -1524,10 +1581,28 @@ static void fs__fchmod(uv_fs_t* req) { if (!NT_SUCCESS(nt_status)) { SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); - return; + goto fchmod_cleanup; + } + + if (clear_archive_flag) { + file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE; + if (file_info.FileAttributes == 0) { + file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL; + } + nt_status = pNtSetInformationFile(handle, + &io_status, + &file_info, + sizeof file_info, + FileBasicInformation); + if (!NT_SUCCESS(nt_status)) { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status)); + goto fchmod_cleanup; + } } SET_REQ_SUCCESS(req); +fchmod_cleanup: + CloseHandle(handle); } @@ -1787,17 +1862,13 @@ static void fs__symlink(uv_fs_t* req) { fs__create_junction(req, pathw, new_pathw); return; } - if (!pCreateSymbolicLinkW) { - SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; - } if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR) flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag; else flags = uv__file_symlink_usermode_flag; - if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) { + if (CreateSymbolicLinkW(new_pathw, pathw, flags)) { SET_REQ_RESULT(req, 0); return; } @@ -1848,13 +1919,13 @@ static void fs__readlink(uv_fs_t* req) { } -static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { +static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { int r; DWORD w_realpath_len; WCHAR* w_realpath_ptr = NULL; WCHAR* w_realpath_buf; - w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); if (w_realpath_len == 0) { return -1; } @@ -1866,10 +1937,8 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { } w_realpath_ptr = w_realpath_buf; - if (pGetFinalPathNameByHandleW(handle, - w_realpath_ptr, - w_realpath_len, - VOLUME_NAME_DOS) == 0) { + if (GetFinalPathNameByHandleW( + handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) { uv__free(w_realpath_buf); SetLastError(ERROR_INVALID_HANDLE); return -1; @@ -1901,11 +1970,6 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { static void fs__realpath(uv_fs_t* req) { HANDLE handle; - if (!pGetFinalPathNameByHandleW) { - SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; - } - handle = CreateFileW(req->file.pathw, 0, 0, @@ -1940,6 +2004,10 @@ static void fs__fchown(uv_fs_t* req) { } +static void fs__lchown(uv_fs_t* req) { + req->result = 0; +} + static void uv__fs_work(struct uv__work* w) { uv_fs_t* req; @@ -1977,6 +2045,7 @@ static void uv__fs_work(struct uv__work* w) { XX(REALPATH, realpath) XX(CHOWN, chown) XX(FCHOWN, fchown); + XX(LCHOWN, lchown); default: assert(!"bad uv_fs_type"); } @@ -2262,6 +2331,19 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, } +int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { + int err; + + INIT(UV_FS_LCHOWN); + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + POST; +} + + int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { int err; diff --git a/Utilities/cmlibuv/src/win/getaddrinfo.c b/Utilities/cmlibuv/src/win/getaddrinfo.c index 5adc766..dfab860 100644 --- a/Utilities/cmlibuv/src/win/getaddrinfo.c +++ b/Utilities/cmlibuv/src/win/getaddrinfo.c @@ -24,6 +24,7 @@ #include "uv.h" #include "internal.h" #include "req-inl.h" +#include "idna.h" /* EAI_* constants. */ #include <winsock2.h> @@ -71,8 +72,8 @@ int uv__getaddrinfo_translate_error(int sys_err) { #endif -/* adjust size value to be multiple of 4. Use to keep pointer aligned */ -/* Do we need different versions of this for different architectures? */ +/* Adjust size value to be multiple of 4. Use to keep pointer aligned. + * Do we need different versions of this for different architectures? */ #define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2) #ifndef NDIS_IF_MAX_STRING_SIZE @@ -124,8 +125,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { } if (req->retcode == 0) { - /* convert addrinfoW to addrinfo */ - /* first calculate required length */ + /* Convert addrinfoW to addrinfo. First calculate required length. */ addrinfow_ptr = req->addrinfow; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + @@ -260,11 +260,13 @@ int uv_getaddrinfo(uv_loop_t* loop, const char* node, const char* service, const struct addrinfo* hints) { + char hostname_ascii[256]; int nodesize = 0; int servicesize = 0; int hintssize = 0; char* alloc_ptr = NULL; int err; + long rc; if (req == NULL || (node == NULL && service == NULL)) { return UV_EINVAL; @@ -278,12 +280,19 @@ int uv_getaddrinfo(uv_loop_t* loop, /* calculate required memory size for all input values */ if (node != NULL) { - nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) * - sizeof(WCHAR)); + rc = uv__idna_toascii(node, + node + strlen(node), + hostname_ascii, + hostname_ascii + sizeof(hostname_ascii)); + if (rc < 0) + return rc; + nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii, + -1, NULL, 0) * sizeof(WCHAR)); if (nodesize == 0) { err = GetLastError(); goto error; } + node = hostname_ascii; } if (service != NULL) { @@ -313,8 +322,8 @@ int uv_getaddrinfo(uv_loop_t* loop, /* save alloc_ptr now so we can free if error */ req->alloc = (void*)alloc_ptr; - /* convert node string to UTF16 into allocated memory and save pointer in */ - /* the request. */ + /* Convert node string to UTF16 into allocated memory and save pointer in the + * request. */ if (node != NULL) { req->node = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, @@ -331,8 +340,8 @@ int uv_getaddrinfo(uv_loop_t* loop, req->node = NULL; } - /* convert service string to UTF16 into allocated memory and save pointer */ - /* in the req. */ + /* Convert service string to UTF16 into allocated memory and save pointer in + * the req. */ if (service != NULL) { req->service = (WCHAR*)alloc_ptr; if (MultiByteToWideChar(CP_UTF8, @@ -369,6 +378,7 @@ int uv_getaddrinfo(uv_loop_t* loop, if (getaddrinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getaddrinfo_work, uv__getaddrinfo_done); return 0; @@ -392,21 +402,15 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) { DWORD bufsize; int r; - uv__once_init(); - if (buffer == NULL || size == NULL || *size == 0) return UV_EINVAL; - if (pConvertInterfaceIndexToLuid == NULL) - return UV_ENOSYS; - r = pConvertInterfaceIndexToLuid(ifindex, &luid); + r = ConvertInterfaceIndexToLuid(ifindex, &luid); if (r != 0) return uv_translate_sys_error(r); - if (pConvertInterfaceLuidToNameW == NULL) - return UV_ENOSYS; - r = pConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); + r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname)); if (r != 0) return uv_translate_sys_error(r); diff --git a/Utilities/cmlibuv/src/win/getnameinfo.c b/Utilities/cmlibuv/src/win/getnameinfo.c index 9f10cd2..b377338 100644 --- a/Utilities/cmlibuv/src/win/getnameinfo.c +++ b/Utilities/cmlibuv/src/win/getnameinfo.c @@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) { uv_getnameinfo_t* req; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; - int ret = 0; + int ret; req = container_of(w, uv_getnameinfo_t, work_req); if (GetNameInfoW((struct sockaddr*)&req->storage, @@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) { ARRAY_SIZE(service), req->flags)) { ret = WSAGetLastError(); + req->retcode = uv__getaddrinfo_translate_error(ret); + return; + } + + ret = WideCharToMultiByte(CP_UTF8, + 0, + host, + -1, + req->host, + sizeof(req->host), + NULL, + NULL); + if (ret == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); + return; + } + + ret = WideCharToMultiByte(CP_UTF8, + 0, + service, + -1, + req->service, + sizeof(req->service), + NULL, + NULL); + if (ret == 0) { + req->retcode = uv_translate_sys_error(GetLastError()); } - req->retcode = uv__getaddrinfo_translate_error(ret); - - /* convert results to UTF-8 */ - WideCharToMultiByte(CP_UTF8, - 0, - host, - -1, - req->host, - sizeof(req->host), - NULL, - NULL); - - WideCharToMultiByte(CP_UTF8, - 0, - service, - -1, - req->service, - sizeof(req->service), - NULL, - NULL); } @@ -138,6 +145,7 @@ int uv_getnameinfo(uv_loop_t* loop, if (getnameinfo_cb) { uv__work_submit(loop, &req->work_req, + UV__WORK_SLOW_IO, uv__getnameinfo_work, uv__getnameinfo_done); return 0; diff --git a/Utilities/cmlibuv/src/win/handle-inl.h b/Utilities/cmlibuv/src/win/handle-inl.h index 8d0334c..82c657d 100644 --- a/Utilities/cmlibuv/src/win/handle-inl.h +++ b/Utilities/cmlibuv/src/win/handle-inl.h @@ -32,7 +32,7 @@ #define DECREASE_ACTIVE_COUNT(loop, handle) \ do { \ if (--(handle)->activecnt == 0 && \ - !((handle)->flags & UV__HANDLE_CLOSING)) { \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ uv__handle_stop((handle)); \ } \ assert((handle)->activecnt >= 0); \ @@ -53,7 +53,7 @@ assert(handle->reqs_pending > 0); \ handle->reqs_pending--; \ \ - if (handle->flags & UV__HANDLE_CLOSING && \ + if (handle->flags & UV_HANDLE_CLOSING && \ handle->reqs_pending == 0) { \ uv_want_endgame(loop, (uv_handle_t*)handle); \ } \ @@ -62,14 +62,14 @@ #define uv__handle_closing(handle) \ do { \ - assert(!((handle)->flags & UV__HANDLE_CLOSING)); \ + assert(!((handle)->flags & UV_HANDLE_CLOSING)); \ \ - if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \ - ((handle)->flags & UV__HANDLE_REF))) \ + if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \ + ((handle)->flags & UV_HANDLE_REF))) \ uv__active_handle_add((uv_handle_t*) (handle)); \ \ - (handle)->flags |= UV__HANDLE_CLOSING; \ - (handle)->flags &= ~UV__HANDLE_ACTIVE; \ + (handle)->flags |= UV_HANDLE_CLOSING; \ + (handle)->flags &= ~UV_HANDLE_ACTIVE; \ } while (0) @@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { break; case UV_TIMER: - uv_timer_endgame(loop, (uv_timer_t*) handle); + uv__timer_close((uv_timer_t*) handle); + uv__handle_close(handle); break; case UV_PREPARE: @@ -164,10 +165,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) { INLINE static HANDLE uv__get_osfhandle(int fd) { - /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */ - /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */ - /* for invalid FDs in release builds (or if you let the assert continue). */ - /* So this wrapper function disables asserts when calling _get_osfhandle. */ + /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. + * But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for + * invalid FDs in release builds (or if you let the assert continue). So this + * wrapper function disables asserts when calling _get_osfhandle. */ HANDLE handle; UV_BEGIN_DISABLE_CRT_ASSERT(); diff --git a/Utilities/cmlibuv/src/win/handle.c b/Utilities/cmlibuv/src/win/handle.c index 3915070..9d76c3f 100644 --- a/Utilities/cmlibuv/src/win/handle.c +++ b/Utilities/cmlibuv/src/win/handle.c @@ -59,15 +59,15 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(const uv_handle_t* handle) { - return (handle->flags & UV__HANDLE_ACTIVE) && - !(handle->flags & UV__HANDLE_CLOSING); + return (handle->flags & UV_HANDLE_ACTIVE) && + !(handle->flags & UV_HANDLE_CLOSING); } void uv_close(uv_handle_t* handle, uv_close_cb cb) { uv_loop_t* loop = handle->loop; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { assert(0); return; } @@ -150,10 +150,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { int uv_is_closing(const uv_handle_t* handle) { - return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED)); + return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)); } uv_os_fd_t uv_get_osfhandle(int fd) { return uv__get_osfhandle(fd); } + +int uv_open_osfhandle(uv_os_fd_t os_fd) { + return _open_osfhandle((intptr_t) os_fd, 0); +} diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h index 849bc82..206ab5f 100644 --- a/Utilities/cmlibuv/src/win/internal.h +++ b/Utilities/cmlibuv/src/win/internal.h @@ -29,7 +29,7 @@ #include "uv.h" #include "../uv-common.h" -#include "tree.h" +#include "uv/tree.h" #include "winapi.h" #include "winsock.h" @@ -62,77 +62,19 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #endif /* - * Handles - * (also see handle-inl.h) - */ - -/* Used by all handles. */ -#define UV_HANDLE_CLOSED 0x00000002 -#define UV_HANDLE_ENDGAME_QUEUED 0x00000008 - -/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */ -/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */ -/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */ -/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */ - -/* Used by streams and UDP handles. */ -#define UV_HANDLE_READING 0x00000100 -#define UV_HANDLE_BOUND 0x00000200 -#define UV_HANDLE_LISTENING 0x00000800 -#define UV_HANDLE_CONNECTION 0x00001000 -#define UV_HANDLE_READABLE 0x00008000 -#define UV_HANDLE_WRITABLE 0x00010000 -#define UV_HANDLE_READ_PENDING 0x00020000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 -#define UV_HANDLE_ZERO_READ 0x00080000 -#define UV_HANDLE_EMULATE_IOCP 0x00100000 -#define UV_HANDLE_BLOCKING_WRITES 0x00200000 -#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 - -/* Used by uv_tcp_t and uv_udp_t handles */ -#define UV_HANDLE_IPV6 0x01000000 - -/* Only used by uv_tcp_t handles. */ -#define UV_HANDLE_TCP_NODELAY 0x02000000 -#define UV_HANDLE_TCP_KEEPALIVE 0x04000000 -#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 -#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 -#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 -#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 - -/* Only used by uv_pipe_t handles. */ -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 -#define UV_HANDLE_PIPESERVER 0x02000000 -#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000 - -/* Only used by uv_tty_t handles. */ -#define UV_HANDLE_TTY_READABLE 0x01000000 -#define UV_HANDLE_TTY_RAW 0x02000000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000 - -/* Only used by uv_poll_t handles. */ -#define UV_HANDLE_POLL_SLOW 0x02000000 - - -/* - * Requests: see req-inl.h - */ - - -/* - * Streams: see stream-inl.h - */ - - -/* * TCP */ +typedef enum { + UV__IPC_SOCKET_XFER_NONE = 0, + UV__IPC_SOCKET_XFER_TCP_CONNECTION, + UV__IPC_SOCKET_XFER_TCP_SERVER +} uv__ipc_socket_xfer_type_t; + typedef struct { WSAPROTOCOL_INFOW socket_info; - int delayed_error; -} uv__ipc_socket_info_ex; + uint32_t delayed_error; +} uv__ipc_socket_xfer_info_t; 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); @@ -154,11 +96,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); -int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, - int tcp_connection); - -int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, - LPWSAPROTOCOL_INFOW protocol_info); +int uv__tcp_xfer_export(uv_tcp_t* handle, + int pid, + uv__ipc_socket_xfer_type_t* xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info); +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info); /* @@ -182,14 +126,14 @@ 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_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb); -int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, - const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb); -int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, - const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle, - uv_write_cb cb); -void uv__pipe_pause_read(uv_pipe_t* handle); -void uv__pipe_unpause_read(uv_pipe_t* handle); -void uv__pipe_stop_read(uv_pipe_t* handle); +void uv__pipe_read_stop(uv_pipe_t* handle); +int uv__pipe_write(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + size_t nbufs, + uv_stream_t* send_handle, + uv_write_cb cb); void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, uv_req_t* req); @@ -252,15 +196,6 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); /* - * Timers - */ -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); - -DWORD uv__next_timeout(const uv_loop_t* loop); -void uv_process_timers(uv_loop_t* loop); - - -/* * Loop watchers */ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); @@ -336,7 +271,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle); void uv__util_init(void); uint64_t uv__hrtime(double scale); -int uv_current_pid(void); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); diff --git a/Utilities/cmlibuv/src/win/loop-watcher.c b/Utilities/cmlibuv/src/win/loop-watcher.c index 20e4509..ad7fbea 100644 --- a/Utilities/cmlibuv/src/win/loop-watcher.c +++ b/Utilities/cmlibuv/src/win/loop-watcher.c @@ -27,7 +27,7 @@ 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)); handle->flags |= UV_HANDLE_CLOSED; uv__handle_close(handle); diff --git a/Utilities/cmlibuv/src/win/pipe.c b/Utilities/cmlibuv/src/win/pipe.c index 83ee4f9..277f649 100644 --- a/Utilities/cmlibuv/src/win/pipe.c +++ b/Utilities/cmlibuv/src/win/pipe.c @@ -21,39 +21,28 @@ #include <assert.h> #include <io.h> -#include <string.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> -#include "uv.h" -#include "internal.h" #include "handle-inl.h" -#include "stream-inl.h" +#include "internal.h" #include "req-inl.h" +#include "stream-inl.h" +#include "uv-common.h" +#include "uv.h" #include <aclapi.h> #include <accctrl.h> -typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t; - -struct uv__ipc_queue_item_s { - /* - * NOTE: It is important for socket_info_ex to be the first field, - * because we will we assigning it to the pending_ipc_info.socket_info - */ - uv__ipc_socket_info_ex socket_info_ex; - QUEUE member; - int tcp_connection; -}; - /* A zero-size buffer for use by uv_pipe_read */ static char uv_zero_[] = ""; /* Null uv_buf_t */ static const uv_buf_t uv_null_buf_ = { 0, NULL }; -/* The timeout that the pipe will wait for the remote end to write data */ -/* when the local ends wants to shut it down. */ +/* The timeout that the pipe will wait for the remote end to write data when + * the local ends wants to shut it down. */ static const int64_t eof_timeout = 50; /* ms */ static const int default_pending_pipe_instances = 4; @@ -62,22 +51,44 @@ static const int default_pending_pipe_instances = 4; static char pipe_prefix[] = "\\\\?\\pipe"; static const int pipe_prefix_len = sizeof(pipe_prefix) - 1; -/* IPC protocol flags. */ -#define UV_IPC_RAW_DATA 0x0001 -#define UV_IPC_TCP_SERVER 0x0002 -#define UV_IPC_TCP_CONNECTION 0x0004 +/* IPC incoming xfer queue item. */ +typedef struct { + uv__ipc_socket_xfer_type_t xfer_type; + uv__ipc_socket_xfer_info_t xfer_info; + QUEUE member; +} uv__ipc_xfer_queue_item_t; + +/* IPC frame header flags. */ +/* clang-format off */ +enum { + UV__IPC_FRAME_HAS_DATA = 0x01, + UV__IPC_FRAME_HAS_SOCKET_XFER = 0x02, + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION = 0x04, + /* These are combinations of the flags above. */ + UV__IPC_FRAME_XFER_FLAGS = 0x06, + UV__IPC_FRAME_VALID_FLAGS = 0x07 +}; +/* clang-format on */ /* IPC frame header. */ typedef struct { - int flags; - uint64_t raw_data_length; -} uv_ipc_frame_header_t; - -/* IPC frame, which contains an imported TCP socket stream. */ + uint32_t flags; + uint32_t reserved1; /* Ignored. */ + uint32_t data_length; /* Must be zero if there is no data. */ + uint32_t reserved2; /* Must be zero. */ +} uv__ipc_frame_header_t; + +/* To implement the IPC protocol correctly, these structures must have exactly + * the right size. */ +STATIC_ASSERT(sizeof(uv__ipc_frame_header_t) == 16); +STATIC_ASSERT(sizeof(uv__ipc_socket_xfer_info_t) == 632); + +/* Coalesced write request. */ typedef struct { - uv_ipc_frame_header_t header; - uv__ipc_socket_info_ex socket_info_ex; -} uv_ipc_frame_uv_stream; + uv_write_t req; /* Internal heap-allocated write request. */ + uv_write_t* user_req; /* Pointer to user-specified uv_write_t. */ +} uv__coalesced_write_t; + static void eof_timer_init(uv_pipe_t* pipe); static void eof_timer_start(uv_pipe_t* pipe); @@ -98,15 +109,12 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { handle->reqs_pending = 0; handle->handle = INVALID_HANDLE_VALUE; handle->name = NULL; - handle->pipe.conn.ipc_pid = 0; - handle->pipe.conn.remaining_ipc_rawdata_bytes = 0; - QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue); - handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->pipe.conn.ipc_remote_pid = 0; + handle->pipe.conn.ipc_data_frame.payload_remaining = 0; + QUEUE_INIT(&handle->pipe.conn.ipc_xfer_queue); + handle->pipe.conn.ipc_xfer_queue_length = 0; handle->ipc = ipc; handle->pipe.conn.non_overlapped_writes_tail = NULL; - handle->pipe.conn.readfile_thread = NULL; - - UV_REQ_INIT(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_REQ); return 0; } @@ -117,10 +125,9 @@ static void uv_pipe_connection_init(uv_pipe_t* handle) { handle->read_req.data = handle; handle->pipe.conn.eof_timer = NULL; assert(!(handle->flags & UV_HANDLE_PIPESERVER)); - if (pCancelSynchronousIo && - handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - uv_mutex_init(&handle->pipe.conn.readfile_mutex); - handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE; + if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + handle->pipe.conn.readfile_thread_handle = NULL; + InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock); } } @@ -347,12 +354,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { NTSTATUS nt_status; IO_STATUS_BLOCK io_status; FILE_PIPE_LOCAL_INFORMATION pipe_info; - uv__ipc_queue_item_t* item; - - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE; - uv_mutex_destroy(&handle->pipe.conn.readfile_mutex); - } + uv__ipc_xfer_queue_item_t* xfer_queue_item; if ((handle->flags & UV_HANDLE_CONNECTION) && handle->stream.conn.shutdown_req != NULL && @@ -362,7 +364,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { /* Clear the shutdown_req field so we don't go here again. */ handle->stream.conn.shutdown_req = NULL; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { UNREGISTER_HANDLE_REQ(loop, handle, req); /* Already closing. Cancel the shutdown. */ @@ -423,33 +425,33 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); if (handle->flags & UV_HANDLE_CONNECTION) { /* Free pending sockets */ - while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) { + while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) { QUEUE* q; SOCKET socket; - q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue); + q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue); QUEUE_REMOVE(q); - item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + 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, - &item->socket_info_ex.socket_info, + &xfer_queue_item->xfer_info.socket_info, 0, WSA_FLAG_OVERLAPPED); - uv__free(item); + uv__free(xfer_queue_item); if (socket != INVALID_SOCKET) closesocket(socket); } - handle->pipe.conn.pending_ipc_info.queue_len = 0; + handle->pipe.conn.ipc_xfer_queue_length = 0; if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) { @@ -461,6 +463,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* 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) { @@ -595,8 +600,8 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { loop = handle->loop; assert(loop); - /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ - /* We wait for the pipe to become available with WaitNamedPipe. */ + /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait + * for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); @@ -706,55 +711,68 @@ error: } -void uv__pipe_pause_read(uv_pipe_t* handle) { - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - /* Pause the ReadFile task briefly, to work - around the Windows kernel bug that causes - any access to a NamedPipe to deadlock if - any process has called ReadFile */ - HANDLE h; - uv_mutex_lock(&handle->pipe.conn.readfile_mutex); - h = handle->pipe.conn.readfile_thread; - while (h) { - /* spinlock: we expect this to finish quickly, - or we are probably about to deadlock anyways - (in the kernel), so it doesn't matter */ - pCancelSynchronousIo(h); - SwitchToThread(); /* yield thread control briefly */ - h = handle->pipe.conn.readfile_thread; - } - } -} +void uv__pipe_interrupt_read(uv_pipe_t* handle) { + BOOL r; + + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return; /* No pending reads. */ + if (handle->flags & UV_HANDLE_CANCELLATION_PENDING) + return; /* Already cancelled. */ + if (handle->handle == INVALID_HANDLE_VALUE) + return; /* Pipe handle closed. */ + if (!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)) { + /* Cancel asynchronous read. */ + r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped); + assert(r || GetLastError() == ERROR_NOT_FOUND); -void uv__pipe_unpause_read(uv_pipe_t* handle) { - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - uv_mutex_unlock(&handle->pipe.conn.readfile_mutex); + } else { + /* Cancel synchronous read (which is happening in the thread pool). */ + HANDLE thread; + volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle; + + EnterCriticalSection(&handle->pipe.conn.readfile_thread_lock); + + thread = *thread_ptr; + if (thread == NULL) { + /* The thread pool thread has not yet reached the point of blocking, we + * can pre-empt it by setting thread_handle to INVALID_HANDLE_VALUE. */ + *thread_ptr = INVALID_HANDLE_VALUE; + + } else { + /* Spin until the thread has acknowledged (by setting the thread to + * INVALID_HANDLE_VALUE) that it is past the point of blocking. */ + while (thread != INVALID_HANDLE_VALUE) { + r = CancelSynchronousIo(thread); + assert(r || GetLastError() == ERROR_NOT_FOUND); + SwitchToThread(); /* Yield thread. */ + thread = *thread_ptr; + } + } + + LeaveCriticalSection(&handle->pipe.conn.readfile_thread_lock); } + + /* Set flag to indicate that read has been cancelled. */ + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; } -void uv__pipe_stop_read(uv_pipe_t* handle) { - if (pCancelIoEx && - !(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) && - !(handle->flags & UV_HANDLE_EMULATE_IOCP) && - handle->flags & UV_HANDLE_READING && - handle->read_req.type == UV_READ) { - pCancelIoEx(handle->handle, &handle->read_req.u.io.overlapped); - } +void uv__pipe_read_stop(uv_pipe_t* handle) { handle->flags &= ~UV_HANDLE_READING; - uv__pipe_pause_read((uv_pipe_t*)handle); - uv__pipe_unpause_read((uv_pipe_t*)handle); + DECREASE_ACTIVE_COUNT(handle->loop, handle); + + uv__pipe_interrupt_read(handle); } -/* Cleans up uv_pipe_t (server or connection) and all resources associated */ -/* with it. */ +/* Cleans up uv_pipe_t (server or connection) and all resources associated with + * it. */ void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; - uv__pipe_stop_read(handle); + uv__pipe_interrupt_read(handle); if (handle->name) { uv__free(handle->name); @@ -864,23 +882,22 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { uv_pipe_t* pipe_client; uv_pipe_accept_t* req; QUEUE* q; - uv__ipc_queue_item_t* item; + uv__ipc_xfer_queue_item_t* item; int err; if (server->ipc) { - if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) { + if (QUEUE_EMPTY(&server->pipe.conn.ipc_xfer_queue)) { /* No valid pending sockets. */ return WSAEWOULDBLOCK; } - q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue); + q = QUEUE_HEAD(&server->pipe.conn.ipc_xfer_queue); QUEUE_REMOVE(q); - server->pipe.conn.pending_ipc_info.queue_len--; - item = QUEUE_DATA(q, uv__ipc_queue_item_t, member); + server->pipe.conn.ipc_xfer_queue_length--; + item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member); - err = uv_tcp_import((uv_tcp_t*)client, - &item->socket_info_ex, - item->tcp_connection); + err = uv__tcp_xfer_import( + (uv_tcp_t*) client, item->xfer_type, &item->xfer_info); if (err != 0) return err; @@ -889,8 +906,8 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { } else { pipe_client = (uv_pipe_t*)client; - /* Find a connection instance that has been connected, but not yet */ - /* accepted. */ + /* Find a connection instance that has been connected, but not yet + * accepted. */ req = server->pipe.serv.pending_accepts; if (!req) { @@ -908,7 +925,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { req->next_pending = NULL; req->pipeHandle = INVALID_HANDLE_VALUE; - if (!(server->flags & UV__HANDLE_CLOSING)) { + if (!(server->flags & UV_HANDLE_CLOSING)) { uv_pipe_queue_accept(loop, server, req, FALSE); } } @@ -953,74 +970,75 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { } -static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { - int result; - DWORD bytes; - uv_read_t* req = (uv_read_t*) parameter; +static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* arg) { + uv_read_t* req = (uv_read_t*) arg; uv_pipe_t* handle = (uv_pipe_t*) req->data; uv_loop_t* loop = handle->loop; - HANDLE hThread = NULL; + volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle; + CRITICAL_SECTION* lock = &handle->pipe.conn.readfile_thread_lock; + HANDLE thread; + DWORD bytes; DWORD err; - uv_mutex_t *m = &handle->pipe.conn.readfile_mutex; - assert(req != NULL); assert(req->type == UV_READ); assert(handle->type == UV_NAMED_PIPE); - if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */ - if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &hThread, - 0, FALSE, DUPLICATE_SAME_ACCESS)) { - handle->pipe.conn.readfile_thread = hThread; - } else { - hThread = NULL; - } - uv_mutex_unlock(m); + err = 0; + + /* Create a handle to the current thread. */ + if (!DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &thread, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + err = GetLastError(); + goto out1; } -restart_readfile: - if (handle->flags & UV_HANDLE_READING) { - result = ReadFile(handle->handle, - &uv_zero_, - 0, - &bytes, - NULL); - if (!result) { - err = GetLastError(); - if (err == ERROR_OPERATION_ABORTED && - handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) { - if (handle->flags & UV_HANDLE_READING) { - /* just a brief break to do something else */ - handle->pipe.conn.readfile_thread = NULL; - /* resume after it is finished */ - uv_mutex_lock(m); - handle->pipe.conn.readfile_thread = hThread; - uv_mutex_unlock(m); - goto restart_readfile; - } else { - result = 1; /* successfully stopped reading */ - } - } - } + + /* The lock needs to be held when thread handle is modified. */ + EnterCriticalSection(lock); + if (*thread_ptr == INVALID_HANDLE_VALUE) { + /* uv__pipe_interrupt_read() cancelled reading before we got here. */ + err = ERROR_OPERATION_ABORTED; } else { - result = 1; /* successfully aborted read before it even started */ - } - if (hThread) { - assert(hThread == handle->pipe.conn.readfile_thread); - /* mutex does not control clearing readfile_thread */ - handle->pipe.conn.readfile_thread = NULL; - uv_mutex_lock(m); - /* only when we hold the mutex lock is it safe to - open or close the handle */ - CloseHandle(hThread); - uv_mutex_unlock(m); + /* Let main thread know which worker thread is doing the blocking read. */ + assert(*thread_ptr == NULL); + *thread_ptr = thread; } + LeaveCriticalSection(lock); - if (!result) { - SET_REQ_ERROR(req, err); - } + if (err) + goto out2; + + /* Block the thread until data is available on the pipe, or the read is + * cancelled. */ + if (!ReadFile(handle->handle, &uv_zero_, 0, &bytes, NULL)) + err = GetLastError(); + + /* Let the main thread know the worker is past the point of blocking. */ + assert(thread == *thread_ptr); + *thread_ptr = INVALID_HANDLE_VALUE; + + /* Briefly acquire the mutex. Since the main thread holds the lock while it + * is spinning trying to cancel this thread's I/O, we will block here until + * it stops doing that. */ + EnterCriticalSection(lock); + LeaveCriticalSection(lock); +out2: + /* Close the handle to the current thread. */ + CloseHandle(thread); + +out1: + /* Set request status and post a completion record to the IOCP. */ + if (err) + SET_REQ_ERROR(req, err); + else + SET_REQ_SUCCESS(req); POST_COMPLETION_FOR_REQ(loop, req); + return 0; } @@ -1102,6 +1120,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { req = &handle->read_req; if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + handle->pipe.conn.readfile_thread_handle = NULL; /* Reset cancellation. */ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, req, WT_EXECUTELONGFUNCTION)) { @@ -1169,8 +1188,8 @@ int uv_pipe_read_start(uv_pipe_t* handle, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_pipe_queue_read(loop, handle); @@ -1226,154 +1245,110 @@ static void uv_queue_non_overlapped_write(uv_pipe_t* handle) { } -static int uv_pipe_write_impl(uv_loop_t* loop, - uv_write_t* req, - uv_pipe_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs, - uv_stream_t* send_handle, - uv_write_cb cb) { - int err; - int result; - uv_tcp_t* tcp_send_handle; - uv_write_t* ipc_header_req = NULL; - uv_ipc_frame_uv_stream ipc_frame; +static int uv__build_coalesced_write_req(uv_write_t* user_req, + const uv_buf_t bufs[], + size_t nbufs, + uv_write_t** req_out, + uv_buf_t* write_buf_out) { + /* Pack into a single heap-allocated buffer: + * (a) a uv_write_t structure where libuv stores the actual state. + * (b) a pointer to the original uv_write_t. + * (c) data from all `bufs` entries. + */ + char* heap_buffer; + size_t heap_buffer_length, heap_buffer_offset; + uv__coalesced_write_t* coalesced_write_req; /* (a) + (b) */ + char* data_start; /* (c) */ + size_t data_length; + unsigned int i; + + /* Compute combined size of all combined buffers from `bufs`. */ + data_length = 0; + for (i = 0; i < nbufs; i++) + data_length += bufs[i].len; + + /* The total combined size of data buffers should not exceed UINT32_MAX, + * because WriteFile() won't accept buffers larger than that. */ + if (data_length > UINT32_MAX) + return WSAENOBUFS; /* Maps to UV_ENOBUFS. */ + + /* Compute heap buffer size. */ + heap_buffer_length = sizeof *coalesced_write_req + /* (a) + (b) */ + data_length; /* (c) */ + + /* Allocate buffer. */ + heap_buffer = uv__malloc(heap_buffer_length); + if (heap_buffer == NULL) + return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */ + + /* Copy uv_write_t information to the buffer. */ + coalesced_write_req = (uv__coalesced_write_t*) heap_buffer; + coalesced_write_req->req = *user_req; /* copy (a) */ + coalesced_write_req->req.coalesced = 1; + coalesced_write_req->user_req = user_req; /* copy (b) */ + heap_buffer_offset = sizeof *coalesced_write_req; /* offset (a) + (b) */ + + /* Copy data buffers to the heap buffer. */ + data_start = &heap_buffer[heap_buffer_offset]; + for (i = 0; i < nbufs; i++) { + memcpy(&heap_buffer[heap_buffer_offset], + bufs[i].base, + bufs[i].len); /* copy (c) */ + heap_buffer_offset += bufs[i].len; /* offset (c) */ + } + assert(heap_buffer_offset == heap_buffer_length); + + /* Set out arguments and return. */ + *req_out = &coalesced_write_req->req; + *write_buf_out = uv_buf_init(data_start, (unsigned int) data_length); + return 0; +} - if (nbufs != 1 && (nbufs != 0 || !send_handle)) { - return ERROR_NOT_SUPPORTED; - } - /* Only TCP handles are supported for sharing. */ - if (send_handle && ((send_handle->type != UV_TCP) || - (!(send_handle->flags & UV_HANDLE_BOUND) && - !(send_handle->flags & UV_HANDLE_CONNECTION)))) { - return ERROR_NOT_SUPPORTED; - } +static int uv__pipe_write_data(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t bufs[], + size_t nbufs, + uv_write_cb cb, + int copy_always) { + int err; + int result; + uv_buf_t write_buf; assert(handle->handle != INVALID_HANDLE_VALUE); UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; + req->send_handle = NULL; req->cb = cb; - req->ipc_header = 0; + /* Private fields. */ + req->coalesced = 0; req->event_handle = NULL; req->wait_handle = INVALID_HANDLE_VALUE; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - - if (handle->ipc) { - assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - ipc_frame.header.flags = 0; - - /* Use the IPC framing protocol. */ - if (send_handle) { - tcp_send_handle = (uv_tcp_t*)send_handle; - - if (handle->pipe.conn.ipc_pid == 0) { - handle->pipe.conn.ipc_pid = uv_current_pid(); - } - - err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, - &ipc_frame.socket_info_ex.socket_info); - if (err) { - return err; - } - - ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error; - - ipc_frame.header.flags |= UV_IPC_TCP_SERVER; - - if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) { - ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION; - } - } - - if (nbufs == 1) { - ipc_frame.header.flags |= UV_IPC_RAW_DATA; - ipc_frame.header.raw_data_length = bufs[0].len; - } - - /* - * Use the provided req if we're only doing a single write. - * If we're doing multiple writes, use ipc_header_write_req to do - * the first write, and then use the provided req for the second write. - */ - if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { - ipc_header_req = req; - } else { - /* - * Try to use the preallocated write req if it's available. - * Otherwise allocate a new one. - */ - if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) { - ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req; - } else { - ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t)); - if (!ipc_header_req) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - } - - UV_REQ_INIT(ipc_header_req, UV_WRITE); - ipc_header_req->handle = (uv_stream_t*) handle; - ipc_header_req->cb = NULL; - ipc_header_req->ipc_header = 1; - } - - /* Write the header or the whole frame. */ - memset(&ipc_header_req->u.io.overlapped, 0, - sizeof(ipc_header_req->u.io.overlapped)); - - /* Using overlapped IO, but wait for completion before returning. - This write is blocking because ipc_frame is on stack. */ - ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL); - if (!ipc_header_req->u.io.overlapped.hEvent) { - uv_fatal_error(GetLastError(), "CreateEvent"); - } - - result = WriteFile(handle->handle, - &ipc_frame, - ipc_frame.header.flags & UV_IPC_TCP_SERVER ? - sizeof(ipc_frame) : sizeof(ipc_frame.header), - NULL, - &ipc_header_req->u.io.overlapped); - if (!result && GetLastError() != ERROR_IO_PENDING) { - err = GetLastError(); - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); + req->write_buffer = uv_null_buf_; + + if (nbufs == 0) { + /* Write empty buffer. */ + write_buf = uv_null_buf_; + } else if (nbufs == 1 && !copy_always) { + /* Write directly from bufs[0]. */ + write_buf = bufs[0]; + } else { + /* Coalesce all `bufs` into one big buffer. This also creates a new + * write-request structure that replaces the old one. */ + err = uv__build_coalesced_write_req(req, bufs, nbufs, &req, &write_buf); + if (err != 0) return err; - } - - if (!result) { - /* Request not completed immediately. Wait for it.*/ - if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) != - WAIT_OBJECT_0) { - err = GetLastError(); - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); - return err; - } - } - ipc_header_req->u.io.queued_bytes = 0; - CloseHandle(ipc_header_req->u.io.overlapped.hEvent); - ipc_header_req->u.io.overlapped.hEvent = NULL; - - REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); - handle->reqs_pending++; - handle->stream.conn.write_reqs_pending++; - - /* If we don't have any raw data to write - we're done. */ - if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) { - return 0; - } } if ((handle->flags & (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) == (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) { DWORD bytes; - result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, - &bytes, - NULL); + result = + WriteFile(handle->handle, write_buf.base, write_buf.len, &bytes, NULL); if (!result) { err = GetLastError(); @@ -1389,14 +1364,14 @@ static int uv_pipe_write_impl(uv_loop_t* loop, POST_COMPLETION_FOR_REQ(loop, req); return 0; } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { - req->write_buffer = bufs[0]; + req->write_buffer = write_buf; uv_insert_non_overlapped_write_req(handle, req); if (handle->stream.conn.write_reqs_pending == 0) { uv_queue_non_overlapped_write(handle); } /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) { /* Using overlapped IO, but wait for completion before returning */ @@ -1406,8 +1381,8 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, + write_buf.base, + write_buf.len, NULL, &req->u.io.overlapped); @@ -1422,13 +1397,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop, req->u.io.queued_bytes = 0; } else { /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) { err = GetLastError(); CloseHandle(req->u.io.overlapped.hEvent); - return uv_translate_sys_error(err); + return err; } } CloseHandle(req->u.io.overlapped.hEvent); @@ -1439,8 +1414,8 @@ static int uv_pipe_write_impl(uv_loop_t* loop, return 0; } else { result = WriteFile(handle->handle, - bufs[0].base, - bufs[0].len, + write_buf.base, + write_buf.len, NULL, &req->u.io.overlapped); @@ -1453,7 +1428,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, req->u.io.queued_bytes = 0; } else { /* Request queued by the kernel. */ - req->u.io.queued_bytes = bufs[0].len; + req->u.io.queued_bytes = write_buf.len; handle->write_queue_size += req->u.io.queued_bytes; } @@ -1478,35 +1453,143 @@ static int uv_pipe_write_impl(uv_loop_t* loop, } -int uv_pipe_write(uv_loop_t* loop, - uv_write_t* req, - uv_pipe_t* handle, - const uv_buf_t bufs[], - unsigned int nbufs, - uv_write_cb cb) { - return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb); +static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) { + DWORD* pid = &handle->pipe.conn.ipc_remote_pid; + + /* If the both ends of the IPC pipe are owned by the same process, + * the remote end pid may not yet be set. If so, do it here. + * TODO: this is weird; it'd probably better to use a handshake. */ + if (*pid == 0) + *pid = GetCurrentProcessId(); + + return *pid; +} + + +int uv__pipe_write_ipc(uv_loop_t* loop, + uv_write_t* req, + uv_pipe_t* handle, + const uv_buf_t data_bufs[], + size_t data_buf_count, + uv_stream_t* send_handle, + uv_write_cb cb) { + uv_buf_t stack_bufs[6]; + uv_buf_t* bufs; + size_t buf_count, buf_index; + uv__ipc_frame_header_t frame_header; + uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE; + uv__ipc_socket_xfer_info_t xfer_info; + uint64_t data_length; + size_t i; + int err; + + /* Compute the combined size of data buffers. */ + data_length = 0; + for (i = 0; i < data_buf_count; i++) + data_length += data_bufs[i].len; + if (data_length > UINT32_MAX) + return WSAENOBUFS; /* Maps to UV_ENOBUFS. */ + + /* Prepare the frame's socket xfer payload. */ + if (send_handle != NULL) { + uv_tcp_t* send_tcp_handle = (uv_tcp_t*) send_handle; + + /* Verify that `send_handle` it is indeed a tcp handle. */ + if (send_tcp_handle->type != UV_TCP) + return ERROR_NOT_SUPPORTED; + + /* Export the tcp handle. */ + err = uv__tcp_xfer_export(send_tcp_handle, + uv__pipe_get_ipc_remote_pid(handle), + &xfer_type, + &xfer_info); + if (err != 0) + return err; + } + + /* Compute the number of uv_buf_t's required. */ + buf_count = 1 + data_buf_count; /* Frame header and data buffers. */ + if (send_handle != NULL) + buf_count += 1; /* One extra for the socket xfer information. */ + + /* Use the on-stack buffer array if it is big enough; otherwise allocate + * space for it on the heap. */ + if (buf_count < ARRAY_SIZE(stack_bufs)) { + /* Use on-stack buffer array. */ + bufs = stack_bufs; + } else { + /* Use heap-allocated buffer array. */ + bufs = uv__calloc(buf_count, sizeof(uv_buf_t)); + if (bufs == NULL) + return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */ + } + buf_index = 0; + + /* Initialize frame header and add it to the buffers list. */ + memset(&frame_header, 0, sizeof frame_header); + bufs[buf_index++] = uv_buf_init((char*) &frame_header, sizeof frame_header); + + if (send_handle != NULL) { + /* Add frame header flags. */ + switch (xfer_type) { + case UV__IPC_SOCKET_XFER_TCP_CONNECTION: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER | + UV__IPC_FRAME_XFER_IS_TCP_CONNECTION; + break; + case UV__IPC_SOCKET_XFER_TCP_SERVER: + frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER; + break; + default: + assert(0); /* Unreachable. */ + } + /* Add xfer info buffer. */ + bufs[buf_index++] = uv_buf_init((char*) &xfer_info, sizeof xfer_info); + } + + if (data_length > 0) { + /* Update frame header. */ + frame_header.flags |= UV__IPC_FRAME_HAS_DATA; + frame_header.data_length = (uint32_t) data_length; + /* Add data buffers to buffers list. */ + for (i = 0; i < data_buf_count; i++) + bufs[buf_index++] = data_bufs[i]; + } + + /* Write buffers. We set the `always_copy` flag, so it is not a problem that + * some of the written data lives on the stack. */ + err = uv__pipe_write_data(loop, req, handle, bufs, buf_count, cb, 1); + + /* If we had to heap-allocate the bufs array, free it now. */ + if (bufs != stack_bufs) { + uv__free(bufs); + } + + return err; } -int uv_pipe_write2(uv_loop_t* loop, +int uv__pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle, const uv_buf_t bufs[], - unsigned int nbufs, + size_t nbufs, uv_stream_t* send_handle, uv_write_cb cb) { - if (!handle->ipc) { - return WSAEINVAL; + if (handle->ipc) { + /* IPC pipe write: use framing protocol. */ + return uv__pipe_write_ipc(loop, req, handle, bufs, nbufs, send_handle, cb); + } else { + /* Non-IPC pipe write: put data on the wire directly. */ + assert(send_handle == NULL); + return uv__pipe_write_data(loop, req, handle, bufs, nbufs, cb, 0); } - - return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb); } static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle, uv_buf_t buf) { - /* If there is an eof timer running, we don't need it any more, */ - /* so discard it. */ + /* If there is an eof timer running, we don't need it any more, so discard + * it. */ eof_timer_destroy(handle); handle->flags &= ~UV_HANDLE_READABLE; @@ -1518,8 +1601,8 @@ 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, uv_buf_t buf) { - /* If there is an eof timer running, we don't need it any more, */ - /* so discard it. */ + /* If there is an eof timer running, we don't need it any more, so discard + * it. */ eof_timer_destroy(handle); uv_read_stop((uv_stream_t*) handle); @@ -1530,10 +1613,7 @@ 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, int error, uv_buf_t buf) { - if (error == ERROR_OPERATION_ABORTED) { - /* do nothing (equivalent to EINTR) */ - } - else if (error == ERROR_BROKEN_PIPE) { + if (error == ERROR_BROKEN_PIPE) { uv_pipe_read_eof(loop, handle, buf); } else { uv_pipe_read_error(loop, handle, error, buf); @@ -1541,152 +1621,228 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle, } -void uv__pipe_insert_pending_socket(uv_pipe_t* handle, - uv__ipc_socket_info_ex* info, - int tcp_connection) { - uv__ipc_queue_item_t* item; +static void uv__pipe_queue_ipc_xfer_info( + uv_pipe_t* handle, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { + uv__ipc_xfer_queue_item_t* item; - item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item)); + item = (uv__ipc_xfer_queue_item_t*) uv__malloc(sizeof(*item)); if (item == NULL) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex)); - item->tcp_connection = tcp_connection; - QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member); - handle->pipe.conn.pending_ipc_info.queue_len++; + item->xfer_type = xfer_type; + item->xfer_info = *xfer_info; + + QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member); + handle->pipe.conn.ipc_xfer_queue_length++; +} + + +/* Read an exact number of bytes from a pipe. If an error or end-of-file is + * encountered before the requested number of bytes are read, an error is + * returned. */ +static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) { + DWORD bytes_read, bytes_read_now; + + bytes_read = 0; + while (bytes_read < count) { + if (!ReadFile(h, + (char*) buffer + bytes_read, + count - bytes_read, + &bytes_read_now, + NULL)) { + return GetLastError(); + } + + bytes_read += bytes_read_now; + } + + assert(bytes_read == count); + return 0; } -void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, - uv_req_t* req) { - DWORD bytes, avail; +static DWORD uv__pipe_read_data(uv_loop_t* loop, + uv_pipe_t* handle, + DWORD suggested_bytes, + DWORD max_bytes) { + DWORD bytes_read; uv_buf_t buf; - uv_ipc_frame_uv_stream ipc_frame; + /* Ask the user for a buffer to read data into. */ + buf = uv_buf_init(NULL, 0); + handle->alloc_cb((uv_handle_t*) handle, suggested_bytes, &buf); + if (buf.base == NULL || buf.len == 0) { + handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + return 0; /* Break out of read loop. */ + } + + /* Ensure we read at most the smaller of: + * (a) the length of the user-allocated buffer. + * (b) the maximum data length as specified by the `max_bytes` argument. + */ + if (max_bytes > buf.len) + max_bytes = buf.len; + + /* Read into the user buffer. */ + if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) { + uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + return 0; /* Break out of read loop. */ + } + + /* Call the read callback. */ + handle->read_cb((uv_stream_t*) handle, bytes_read, &buf); + + return bytes_read; +} + + +static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) { + uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining; + int err; + + if (*data_remaining > 0) { + /* Read frame data payload. */ + DWORD bytes_read = + uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining); + *data_remaining -= bytes_read; + return bytes_read; + + } else { + /* Start of a new IPC frame. */ + uv__ipc_frame_header_t frame_header; + uint32_t xfer_flags; + uv__ipc_socket_xfer_type_t xfer_type; + uv__ipc_socket_xfer_info_t xfer_info; + + /* Read the IPC frame header. */ + err = uv__pipe_read_exactly( + handle->handle, &frame_header, sizeof frame_header); + if (err) + goto error; + + /* Validate that flags are valid. */ + if ((frame_header.flags & ~UV__IPC_FRAME_VALID_FLAGS) != 0) + goto invalid; + /* Validate that reserved2 is zero. */ + if (frame_header.reserved2 != 0) + goto invalid; + + /* Parse xfer flags. */ + xfer_flags = frame_header.flags & UV__IPC_FRAME_XFER_FLAGS; + if (xfer_flags & UV__IPC_FRAME_HAS_SOCKET_XFER) { + /* Socket coming -- determine the type. */ + xfer_type = xfer_flags & UV__IPC_FRAME_XFER_IS_TCP_CONNECTION + ? UV__IPC_SOCKET_XFER_TCP_CONNECTION + : UV__IPC_SOCKET_XFER_TCP_SERVER; + } else if (xfer_flags == 0) { + /* No socket. */ + xfer_type = UV__IPC_SOCKET_XFER_NONE; + } else { + /* Invalid flags. */ + goto invalid; + } + + /* Parse data frame information. */ + if (frame_header.flags & UV__IPC_FRAME_HAS_DATA) { + *data_remaining = frame_header.data_length; + } else if (frame_header.data_length != 0) { + /* Data length greater than zero but data flag not set -- invalid. */ + goto invalid; + } + + /* If no socket xfer info follows, return here. Data will be read in a + * subsequent invocation of uv__pipe_read_ipc(). */ + if (xfer_type == UV__IPC_SOCKET_XFER_NONE) + return sizeof frame_header; /* Number of bytes read. */ + + /* Read transferred socket information. */ + err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info); + if (err) + goto error; + + /* Store the pending socket info. */ + uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info); + + /* Return number of bytes read. */ + return sizeof frame_header + sizeof xfer_info; + } + +invalid: + /* Invalid frame. */ + err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */ + +error: + uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); + return 0; /* Break out of read loop. */ +} + + +void uv_process_pipe_read_req(uv_loop_t* loop, + uv_pipe_t* handle, + uv_req_t* req) { assert(handle->type == UV_NAMED_PIPE); - handle->flags &= ~UV_HANDLE_READ_PENDING; + handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING); + DECREASE_PENDING_REQ_COUNT(handle); eof_timer_stop(handle); - if (!REQ_SUCCESS(req)) { - /* An error occurred doing the 0-read. */ - if (handle->flags & UV_HANDLE_READING) { - uv_pipe_read_error_or_eof(loop, - handle, - GET_REQ_ERROR(req), - uv_null_buf_); - } - } else { - /* Do non-blocking reads until the buffer is empty */ - while (handle->flags & UV_HANDLE_READING) { - if (!PeekNamedPipe(handle->handle, - NULL, - 0, - NULL, - &avail, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_); - break; - } + /* At this point, we're done with bookkeeping. If the user has stopped + * reading the pipe in the meantime, there is nothing left to do, since there + * is no callback that we can call. */ + if (!(handle->flags & UV_HANDLE_READING)) + return; - if (avail == 0) { - /* There is nothing to read after all. */ - break; - } + if (!REQ_SUCCESS(req)) { + /* An error occurred doing the zero-read. */ + DWORD err = GET_REQ_ERROR(req); - if (handle->ipc) { - /* Use the IPC framing protocol to read the incoming data. */ - if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) { - /* We're reading a new frame. First, read the header. */ - assert(avail >= sizeof(ipc_frame.header)); - - if (!ReadFile(handle->handle, - &ipc_frame.header, - sizeof(ipc_frame.header), - &bytes, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), - uv_null_buf_); - break; - } - - assert(bytes == sizeof(ipc_frame.header)); - assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA | - UV_IPC_TCP_CONNECTION)); - - if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) { - assert(avail - sizeof(ipc_frame.header) >= - sizeof(ipc_frame.socket_info_ex)); - - /* Read the TCP socket info. */ - if (!ReadFile(handle->handle, - &ipc_frame.socket_info_ex, - sizeof(ipc_frame) - sizeof(ipc_frame.header), - &bytes, - NULL)) { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), - uv_null_buf_); - break; - } - - assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header)); - - /* Store the pending socket info. */ - uv__pipe_insert_pending_socket( - handle, - &ipc_frame.socket_info_ex, - ipc_frame.header.flags & UV_IPC_TCP_CONNECTION); - } - - if (ipc_frame.header.flags & UV_IPC_RAW_DATA) { - handle->pipe.conn.remaining_ipc_rawdata_bytes = - ipc_frame.header.raw_data_length; - continue; - } - } else { - avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes); - } - } + /* If the read was cancelled by uv__pipe_interrupt_read(), the request may + * 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. */ + if (err != ERROR_OPERATION_ABORTED) + uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_); - buf = uv_buf_init(NULL, 0); - handle->alloc_cb((uv_handle_t*) handle, avail, &buf); - if (buf.base == NULL || buf.len == 0) { - handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf); + } else { + /* The zero-read completed without error, indicating there is data + * available in the kernel buffer. */ + DWORD avail; + + /* Get the number of bytes available. */ + avail = 0; + if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL)) + 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' + * flag is cleared. */ + while (avail > 0 && handle->flags & UV_HANDLE_READING) { + /* Depending on the type of pipe, read either IPC frames or raw data. */ + DWORD bytes_read = + handle->ipc ? uv__pipe_read_ipc(loop, handle) + : uv__pipe_read_data(loop, handle, avail, (DWORD) -1); + + /* If no bytes were read, treat this as an indication that an error + * occurred, and break out of the read loop. */ + if (bytes_read == 0) break; - } - assert(buf.base != NULL); - - if (ReadFile(handle->handle, - buf.base, - min(buf.len, avail), - &bytes, - NULL)) { - /* Successful read */ - if (handle->ipc) { - assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes); - handle->pipe.conn.remaining_ipc_rawdata_bytes = - handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes; - } - handle->read_cb((uv_stream_t*)handle, bytes, &buf); - /* Read again only if bytes == buf.len */ - if (bytes <= buf.len) { - break; - } - } else { - uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf); + /* It is possible that more bytes were read than we thought were + * available. To prevent `avail` from underflowing, break out of the loop + * if this is the case. */ + if (bytes_read > avail) break; - } - } - /* Post another 0-read if still reading and not closing. */ - if ((handle->flags & UV_HANDLE_READING) && - !(handle->flags & UV_HANDLE_READ_PENDING)) { - uv_pipe_queue_read(loop, handle); + /* Recompute the number of bytes available. */ + avail -= bytes_read; } } - DECREASE_PENDING_REQ_COUNT(handle); + /* Start another zero-read request if necessary. */ + if ((handle->flags & UV_HANDLE_READING) && + !(handle->flags & UV_HANDLE_READ_PENDING)) { + uv_pipe_queue_read(loop, handle); + } } @@ -1712,17 +1868,19 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, } } - if (req->ipc_header) { - if (req == &handle->pipe.conn.ipc_header_write_req) { - req->type = UV_UNKNOWN_REQ; - } else { - uv__free(req); - } - } else { - if (req->cb) { - err = GET_REQ_ERROR(req); - req->cb(req, uv_translate_sys_error(err)); - } + err = GET_REQ_ERROR(req); + + /* If this was a coalesced write, extract pointer to the user_provided + * uv_write_t structure so we can pass the expected pointer to the callback, + * then free the heap-allocated write req. */ + if (req->coalesced) { + uv__coalesced_write_t* coalesced_write = + container_of(req, uv__coalesced_write_t, req); + req = coalesced_write->user_req; + uv__free(coalesced_write); + } + if (req->cb) { + req->cb(req, uv_translate_sys_error(err)); } handle->stream.conn.write_reqs_pending--; @@ -1748,7 +1906,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->type == UV_NAMED_PIPE); - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */ assert(req->pipeHandle == INVALID_HANDLE_VALUE); DECREASE_PENDING_REQ_COUNT(handle); @@ -1768,7 +1926,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle, CloseHandle(req->pipeHandle); 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); } } @@ -1806,19 +1964,19 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, UNREGISTER_HANDLE_REQ(loop, handle, req); if (handle->flags & UV_HANDLE_READABLE) { - /* Initialize and optionally start the eof timer. Only do this if the */ - /* pipe is readable and we haven't seen EOF come in ourselves. */ + /* Initialize and optionally start the eof timer. Only do this if the pipe + * is readable and we haven't seen EOF come in ourselves. */ eof_timer_init(handle); - /* If reading start the timer right now. */ - /* Otherwise uv_pipe_queue_read will start it. */ + /* If 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. */ + /* This pipe is not readable. We can just close it to let the other end + * know that we're done writing. */ close_pipe(handle); } @@ -1869,17 +2027,16 @@ static void eof_timer_cb(uv_timer_t* timer) { assert(pipe->type == UV_NAMED_PIPE); - /* This should always be true, since we start the timer only */ - /* in uv_pipe_queue_read after successfully calling ReadFile, */ - /* or in uv_process_pipe_shutdown_req if a read is pending, */ - /* and we always immediately stop the timer in */ - /* uv_process_pipe_read_req. */ + /* This should always be true, since we start the timer only in + * uv_pipe_queue_read after successfully calling ReadFile, or in + * uv_process_pipe_shutdown_req if a read is pending, and we always + * immediately stop the timer in uv_process_pipe_read_req. */ assert(pipe->flags & UV_HANDLE_READ_PENDING); - /* If there are many packets coming off the iocp then the timer callback */ - /* may be called before the read request is coming off the queue. */ - /* Therefore we check here if the read request has completed but will */ - /* be processed later. */ + /* If there are many packets coming off the iocp then the timer callback may + * be called before the read request is coming off the queue. Therefore we + * check here if the read request has completed but will be processed later. + */ if ((pipe->flags & UV_HANDLE_READ_PENDING) && HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) { return; @@ -1888,12 +2045,12 @@ static void eof_timer_cb(uv_timer_t* timer) { /* Force both ends off the pipe. */ close_pipe(pipe); - /* Stop reading, so the pending read that is going to fail will */ - /* not be reported to the user. */ + /* Stop reading, so the pending read that is going to fail will not be + * reported to the user. */ uv_read_stop((uv_stream_t*) pipe); - /* Report the eof and update flags. This will get reported even if the */ - /* user stopped reading in the meantime. TODO: is that okay? */ + /* Report the eof and update flags. This will get reported even if the user + * stopped reading in the meantime. TODO: is that okay? */ uv_pipe_read_eof(loop, pipe, uv_null_buf_); } @@ -1980,8 +2137,8 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) { if (pipe->ipc) { assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)); - pipe->pipe.conn.ipc_pid = uv_os_getppid(); - assert(pipe->pipe.conn.ipc_pid != -1); + pipe->pipe.conn.ipc_remote_pid = uv_os_getppid(); + assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1); } return 0; } @@ -2006,7 +2163,15 @@ static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) return UV_EINVAL; } - uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */ + /* NtQueryInformationFile will block if another thread is performing a + * blocking operation on the queried handle. If the pipe handle is + * synchronous, there may be a worker thread currently calling ReadFile() on + * the pipe handle, which could cause a deadlock. To avoid this, interrupt + * the read. */ + if (handle->flags & UV_HANDLE_CONNECTION && + handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { + uv__pipe_interrupt_read((uv_pipe_t*) handle); /* cast away const warning */ + } nt_status = pNtQueryInformationFile(handle->handle, &io_status, @@ -2097,7 +2262,6 @@ error: uv__free(name_info); cleanup: - uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */ return err; } @@ -2105,7 +2269,7 @@ cleanup: int uv_pipe_pending_count(uv_pipe_t* handle) { if (!handle->ipc) return 0; - return handle->pipe.conn.pending_ipc_info.queue_len; + return handle->pipe.conn.ipc_xfer_queue_length; } @@ -2138,14 +2302,14 @@ int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) { uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { if (!handle->ipc) return UV_UNKNOWN_HANDLE; - if (handle->pipe.conn.pending_ipc_info.queue_len == 0) + if (handle->pipe.conn.ipc_xfer_queue_length == 0) return UV_UNKNOWN_HANDLE; else return UV_TCP; } int uv_pipe_chmod(uv_pipe_t* handle, int mode) { - SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY; + SID_IDENTIFIER_AUTHORITY sid_world = { SECURITY_WORLD_SID_AUTHORITY }; PACL old_dacl, new_dacl; PSECURITY_DESCRIPTOR sd; EXPLICIT_ACCESS ea; @@ -2180,7 +2344,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) { error = GetLastError(); goto clean_sid; } - + memset(&ea, 0, sizeof(EXPLICIT_ACCESS)); if (mode & UV_READABLE) ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; diff --git a/Utilities/cmlibuv/src/win/poll.c b/Utilities/cmlibuv/src/win/poll.c index a648ba7..3c66786 100644 --- a/Utilities/cmlibuv/src/win/poll.c +++ b/Utilities/cmlibuv/src/win/poll.c @@ -75,7 +75,7 @@ static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) { static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { uv_req_t* req; AFD_POLL_INFO* afd_poll_info; - DWORD result; + int result; /* Find a yet unsubmitted req to submit. */ if (handle->submitted_events_1 == 0) { @@ -91,16 +91,16 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { handle->mask_events_1 = handle->events; handle->mask_events_2 = 0; } else { - /* Just wait until there's an unsubmitted req. */ - /* This will happen almost immediately as one of the 2 outstanding */ - /* requests is about to return. When this happens, */ - /* uv__fast_poll_process_poll_req will be called, and the pending */ - /* events, if needed, will be processed in a subsequent request. */ + /* Just wait until there's an unsubmitted req. This will happen almost + * immediately as one of the 2 outstanding requests is about to return. + * When this happens, uv__fast_poll_process_poll_req will be called, and + * the pending events, if needed, will be processed in a subsequent + * request. */ return; } - /* Setting Exclusive to TRUE makes the other poll request return if there */ - /* is any. */ + /* Setting Exclusive to TRUE makes the other poll request return if there is + * any. */ afd_poll_info->Exclusive = TRUE; afd_poll_info->NumberOfHandles = 1; afd_poll_info->Timeout.QuadPart = INT64_MAX; @@ -136,7 +136,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) { AFD_POLL_INFO afd_poll_info; - DWORD result; + int result; afd_poll_info.Exclusive = TRUE; afd_poll_info.NumberOfHandles = 1; @@ -218,7 +218,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__fast_poll_submit_poll_req(loop, handle); - } else if ((handle->flags & UV__HANDLE_CLOSING) && + } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); @@ -228,7 +228,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); - assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0); handle->events = events; @@ -257,8 +257,8 @@ static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { uv_want_endgame(loop, (uv_handle_t*) handle); return 0; } else { - /* Cancel outstanding poll requests by executing another, unique poll */ - /* request that forces the outstanding ones to return. */ + /* Cancel outstanding poll requests by executing another, unique poll + * request that forces the outstanding ones to return. */ return uv__fast_poll_cancel_poll_req(loop, handle); } } @@ -316,9 +316,8 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, return INVALID_SOCKET; } - /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ - /* try again if the peer socket creation failed earlier for the same */ - /* protocol. */ + /* If we didn't (try) to create a peer socket yet, try to make one. Don't try + * again if the peer socket creation failed earlier for the same protocol. */ peer_socket = loop->poll_peer_sockets[index]; if (peer_socket == 0) { peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); @@ -357,8 +356,8 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { efds.fd_count = 0; } - /* Make the select() time out after 3 minutes. If select() hangs because */ - /* the user closed the socket, we will at least not hang indefinitely. */ + /* Make the select() time out after 3 minutes. If select() hangs because the + * user closed the socket, we will at least not hang indefinitely. */ timeout.tv_sec = 3 * 60; timeout.tv_usec = 0; @@ -462,7 +461,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__slow_poll_submit_poll_req(loop, handle); - } else if ((handle->flags & UV__HANDLE_CLOSING) && + } else if ((handle->flags & UV_HANDLE_CLOSING) && handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { uv_want_endgame(loop, (uv_handle_t*) handle); @@ -472,7 +471,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert(handle->type == UV_POLL); - assert(!(handle->flags & UV__HANDLE_CLOSING)); + assert(!(handle->flags & UV_HANDLE_CLOSING)); assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); handle->events = events; @@ -522,10 +521,10 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) return uv_translate_sys_error(WSAGetLastError()); - /* Try to obtain a base handle for the socket. This increases this chances */ - /* that we find an AFD handle and are able to use the fast poll mechanism. */ - /* This will always fail on windows XP/2k3, since they don't support the */ - /* SIO_BASE_HANDLE ioctl. */ +/* Try to obtain a base handle for the socket. This increases this chances that + * we find an AFD handle and are able to use the fast poll mechanism. This will + * always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE + * ioctl. */ #ifndef NDEBUG base_socket = INVALID_SOCKET; #endif @@ -557,9 +556,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, return uv_translate_sys_error(WSAGetLastError()); } - /* Get the peer socket that is needed to enable fast poll. If the returned */ - /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ - /* to use slow mode. */ + /* Get the peer socket that is needed to enable fast poll. If the returned + * value is NULL, the protocol is not implemented by MSAFD and we'll have to + * use slow mode. */ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); if (peer_socket != INVALID_SOCKET) { @@ -634,7 +633,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) { - assert(handle->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); assert(handle->submitted_events_1 == 0); diff --git a/Utilities/cmlibuv/src/win/process-stdio.c b/Utilities/cmlibuv/src/win/process-stdio.c index 032e309..355d618 100644 --- a/Utilities/cmlibuv/src/win/process-stdio.c +++ b/Utilities/cmlibuv/src/win/process-stdio.c @@ -103,12 +103,12 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, DWORD client_access = 0; HANDLE child_pipe = INVALID_HANDLE_VALUE; int err; + int overlap; if (flags & UV_READABLE_PIPE) { - /* The server needs inbound access too, otherwise CreateNamedPipe() */ - /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */ - /* probe the state of the write buffer when we're trying to shutdown */ - /* the pipe. */ + /* The server needs inbound access too, otherwise CreateNamedPipe() won't + * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the + * state of the write buffer when we're trying to shutdown the pipe. */ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND; client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES; } @@ -131,12 +131,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; + overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE); child_pipe = CreateFileA(pipe_name, client_access, 0, &sa, OPEN_EXISTING, - server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0, + overlap ? FILE_FLAG_OVERLAPPED : 0, NULL); if (child_pipe == INVALID_HANDLE_VALUE) { err = GetLastError(); @@ -159,8 +160,8 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop, } #endif - /* Do a blocking ConnectNamedPipe. This should not block because we have */ - /* both ends of the pipe created. */ + /* Do a blocking ConnectNamedPipe. This should not block because we have both + * ends of the pipe created. */ if (!ConnectNamedPipe(server_pipe->handle, NULL)) { if (GetLastError() != ERROR_PIPE_CONNECTED) { err = GetLastError(); @@ -194,11 +195,11 @@ static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { HANDLE current_process; - /* _get_osfhandle will sometimes return -2 in case of an error. This seems */ - /* to happen when fd <= 2 and the process' corresponding stdio handle is */ - /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */ - /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */ - /* use the duplicate. Therefore we filter out known-invalid handles here. */ + /* _get_osfhandle will sometimes return -2 in case of an error. This seems to + * happen when fd <= 2 and the process' corresponding stdio handle is set to + * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so + * this situation goes unnoticed until someone tries to use the duplicate. + * Therefore we filter out known-invalid handles here. */ if (handle == INVALID_HANDLE_VALUE || handle == NULL || handle == (HANDLE) -2) { @@ -284,8 +285,8 @@ int uv__stdio_create(uv_loop_t* loop, return ERROR_OUTOFMEMORY; } - /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */ - /* clean up on failure. */ + /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean + * up on failure. */ CHILD_STDIO_COUNT(buffer) = count; for (i = 0; i < count; i++) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; @@ -303,12 +304,12 @@ int uv__stdio_create(uv_loop_t* loop, switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM)) { case UV_IGNORE: - /* Starting a process with no stdin/stout/stderr can confuse it. */ - /* So no matter what the user specified, we make sure the first */ - /* three FDs are always open in their typical modes, e.g. stdin */ - /* be readable and stdout/err should be writable. For FDs > 2, don't */ - /* do anything - all handles in the stdio buffer are initialized with */ - /* INVALID_HANDLE_VALUE, which should be okay. */ + /* Starting a process with no stdin/stout/stderr can confuse it. So no + * matter what the user specified, we make sure the first three FDs are + * always open in their typical modes, e. g. stdin be readable and + * stdout/err should be writable. For FDs > 2, don't do anything - all + * handles in the stdio buffer are initialized with. + * INVALID_HANDLE_VALUE, which should be okay. */ if (i <= 2) { DWORD access = (i == 0) ? FILE_GENERIC_READ : FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; @@ -323,14 +324,14 @@ int uv__stdio_create(uv_loop_t* loop, break; case UV_CREATE_PIPE: { - /* Create a pair of two connected pipe ends; one end is turned into */ - /* an uv_pipe_t for use by the parent. The other one is given to */ - /* the child. */ + /* Create a pair of two connected pipe ends; one end is turned into an + * uv_pipe_t for use by the parent. The other one is given to the + * child. */ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; HANDLE child_pipe = INVALID_HANDLE_VALUE; - /* Create a new, connected pipe pair. stdio[i].stream should point */ - /* to an uninitialized, but not connected pipe handle. */ + /* Create a new, connected pipe pair. stdio[i]. stream should point to + * an uninitialized, but not connected pipe handle. */ assert(fdopt.data.stream->type == UV_NAMED_PIPE); assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); @@ -354,8 +355,8 @@ int uv__stdio_create(uv_loop_t* loop, /* Make an inheritable duplicate of the handle. */ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); if (err) { - /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */ - /* error. */ + /* If fdopt. data. fd is not valid and fd <= 2, then ignore the + * error. */ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE; @@ -418,8 +419,8 @@ int uv__stdio_create(uv_loop_t* loop, if (stream_handle == NULL || stream_handle == INVALID_HANDLE_VALUE) { - /* The handle is already closed, or not yet created, or the */ - /* stream type is not supported. */ + /* The handle is already closed, or not yet created, or the stream + * type is not supported. */ err = ERROR_NOT_SUPPORTED; goto error; } diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c index 25cfe87..24037b3 100644 --- a/Utilities/cmlibuv/src/win/process.c +++ b/Utilities/cmlibuv/src/win/process.c @@ -360,8 +360,8 @@ static WCHAR* search_path(const WCHAR *file, return NULL; } - /* Find the start of the filename so we can split the directory from the */ - /* name. */ + /* Find the start of the filename so we can split the directory from the + * name. */ for (file_name_start = (WCHAR*)file + file_len; file_name_start > file && file_name_start[-1] != L'\\' @@ -556,8 +556,8 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) { arg_count++; } - /* Adjust for potential quotes. Also assume the worst-case scenario */ - /* that every character needs escaping, so we need twice as much space. */ + /* Adjust for potential quotes. Also assume the worst-case scenario that + * every character needs escaping, so we need twice as much space. */ dst_len = dst_len * 2 + arg_count * 2; /* Allocate buffer for the final command line. */ @@ -739,7 +739,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { } } *ptr_copy = NULL; - assert(env_len == ptr - dst_copy); + assert(env_len == (size_t) (ptr - dst_copy)); /* sort our (UTF-16) copy */ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp); @@ -799,7 +799,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { var_size = GetEnvironmentVariableW(required_vars[i].wide, ptr, (int) (env_len - (ptr - dst))); - if (var_size != len-1) { /* race condition? */ + if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW"); } } @@ -815,7 +815,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { } /* Terminate with an extra NULL. */ - assert(env_len == (ptr - dst)); + assert(env_len == (size_t) (ptr - dst)); *ptr = L'\0'; uv__free(dst_copy); @@ -831,8 +831,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) { */ static WCHAR* find_path(WCHAR *env) { for (; env != NULL && *env != 0; env += wcslen(env) + 1) { - if (wcsncmp(env, L"PATH=", 5) == 0) + if ((env[0] == L'P' || env[0] == L'p') && + (env[1] == L'A' || env[1] == L'a') && + (env[2] == L'T' || env[2] == L't') && + (env[3] == L'H' || env[3] == L'h') && + (env[4] == L'=')) { return &env[5]; + } } return NULL; @@ -865,9 +870,9 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { assert(handle->exit_cb_pending); handle->exit_cb_pending = 0; - /* If we're closing, don't call the exit callback. Just schedule a close */ - /* callback now. */ - if (handle->flags & UV__HANDLE_CLOSING) { + /* If we're closing, don't call the exit callback. Just schedule a close + * callback now. */ + if (handle->flags & UV_HANDLE_CLOSING) { uv_want_endgame(loop, (uv_handle_t*) handle); return; } @@ -878,14 +883,14 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { handle->wait_handle = INVALID_HANDLE_VALUE; } - /* Set the handle to inactive: no callbacks will be made after the exit */ - /* callback.*/ + /* Set the handle to inactive: no callbacks will be made after the exit + * callback. */ uv__handle_stop(handle); if (GetExitCodeProcess(handle->process_handle, &status)) { exit_code = status; } else { - /* Unable to to obtain the exit code. This should never happen. */ + /* Unable to obtain the exit code. This should never happen. */ exit_code = uv_translate_sys_error(GetLastError()); } @@ -900,8 +905,8 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { uv__handle_closing(handle); if (handle->wait_handle != INVALID_HANDLE_VALUE) { - /* This blocks until either the wait was cancelled, or the callback has */ - /* completed. */ + /* This blocks until either the wait was cancelled, or the callback has + * completed. */ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE); if (!r) { /* This should never happen, and if it happens, we can't recover... */ @@ -919,7 +924,7 @@ void uv_process_close(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->flags & UV__HANDLE_CLOSING); + assert(handle->flags & UV_HANDLE_CLOSING); assert(!(handle->flags & UV_HANDLE_CLOSED)); /* Clean-up the process handle. */ @@ -965,6 +970,8 @@ int uv_spawn(uv_loop_t* loop, UV_PROCESS_SETGID | UV_PROCESS_SETUID | UV_PROCESS_WINDOWS_HIDE | + UV_PROCESS_WINDOWS_HIDE_CONSOLE | + UV_PROCESS_WINDOWS_HIDE_GUI | UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS))); err = uv_utf8_to_utf16_alloc(options->file, &application); @@ -1066,7 +1073,8 @@ int uv_spawn(uv_loop_t* loop, process_flags = CREATE_UNICODE_ENVIRONMENT; - if (options->flags & UV_PROCESS_WINDOWS_HIDE) { + if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) || + (options->flags & UV_PROCESS_WINDOWS_HIDE)) { /* Avoid creating console window if stdio is not inherited. */ for (i = 0; i < options->stdio_count; i++) { if (options->stdio[i].flags & UV_INHERIT_FD) @@ -1074,7 +1082,9 @@ int uv_spawn(uv_loop_t* loop, if (i == options->stdio_count - 1) process_flags |= CREATE_NO_WINDOW; } - + } + if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) || + (options->flags & UV_PROCESS_WINDOWS_HIDE)) { /* Use SW_HIDE to avoid any potential process window. */ startup.wShowWindow = SW_HIDE; } else { @@ -1160,14 +1170,13 @@ int uv_spawn(uv_loop_t* loop, } } - /* Spawn succeeded */ - /* Beyond this point, failure is reported asynchronously. */ + /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; - /* If the process isn't spawned as detached, assign to the global job */ - /* object so windows will kill it when the parent process dies. */ + /* If the process isn't spawned as detached, assign to the global job object + * so windows will kill it when the parent process dies. */ if (!(options->flags & UV_PROCESS_DETACHED)) { uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); @@ -1194,7 +1203,8 @@ int uv_spawn(uv_loop_t* loop, if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { - ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId; + ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid = + info.dwProcessId; } } @@ -1210,8 +1220,8 @@ int uv_spawn(uv_loop_t* loop, assert(!err); - /* Make the handle active. It will remain active until the exit callback */ - /* is made or the handle is closed, whichever happens first. */ + /* Make the handle active. It will remain active until the exit callback is + * made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* Cleanup, whether we succeeded or failed. */ @@ -1242,16 +1252,16 @@ static int uv__kill(HANDLE process_handle, int signum) { case SIGTERM: case SIGKILL: case SIGINT: { - /* Unconditionally terminate the process. On Windows, killed processes */ - /* normally return 1. */ + /* Unconditionally terminate the process. On Windows, killed processes + * normally return 1. */ DWORD status; int err; if (TerminateProcess(process_handle, 1)) return 0; - /* If the process already exited before TerminateProcess was called, */ - /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */ + /* If the process already exited before TerminateProcess was called,. + * TerminateProcess will fail with ERROR_ACCESS_DENIED. */ err = GetLastError(); if (err == ERROR_ACCESS_DENIED && GetExitCodeProcess(process_handle, &status) && diff --git a/Utilities/cmlibuv/src/win/req.c b/Utilities/cmlibuv/src/win/req.c deleted file mode 100644 index 111cc5e..0000000 --- a/Utilities/cmlibuv/src/win/req.c +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include <assert.h> - -#include "uv.h" -#include "internal.h" diff --git a/Utilities/cmlibuv/src/win/signal.c b/Utilities/cmlibuv/src/win/signal.c index a174da1..276dc60 100644 --- a/Utilities/cmlibuv/src/win/signal.c +++ b/Utilities/cmlibuv/src/win/signal.c @@ -47,13 +47,13 @@ void uv_signals_init(void) { static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) { - /* Compare signums first so all watchers with the same signnum end up */ - /* adjacent. */ + /* Compare signums first so all watchers with the same signnum end up + * adjacent. */ if (w1->signum < w2->signum) return -1; if (w1->signum > w2->signum) return 1; - /* Sort by loop pointer, so we can easily look up the first item after */ - /* { .signum = x, .loop = NULL } */ + /* Sort by loop pointer, so we can easily look up the first item after + * { .signum = x, .loop = NULL }. */ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1; if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1; @@ -90,7 +90,7 @@ int uv__signal_dispatch(int signum) { unsigned long previous = InterlockedExchange( (volatile LONG*) &handle->pending_signum, signum); - if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED) + if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED) continue; if (!previous) { @@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) { } dispatched = 1; - if (handle->flags & UV__SIGNAL_ONE_SHOT) - handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED; + if (handle->flags & UV_SIGNAL_ONE_SHOT) + handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED; } LeaveCriticalSection(&uv__signal_lock); @@ -118,10 +118,10 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { case CTRL_CLOSE_EVENT: if (uv__signal_dispatch(SIGHUP)) { - /* Windows will terminate the process after the control handler */ - /* returns. After that it will just terminate our process. Therefore */ - /* block the signal handler so the main loop has some time to pick */ - /* up the signal and do something for a few seconds. */ + /* Windows will terminate the process after the control handler + * returns. After that it will just terminate our process. Therefore + * block the signal handler so the main loop has some time to pick up + * the signal and do something for a few seconds. */ Sleep(INFINITE); return TRUE; } @@ -129,8 +129,8 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) { case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: - /* These signals are only sent to services. Services have their own */ - /* notification mechanism, so there's no point in handling these. */ + /* These signals are only sent to services. Services have their own + * notification mechanism, so there's no point in handling these. */ default: /* We don't handle these. */ @@ -190,13 +190,13 @@ int uv__signal_start(uv_signal_t* handle, int signum, int oneshot) { /* Test for invalid signal values. */ - if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG)) + if (signum <= 0 || signum >= NSIG) return UV_EINVAL; - /* Short circuit: if the signal watcher is already watching {signum} don't */ - /* go through the process of deregistering and registering the handler. */ - /* Additionally, this avoids pending signals getting lost in the (small) */ - /* time frame that handle->signum == 0. */ + /* Short circuit: if the signal watcher is already watching {signum} don't go + * through the process of deregistering and registering the handler. + * Additionally, this avoids pending signals getting lost in the (small) time + * frame that handle->signum == 0. */ if (signum == handle->signum) { handle->signal_cb = signal_cb; return 0; @@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle, handle->signum = signum; if (oneshot) - handle->flags |= UV__SIGNAL_ONE_SHOT; + handle->flags |= UV_SIGNAL_ONE_SHOT; RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle); @@ -237,16 +237,16 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle, (volatile LONG*) &handle->pending_signum, 0); assert(dispatched_signum != 0); - /* Check if the pending signal equals the signum that we are watching for. */ - /* These can get out of sync when the handler is stopped and restarted */ - /* while the signal_req is pending. */ + /* Check if the pending signal equals the signum that we are watching for. + * These can get out of sync when the handler is stopped and restarted while + * the signal_req is pending. */ if (dispatched_signum == handle->signum) handle->signal_cb(handle, dispatched_signum); - if (handle->flags & UV__SIGNAL_ONE_SHOT) + if (handle->flags & UV_SIGNAL_ONE_SHOT) uv_signal_stop(handle); - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { /* When it is closing, it must be stopped at this point. */ assert(handle->signum == 0); uv_want_endgame(loop, (uv_handle_t*) handle); @@ -265,7 +265,7 @@ void uv_signal_close(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->signum == 0); diff --git a/Utilities/cmlibuv/src/win/stream.c b/Utilities/cmlibuv/src/win/stream.c index 13cbfdc..7656627 100644 --- a/Utilities/cmlibuv/src/win/stream.c +++ b/Utilities/cmlibuv/src/win/stream.c @@ -105,12 +105,10 @@ int uv_read_stop(uv_stream_t* handle) { err = 0; if (handle->type == UV_TTY) { err = uv_tty_read_stop((uv_tty_t*) handle); + } else if (handle->type == UV_NAMED_PIPE) { + uv__pipe_read_stop((uv_pipe_t*) handle); } else { - if (handle->type == UV_NAMED_PIPE) { - uv__pipe_stop_read((uv_pipe_t*) handle); - } else { - handle->flags &= ~UV_HANDLE_READING; - } + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); } @@ -136,7 +134,8 @@ int uv_write(uv_write_t* req, err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb); break; case UV_NAMED_PIPE: - err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb); + err = uv__pipe_write( + loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb); break; case UV_TTY: err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb); @@ -158,25 +157,18 @@ int uv_write2(uv_write_t* req, uv_loop_t* loop = handle->loop; int err; - if (!(handle->flags & UV_HANDLE_WRITABLE)) { - return UV_EPIPE; + if (send_handle == NULL) { + return uv_write(req, handle, bufs, nbufs, cb); } - err = ERROR_INVALID_PARAMETER; - switch (handle->type) { - case UV_NAMED_PIPE: - err = uv_pipe_write2(loop, - req, - (uv_pipe_t*) handle, - bufs, - nbufs, - send_handle, - cb); - break; - default: - assert(0); + if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) { + return UV_EINVAL; + } else if (!(handle->flags & UV_HANDLE_WRITABLE)) { + return UV_EPIPE; } + err = uv__pipe_write( + loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb); return uv_translate_sys_error(err); } @@ -184,7 +176,7 @@ int uv_write2(uv_write_t* req, int uv_try_write(uv_stream_t* stream, const uv_buf_t bufs[], unsigned int nbufs) { - if (stream->flags & UV__HANDLE_CLOSING) + if (stream->flags & UV_HANDLE_CLOSING) return UV_EBADF; if (!(stream->flags & UV_HANDLE_WRITABLE)) return UV_EPIPE; diff --git a/Utilities/cmlibuv/src/win/tcp.c b/Utilities/cmlibuv/src/win/tcp.c index 39c1ff0..3ce5548 100644 --- a/Utilities/cmlibuv/src/win/tcp.c +++ b/Utilities/cmlibuv/src/win/tcp.c @@ -99,8 +99,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop, if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0)) return GetLastError(); - /* Associate it with the I/O completion port. */ - /* Use uv_handle_t pointer as completion key. */ + /* Associate it with the I/O completion port. Use uv_handle_t pointer as + * completion key. */ if (CreateIoCompletionPort((HANDLE)socket, loop->iocp, (ULONG_PTR)socket, @@ -118,15 +118,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4; } - if (pSetFileCompletionNotificationModes && - !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { - if (pSetFileCompletionNotificationModes((HANDLE) socket, - FILE_SKIP_SET_EVENT_ON_HANDLE | - FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { - handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; - } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) { + UCHAR sfcnm_flags = + FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS; + if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags)) return GetLastError(); - } + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; } if (handle->flags & UV_HANDLE_TCP_NODELAY) { @@ -220,7 +217,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req); err = 0; - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { err = ERROR_OPERATION_ABORTED; } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) { err = WSAGetLastError(); @@ -236,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { return; } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -326,9 +323,9 @@ static int uv_tcp_try_bind(uv_tcp_t* handle, on = (flags & UV_TCP_IPV6ONLY) != 0; - /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ - /* available, or when run on XP/2003 which have no support for dualstack */ - /* sockets. For now we're silently ignoring the error. */ + /* TODO: how to handle errors? This may fail if there is no ipv4 stack + * available, or when run on XP/2003 which have no support for dualstack + * sockets. For now we're silently ignoring the error. */ setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, @@ -626,9 +623,9 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { uv_tcp_queue_accept(handle, req); } - /* Initialize other unused requests too, because uv_tcp_endgame */ - /* doesn't know how how many requests were initialized, so it will */ - /* try to clean up {uv_simultaneous_server_accepts} requests. */ + /* Initialize other unused requests too, because uv_tcp_endgame doesn't + * know how many requests were initialized, so it will try to clean up + * {uv_simultaneous_server_accepts} requests. */ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) { req = &handle->tcp.serv.accept_reqs[i]; UV_REQ_INIT(req, UV_ACCEPT); @@ -683,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) { req->next_pending = NULL; req->accept_socket = INVALID_SOCKET; - 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. */ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) { uv_tcp_queue_accept(server, req); @@ -721,8 +718,8 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, handle->alloc_cb = alloc_cb; INCREASE_ACTIVE_COUNT(loop, handle); - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && !handle->read_req.event_handle) { @@ -948,6 +945,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req) { DWORD bytes, flags, err; uv_buf_t buf; + int count; assert(handle->type == UV_TCP); @@ -965,8 +963,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, err = GET_REQ_SOCK_ERROR(req); if (err == WSAECONNABORTED) { - /* - * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. */ err = WSAECONNRESET; } @@ -1003,7 +1000,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } /* Do nonblocking reads until the buffer is empty */ - while (handle->flags & UV_HANDLE_READING) { + count = 32; + while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) { buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); if (buf.base == NULL || buf.len == 0) { @@ -1046,8 +1044,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, DECREASE_ACTIVE_COUNT(loop, handle); if (err == WSAECONNABORTED) { - /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ - /* Unix. */ + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with + * Unix. */ err = WSAECONNRESET; } @@ -1119,10 +1117,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->type == UV_TCP); - /* If handle->accepted_socket is not a valid socket, then */ - /* uv_queue_accept must have failed. This is a serious error. We stop */ - /* accepting connections and report this error to the connection */ - /* callback. */ + /* If handle->accepted_socket is not a valid socket, then uv_queue_accept + * must have failed. This is a serious error. We stop accepting connections + * and report this error to the connection callback. */ if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; @@ -1147,9 +1144,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, handle->stream.serv.connection_cb((uv_stream_t*)handle, 0); } } else { - /* Error related to accepted socket is ignored because the server */ - /* socket may still be healthy. If the server socket is broken */ - /* uv_queue_accept will detect it. */ + /* Error related to accepted socket is ignored because the server socket + * may still be healthy. If the server socket is broken uv_queue_accept + * will detect it. */ closesocket(req->accept_socket); req->accept_socket = INVALID_SOCKET; if (handle->flags & UV_HANDLE_LISTENING) { @@ -1171,7 +1168,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, err = 0; if (REQ_SUCCESS(req)) { - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { /* use UV_ECANCELED for consistency with Unix */ err = ERROR_OPERATION_ABORTED; } else if (setsockopt(handle->socket, @@ -1194,40 +1191,76 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, } -int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex, - int tcp_connection) { +int uv__tcp_xfer_export(uv_tcp_t* handle, + int target_pid, + uv__ipc_socket_xfer_type_t* xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { + if (handle->flags & UV_HANDLE_CONNECTION) { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION; + } else { + *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER; + /* We're about to share the socket with another process. Because this is a + * listening socket, we assume that the other process will be accepting + * connections on it. Thus, before sharing the socket with another process, + * we call listen here in the parent process. */ + if (!(handle->flags & UV_HANDLE_LISTENING)) { + if (!(handle->flags & UV_HANDLE_BOUND)) { + return ERROR_NOT_SUPPORTED; + } + if (handle->delayed_error == 0 && + listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { + handle->delayed_error = WSAGetLastError(); + } + } + } + + if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info)) + return WSAGetLastError(); + xfer_info->delayed_error = handle->delayed_error; + + /* Mark the local copy of the handle as 'shared' so we behave in a way that's + * friendly to the process(es) that we share the socket with. */ + handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; + + return 0; +} + + +int uv__tcp_xfer_import(uv_tcp_t* tcp, + uv__ipc_socket_xfer_type_t xfer_type, + uv__ipc_socket_xfer_info_t* xfer_info) { int err; - SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - FROM_PROTOCOL_INFO, - &socket_info_ex->socket_info, - 0, - WSA_FLAG_OVERLAPPED); + SOCKET socket; + + assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER || + xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION); + + socket = WSASocketW(FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + FROM_PROTOCOL_INFO, + &xfer_info->socket_info, + 0, + WSA_FLAG_OVERLAPPED); if (socket == INVALID_SOCKET) { return WSAGetLastError(); } - err = uv_tcp_set_socket(tcp->loop, - tcp, - socket, - socket_info_ex->socket_info.iAddressFamily, - 1); + err = uv_tcp_set_socket( + tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1); if (err) { closesocket(socket); return err; } - if (tcp_connection) { + tcp->delayed_error = xfer_info->delayed_error; + tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET; + + if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) { uv_connection_init((uv_stream_t*)tcp); tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE; } - tcp->flags |= UV_HANDLE_BOUND; - tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET; - - tcp->delayed_error = socket_info_ex->delayed_error; - tcp->loop->active_tcp_streams++; return 0; } @@ -1273,39 +1306,6 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } -int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, - LPWSAPROTOCOL_INFOW protocol_info) { - if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* - * We're about to share the socket with another process. Because - * this is a listening socket, we assume that the other process will - * be accepting connections on it. So, before sharing the socket - * with another process, we call listen here in the parent process. - */ - - if (!(handle->flags & UV_HANDLE_LISTENING)) { - if (!(handle->flags & UV_HANDLE_BOUND)) { - return ERROR_INVALID_PARAMETER; - } - - if (!(handle->delayed_error)) { - if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) { - handle->delayed_error = WSAGetLastError(); - } - } - } - } - - if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) { - return WSAGetLastError(); - } - - handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET; - - return 0; -} - - int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { if (handle->flags & UV_HANDLE_CONNECTION) { return UV_EINVAL; @@ -1346,8 +1346,8 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) { non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 : uv_tcp_non_ifs_lsp_ipv4; - /* If there are non-ifs LSPs then try to obtain a base handle for the */ - /* socket. This will always fail on Windows XP/3k. */ + /* If there are non-ifs LSPs then try to obtain a base handle for the socket. + * This will always fail on Windows XP/3k. */ if (non_ifs_lsp) { DWORD bytes; if (WSAIoctl(socket, @@ -1379,38 +1379,37 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int close_socket = 1; if (tcp->flags & UV_HANDLE_READ_PENDING) { - /* In order for winsock to do a graceful close there must not be any */ - /* any pending reads, or the socket must be shut down for writing */ + /* In order for winsock to do a graceful close there must not be any any + * pending reads, or the socket must be shut down for writing */ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) { /* Just do shutdown on non-shared sockets, which ensures graceful close. */ shutdown(tcp->socket, SD_SEND); } else if (uv_tcp_try_cancel_io(tcp) == 0) { - /* In case of a shared socket, we try to cancel all outstanding I/O, */ - /* If that works, don't close the socket yet - wait for the read req to */ - /* return and close the socket in uv_tcp_endgame. */ + /* In case of a shared socket, we try to cancel all outstanding I/O,. If + * that works, don't close the socket yet - wait for the read req to + * return and close the socket in uv_tcp_endgame. */ close_socket = 0; } else { - /* When cancelling isn't possible - which could happen when an LSP is */ - /* present on an old Windows version, we will have to close the socket */ - /* with a read pending. That is not nice because trailing sent bytes */ - /* may not make it to the other side. */ + /* When cancelling isn't possible - which could happen when an LSP is + * present on an old Windows version, we will have to close the socket + * with a read pending. That is not nice because trailing sent bytes may + * not make it to the other side. */ } } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) && tcp->tcp.serv.accept_reqs != NULL) { - /* Under normal circumstances closesocket() will ensure that all pending */ - /* accept reqs are canceled. However, when the socket is shared the */ - /* presence of another reference to the socket in another process will */ - /* keep the accept reqs going, so we have to ensure that these are */ - /* canceled. */ + /* Under normal circumstances closesocket() will ensure that all pending + * accept reqs are canceled. However, when the socket is shared the + * presence of another reference to the socket in another process will keep + * the accept reqs going, so we have to ensure that these are canceled. */ if (uv_tcp_try_cancel_io(tcp) != 0) { - /* When cancellation is not possible, there is another option: we can */ - /* close the incoming sockets, which will also cancel the accept */ - /* operations. However this is not cool because we might inadvertently */ - /* close a socket that just accepted a new connection, which will */ - /* cause the connection to be aborted. */ + /* When cancellation is not possible, there is another option: we can + * close the incoming sockets, which will also cancel the accept + * operations. However this is not cool because we might inadvertently + * close a socket that just accepted a new connection, which will cause + * the connection to be aborted. */ unsigned int i; for (i = 0; i < uv_simultaneous_server_accepts; i++) { uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i]; diff --git a/Utilities/cmlibuv/src/win/thread.c b/Utilities/cmlibuv/src/win/thread.c index 9eaad77..fd4b7c9 100644 --- a/Utilities/cmlibuv/src/win/thread.c +++ b/Utilities/cmlibuv/src/win/thread.c @@ -23,29 +23,15 @@ #include <limits.h> #include <stdlib.h> +#if defined(__MINGW64_VERSION_MAJOR) +/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may + * require this header in some versions of mingw64. */ +#include <intrin.h> +#endif + #include "uv.h" #include "internal.h" - -#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) - -static int uv_cond_fallback_init(uv_cond_t* cond); -static void uv_cond_fallback_destroy(uv_cond_t* cond); -static void uv_cond_fallback_signal(uv_cond_t* cond); -static void uv_cond_fallback_broadcast(uv_cond_t* cond); -static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex); -static int uv_cond_fallback_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout); - -static int uv_cond_condvar_init(uv_cond_t* cond); -static void uv_cond_condvar_destroy(uv_cond_t* cond); -static void uv_cond_condvar_signal(uv_cond_t* cond); -static void uv_cond_condvar_broadcast(uv_cond_t* cond); -static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex); -static int uv_cond_condvar_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout); - - static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { DWORD result; HANDLE existing_event, created_event; @@ -69,8 +55,8 @@ static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) { guard->ran = 1; } else { - /* We lost the race. Destroy the event we created and wait for the */ - /* existing one to become signaled. */ + /* We lost the race. Destroy the event we created and wait for the existing + * one to become signaled. */ CloseHandle(created_event); result = WaitForSingleObject(existing_event, INFINITE); assert(result == WAIT_OBJECT_0); @@ -138,7 +124,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { ctx->arg = arg; /* Create the thread in suspended state so we have a chance to pass - * its own creation handle to it */ + * its own creation handle to it */ thread = (HANDLE) _beginthreadex(NULL, 0, uv__thread_start, @@ -377,220 +363,35 @@ int uv_sem_trywait(uv_sem_t* sem) { } -/* This condition variable implementation is based on the SetEvent solution - * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html - * We could not use the SignalObjectAndWait solution (section 3.4) because - * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and - * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs. - */ - -static int uv_cond_fallback_init(uv_cond_t* cond) { - int err; - - /* Initialize the count to 0. */ - cond->fallback.waiters_count = 0; - - InitializeCriticalSection(&cond->fallback.waiters_count_lock); - - /* Create an auto-reset event. */ - cond->fallback.signal_event = CreateEvent(NULL, /* no security */ - FALSE, /* auto-reset event */ - FALSE, /* non-signaled initially */ - NULL); /* unnamed */ - if (!cond->fallback.signal_event) { - err = GetLastError(); - goto error2; - } - - /* Create a manual-reset event. */ - cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */ - TRUE, /* manual-reset */ - FALSE, /* non-signaled */ - NULL); /* unnamed */ - if (!cond->fallback.broadcast_event) { - err = GetLastError(); - goto error; - } - - return 0; - -error: - CloseHandle(cond->fallback.signal_event); -error2: - DeleteCriticalSection(&cond->fallback.waiters_count_lock); - return uv_translate_sys_error(err); -} - - -static int uv_cond_condvar_init(uv_cond_t* cond) { - pInitializeConditionVariable(&cond->cond_var); - return 0; -} - - int uv_cond_init(uv_cond_t* cond) { - uv__once_init(); - - if (HAVE_CONDVAR_API()) - return uv_cond_condvar_init(cond); - else - return uv_cond_fallback_init(cond); -} - - -static void uv_cond_fallback_destroy(uv_cond_t* cond) { - if (!CloseHandle(cond->fallback.broadcast_event)) - abort(); - if (!CloseHandle(cond->fallback.signal_event)) - abort(); - DeleteCriticalSection(&cond->fallback.waiters_count_lock); -} - - -static void uv_cond_condvar_destroy(uv_cond_t* cond) { - /* nothing to do */ + InitializeConditionVariable(&cond->cond_var); + return 0; } void uv_cond_destroy(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_destroy(cond); - else - uv_cond_fallback_destroy(cond); -} - - -static void uv_cond_fallback_signal(uv_cond_t* cond) { - int have_waiters; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - have_waiters = cond->fallback.waiters_count > 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - if (have_waiters) - SetEvent(cond->fallback.signal_event); -} - - -static void uv_cond_condvar_signal(uv_cond_t* cond) { - pWakeConditionVariable(&cond->cond_var); + /* nothing to do */ + (void) &cond; } void uv_cond_signal(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_signal(cond); - else - uv_cond_fallback_signal(cond); -} - - -static void uv_cond_fallback_broadcast(uv_cond_t* cond) { - int have_waiters; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - have_waiters = cond->fallback.waiters_count > 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - if (have_waiters) - SetEvent(cond->fallback.broadcast_event); -} - - -static void uv_cond_condvar_broadcast(uv_cond_t* cond) { - pWakeAllConditionVariable(&cond->cond_var); + WakeConditionVariable(&cond->cond_var); } void uv_cond_broadcast(uv_cond_t* cond) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_broadcast(cond); - else - uv_cond_fallback_broadcast(cond); -} - - -static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex, - DWORD dwMilliseconds) { - DWORD result; - int last_waiter; - HANDLE handles[2] = { - cond->fallback.signal_event, - cond->fallback.broadcast_event - }; - - /* Avoid race conditions. */ - EnterCriticalSection(&cond->fallback.waiters_count_lock); - cond->fallback.waiters_count++; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - /* It's ok to release the <mutex> here since Win32 manual-reset events */ - /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */ - /* bug. */ - uv_mutex_unlock(mutex); - - /* Wait for either event to become signaled due to <uv_cond_signal> being */ - /* called or <uv_cond_broadcast> being called. */ - result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds); - - EnterCriticalSection(&cond->fallback.waiters_count_lock); - cond->fallback.waiters_count--; - last_waiter = result == WAIT_OBJECT_0 + 1 - && cond->fallback.waiters_count == 0; - LeaveCriticalSection(&cond->fallback.waiters_count_lock); - - /* Some thread called <pthread_cond_broadcast>. */ - if (last_waiter) { - /* We're the last waiter to be notified or to stop waiting, so reset the */ - /* the manual-reset event. */ - ResetEvent(cond->fallback.broadcast_event); - } - - /* Reacquire the <mutex>. */ - uv_mutex_lock(mutex); - - if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1) - return 0; - - if (result == WAIT_TIMEOUT) - return UV_ETIMEDOUT; - - abort(); - return -1; /* Satisfy the compiler. */ -} - - -static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (uv_cond_wait_helper(cond, mutex, INFINITE)) - abort(); -} - - -static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) - abort(); + WakeAllConditionVariable(&cond->cond_var); } void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { - if (HAVE_CONDVAR_API()) - uv_cond_condvar_wait(cond, mutex); - else - uv_cond_fallback_wait(cond, mutex); -} - - -static int uv_cond_fallback_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout) { - return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6)); + if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE)) + abort(); } - -static int uv_cond_condvar_timedwait(uv_cond_t* cond, - uv_mutex_t* mutex, uint64_t timeout) { - if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) +int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { + if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6))) return 0; if (GetLastError() != ERROR_TIMEOUT) abort(); @@ -598,15 +399,6 @@ static int uv_cond_condvar_timedwait(uv_cond_t* cond, } -int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, - uint64_t timeout) { - if (HAVE_CONDVAR_API()) - return uv_cond_condvar_timedwait(cond, mutex, timeout); - else - return uv_cond_fallback_timedwait(cond, mutex, timeout); -} - - int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { int err; diff --git a/Utilities/cmlibuv/src/win/timer.c b/Utilities/cmlibuv/src/win/timer.c deleted file mode 100644 index 7e006fe..0000000 --- a/Utilities/cmlibuv/src/win/timer.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#include <assert.h> -#include <limits.h> - -#include "uv.h" -#include "internal.h" -#include "tree.h" -#include "handle-inl.h" - - -/* The number of milliseconds in one second. */ -#define UV__MILLISEC 1000 - - -void uv_update_time(uv_loop_t* loop) { - uint64_t new_time = uv__hrtime(UV__MILLISEC); - assert(new_time >= loop->time); - loop->time = new_time; -} - - -static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { - if (a->due < b->due) - return -1; - if (a->due > b->due) - return 1; - /* - * compare start_id when both has the same due. start_id is - * allocated with loop->timer_counter in uv_timer_start(). - */ - if (a->start_id < b->start_id) - return -1; - if (a->start_id > b->start_id) - return 1; - return 0; -} - - -RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare) - - -int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER); - handle->timer_cb = NULL; - handle->repeat = 0; - - return 0; -} - - -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { - if (handle->flags & UV__HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - uv__handle_close(handle); - } -} - - -static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { - uint64_t clamped_timeout; - - clamped_timeout = loop_time + timeout; - if (clamped_timeout < timeout) - clamped_timeout = (uint64_t) -1; - - return clamped_timeout; -} - - -int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, - uint64_t repeat) { - uv_loop_t* loop = handle->loop; - uv_timer_t* old; - - if (timer_cb == NULL) - return UV_EINVAL; - - if (uv__is_active(handle)) - uv_timer_stop(handle); - - handle->timer_cb = timer_cb; - handle->due = get_clamped_due_time(loop->time, timeout); - handle->repeat = repeat; - uv__handle_start(handle); - - /* start_id is the second index to be compared in uv__timer_cmp() */ - handle->start_id = handle->loop->timer_counter++; - - old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle); - assert(old == NULL); - - return 0; -} - - -int uv_timer_stop(uv_timer_t* handle) { - uv_loop_t* loop = handle->loop; - - if (!uv__is_active(handle)) - return 0; - - RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); - uv__handle_stop(handle); - - return 0; -} - - -int uv_timer_again(uv_timer_t* handle) { - /* If timer_cb is NULL that means that the timer was never started. */ - if (!handle->timer_cb) { - return UV_EINVAL; - } - - if (handle->repeat) { - uv_timer_stop(handle); - uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat); - } - - return 0; -} - - -void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) { - assert(handle->type == UV_TIMER); - handle->repeat = repeat; -} - - -uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { - assert(handle->type == UV_TIMER); - return handle->repeat; -} - - -DWORD uv__next_timeout(const uv_loop_t* loop) { - uv_timer_t* timer; - int64_t delta; - - /* Check if there are any running timers - * Need to cast away const first, since RB_MIN doesn't know what we are - * going to do with this return value, it can't be marked const - */ - timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers); - if (timer) { - delta = timer->due - loop->time; - if (delta >= UINT_MAX - 1) { - /* A timeout value of UINT_MAX means infinite, so that's no good. */ - return UINT_MAX - 1; - } else if (delta < 0) { - /* Negative timeout values are not allowed */ - return 0; - } else { - return (DWORD)delta; - } - } else { - /* No timers */ - return INFINITE; - } -} - - -void uv_process_timers(uv_loop_t* loop) { - uv_timer_t* timer; - - /* Call timer callbacks */ - for (timer = RB_MIN(uv_timer_tree_s, &loop->timers); - timer != NULL && timer->due <= loop->time; - timer = RB_MIN(uv_timer_tree_s, &loop->timers)) { - - uv_timer_stop(timer); - uv_timer_again(timer); - timer->timer_cb((uv_timer_t*) timer); - } -} diff --git a/Utilities/cmlibuv/src/win/tty.c b/Utilities/cmlibuv/src/win/tty.c index ecf7bc9..f38e9a8 100644 --- a/Utilities/cmlibuv/src/win/tty.c +++ b/Utilities/cmlibuv/src/win/tty.c @@ -25,7 +25,7 @@ #include <stdlib.h> #if defined(_MSC_VER) && _MSC_VER < 1600 -# include "stdint-msvc2008.h" +# include "uv/stdint-msvc2008.h" #else # include <stdint.h> #endif @@ -164,7 +164,7 @@ void uv_console_init(void) { OPEN_EXISTING, 0, 0); - if (uv__tty_console_handle != NULL) { + if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, NULL, WT_EXECUTELONGFUNCTION); @@ -172,9 +172,12 @@ void uv_console_init(void) { } -int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { +int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) { + BOOL readable; + DWORD NumberOfEvents; HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; + (void)unused; uv__once_init(); handle = (HANDLE) uv__get_osfhandle(fd); @@ -199,14 +202,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { fd = -1; } + readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents); if (!readable) { /* Obtain the screen buffer info with the output handle. */ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) { return uv_translate_sys_error(GetLastError()); } - /* Obtain the the tty_output_lock because the virtual window state is */ - /* shared between all uv_tty_t handles. */ + /* Obtain the tty_output_lock because the virtual window state is shared + * between all uv_tty_t handles. */ uv_sem_wait(&uv_tty_output_lock); if (uv__vterm_state == UV_UNCHECKED) @@ -356,6 +360,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } } else { was_reading = 0; + alloc_cb = NULL; + read_cb = NULL; } uv_sem_wait(&uv_tty_output_lock); @@ -382,12 +388,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } -int uv_is_tty(uv_file file) { - DWORD result; - return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0; -} - - int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { CONSOLE_SCREEN_BUFFER_INFO info; @@ -484,8 +484,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { bytes = MAX_INPUT_BUFFER_LENGTH; } - /* At last, unicode! */ - /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ + /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8 + * codeunits to encode. */ chars = bytes / 3; status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); @@ -620,10 +620,10 @@ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl, } switch (code) { - /* These mappings are the same as Cygwin's. Unmodified and alt-modified */ - /* keypad keys comply with linux console, modifiers comply with xterm */ - /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */ - /* f6..f12 with and without modifiers comply with rxvt. */ + /* These mappings are the same as Cygwin's. Unmodified and alt-modified + * keypad keys comply with linux console, modifiers comply with xterm + * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6. + * f12 with and without modifiers comply with rxvt. */ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~") VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~") VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B") @@ -706,8 +706,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, goto out; } - /* Windows sends a lot of events that we're not interested in, so buf */ - /* will be allocated on demand, when there's actually something to emit. */ + /* Windows sends a lot of events that we're not interested in, so buf will be + * allocated on demand, when there's actually something to emit. */ buf = uv_null_buf_; buf_used = 0; @@ -733,16 +733,17 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, continue; } - /* Ignore keyup events, unless the left alt key was held and a valid */ - /* unicode character was emitted. */ - if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || - KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { + /* Ignore keyup events, unless the left alt key was held and a valid + * unicode character was emitted. */ + if (!KEV.bKeyDown && + KEV.wVirtualKeyCode != VK_MENU && + KEV.uChar.UnicodeChar != 0) { continue; } - /* Ignore keypresses to numpad number keys if the left alt is held */ - /* because the user is composing a character, or windows simulating */ - /* this. */ + /* Ignore keypresses to numpad number keys if the left alt is held + * because the user is composing a character, or windows simulating this. + */ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) && !(KEV.dwControlKeyState & ENHANCED_KEY) && (KEV.wVirtualKeyCode == VK_INSERT || @@ -779,8 +780,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, continue; } - /* Prefix with \u033 if alt was held, but alt was not used as part */ - /* a compose sequence. */ + /* Prefix with \u033 if alt was held, but alt was not used as part a + * compose sequence. */ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) { @@ -793,8 +794,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (KEV.uChar.UnicodeChar >= 0xDC00 && KEV.uChar.UnicodeChar < 0xE000) { /* UTF-16 surrogate pair */ - WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate, - KEV.uChar.UnicodeChar}; + WCHAR utf16_buffer[2]; + utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate; + utf16_buffer[1] = KEV.uChar.UnicodeChar; char_len = WideCharToMultiByte(CP_UTF8, 0, utf16_buffer, @@ -818,8 +820,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Whatever happened, the last character wasn't a high surrogate. */ handle->tty.rd.last_utf16_high_surrogate = 0; - /* If the utf16 character(s) couldn't be converted something must */ - /* be wrong. */ + /* If the utf16 character(s) couldn't be converted something must be + * wrong. */ if (!char_len) { handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -943,21 +945,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, handle->read_cb((uv_stream_t*) handle, uv_translate_sys_error(GET_REQ_ERROR(req)), &buf); - } else { - /* The read was cancelled, or whatever we don't care */ - handle->read_cb((uv_stream_t*) handle, 0, &buf); } - } else { - if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { - /* Read successful */ - /* TODO: read unicode, convert to utf-8 */ + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) && + req->u.io.overlapped.InternalHigh != 0) { + /* Read successful. TODO: read unicode, convert to utf-8 */ DWORD bytes = req->u.io.overlapped.InternalHigh; handle->read_cb((uv_stream_t*) handle, bytes, &buf); - } else { - handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; - handle->read_cb((uv_stream_t*) handle, 0, &buf); } + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; } /* Wait for more input events. */ @@ -975,9 +971,9 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle, assert(handle->type == UV_TTY); assert(handle->flags & UV_HANDLE_TTY_READABLE); - /* If the read_line_buffer member is zero, it must have been an raw read. */ - /* Otherwise it was a line-buffered read. */ - /* FIXME: This is quite obscure. Use a flag or something. */ + /* If the read_line_buffer member is zero, it must have been an raw read. + * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a + * flag or something. */ if (handle->tty.rd.read_line_buffer.len == 0) { uv_process_tty_read_raw_req(loop, handle, req); } else { @@ -999,14 +995,14 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* read request pending. */ + /* If reading was stopped and then started again, there could still be a read + * request pending. */ if (handle->flags & UV_HANDLE_READ_PENDING) { return 0; } - /* Maybe the user stopped reading half-way while processing key events. */ - /* Short-circuit if this could be the case. */ + /* Maybe the user stopped reading half-way while processing key events. + * Short-circuit if this could be the case. */ if (handle->tty.rd.last_key_len > 0) { SET_REQ_SUCCESS(&handle->read_req); uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); @@ -1033,9 +1029,10 @@ int uv_tty_read_stop(uv_tty_t* handle) { return 0; if (handle->flags & UV_HANDLE_TTY_RAW) { - /* Cancel raw read */ - /* Write some bullshit event to force the console wait to return. */ + /* Cancel raw read. Write some bullshit event to force the console wait to + * return. */ memset(&record, 0, sizeof record); + record.EventType = FOCUS_EVENT; if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); } @@ -1116,8 +1113,8 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) { uv_tty_virtual_offset = info->dwCursorPosition.Y; } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y - uv_tty_virtual_height + 1) { - /* If suddenly find the cursor outside of the virtual window, it must */ - /* have somehow scrolled. Update the virtual window offset. */ + /* If suddenly find the cursor outside of the virtual window, it must have + * somehow scrolled. Update the virtual window offset. */ uv_tty_virtual_offset = info->dwCursorPosition.Y - uv_tty_virtual_height + 1; } @@ -1304,8 +1301,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, x2 = 0; x2r = 1; } else { - /* 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. */ + /* 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. */ x2 = 0xffff; x2r = 0; } @@ -1613,8 +1610,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, const uv_buf_t bufs[], unsigned int nbufs, DWORD* error) { - /* We can only write 8k characters at a time. Windows can't handle */ - /* much more characters in a single console write anyway. */ + /* We can only write 8k characters at a time. Windows can't handle much more + * characters in a single console write anyway. */ WCHAR utf16_buf[MAX_CONSOLE_CHAR]; WCHAR* utf16_buffer; DWORD utf16_buf_used = 0; @@ -1650,9 +1647,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, unsigned char previous_eol = handle->tty.wr.previous_eol; unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state; - /* Store the error here. If we encounter an error, stop trying to do i/o */ - /* but keep parsing the buffer so we leave the parser in a consistent */ - /* state. */ + /* Store the error here. If we encounter an error, stop trying to do i/o but + * keep parsing the buffer so we leave the parser in a consistent state. */ *error = ERROR_SUCCESS; utf16_buffer = utf16_buf; @@ -1700,9 +1696,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, for (j = 0; j < buf.len; j++) { unsigned char c = buf.base[j]; - /* Run the character through the utf8 decoder We happily accept non */ - /* shortest form encodings and invalid code points - there's no real */ - /* harm that can be done. */ + /* Run the character through the utf8 decoder We happily accept non + * shortest form encodings and invalid code points - there's no real harm + * that can be done. */ if (utf8_bytes_left == 0) { /* Read utf-8 start byte */ DWORD first_zero_bit; @@ -1742,8 +1738,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, /* Start byte where continuation was expected. */ utf8_bytes_left = 0; utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; - /* Patch buf offset so this character will be parsed again as a */ - /* start byte. */ + /* Patch buf offset so this character will be parsed again as a start + * byte. */ j--; } @@ -1776,8 +1772,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, case '_': case 'P': case ']': - /* Not supported, but we'll have to parse until we see a stop */ - /* code, e.g. ESC \ or BEL. */ + /* Not supported, but we'll have to parse until we see a stop code, + * e. g. ESC \ or BEL. */ ansi_parser_state = ANSI_ST_CONTROL; continue; @@ -1859,8 +1855,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, continue; } else { - /* If ANSI_IN_ARG is not set, add another argument and */ - /* default it to 0. */ + /* If ANSI_IN_ARG is not set, add another argument and default it + * to 0. */ + /* Check for too many arguments */ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) { ansi_parser_state |= ANSI_IGNORE; @@ -1874,9 +1871,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) && handle->tty.wr.ansi_csi_argc == 0) { - /* Ignores '?' if it is the first character after CSI[ */ - /* This is an extension character from the VT100 codeset */ - /* that is supported and used by most ANSI terminals today. */ + /* Ignores '?' if it is the first character after CSI[. This is an + * extension character from the VT100 codeset that is supported and + * used by most ANSI terminals today. */ continue; } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' && @@ -2006,8 +2003,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, continue; } else { - /* We don't support commands that use private mode characters or */ - /* intermediaries. Ignore the rest of the sequence. */ + /* We don't support commands that use private mode characters or + * intermediaries. Ignore the rest of the sequence. */ ansi_parser_state |= ANSI_IGNORE; continue; } @@ -2020,8 +2017,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle, } } else if (ansi_parser_state & ANSI_ST_CONTROL) { - /* Unsupported control code */ - /* Ignore everything until we see BEL or ESC \ */ + /* Unsupported control code. + * Ignore everything until we see `BEL` or `ESC \`. */ if (ansi_parser_state & ANSI_IN_STRING) { if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) { if (utf8_codepoint == '"') { @@ -2055,9 +2052,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle, abort(); } - /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */ - /* windows console doesn't really support UTF-16, so just emit the */ - /* replacement character. */ + /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows + * console doesn't really support UTF-16, so just emit the replacement + * character. */ if (utf8_codepoint > 0xffff) { utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER; } @@ -2071,10 +2068,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle, utf16_buf[utf16_buf_used++] = L'\r'; utf16_buf[utf16_buf_used++] = L'\n'; } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) { - /* \n was followed by \r; do not print the \r, since */ - /* the source was either \r\n\r (so the second \r is */ - /* redundant) or was \n\r (so the \n was processed */ - /* by the last case and an \r automatically inserted). */ + /* \n was followed by \r; do not print the \r, since the source was + * either \r\n\r (so the second \r is redundant) or was \n\r (so the + * \n was processed by the last case and an \r automatically + * inserted). */ } else { /* \r without \n; print \r as-is. */ ENSURE_BUFFER_SPACE(1); @@ -2182,14 +2179,14 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, void uv_tty_close(uv_tty_t* handle) { assert(handle->u.fd == -1 || handle->u.fd > 2); + if (handle->flags & UV_HANDLE_READING) + uv_tty_read_stop(handle); + if (handle->u.fd == -1) CloseHandle(handle->handle); else close(handle->u.fd); - if (handle->flags & UV_HANDLE_READING) - uv_tty_read_stop(handle); - handle->u.fd = -1; handle->handle = INVALID_HANDLE_VALUE; handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE); @@ -2209,7 +2206,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { /* TTY shutdown is really just a no-op */ if (handle->stream.conn.shutdown_req->cb) { - if (handle->flags & UV__HANDLE_CLOSING) { + if (handle->flags & UV_HANDLE_CLOSING) { handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED); } else { handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0); @@ -2222,10 +2219,10 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { return; } - if (handle->flags & UV__HANDLE_CLOSING && + if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { - /* The wait handle used for raw reading should be unregistered when the */ - /* wait callback runs. */ + /* 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); diff --git a/Utilities/cmlibuv/src/win/udp.c b/Utilities/cmlibuv/src/win/udp.c index cd1d0e0..37df849 100644 --- a/Utilities/cmlibuv/src/win/udp.c +++ b/Utilities/cmlibuv/src/win/udp.c @@ -74,8 +74,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, return GetLastError(); } - /* Associate it with the I/O completion port. */ - /* Use uv_handle_t pointer as completion key. */ + /* Associate it with the I/O completion port. Use uv_handle_t pointer as + * completion key. */ if (CreateIoCompletionPort((HANDLE)socket, loop->iocp, (ULONG_PTR)socket, @@ -83,31 +83,28 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket, return GetLastError(); } - if (pSetFileCompletionNotificationModes) { - /* All known Windows that support SetFileCompletionNotificationModes */ - /* have a bug that makes it impossible to use this function in */ - /* conjunction with datagram sockets. We can work around that but only */ - /* if the user is using the default UDP driver (AFD) and has no other */ - /* LSPs stacked on top. Here we check whether that is the case. */ - opt_len = (int) sizeof info; - if (getsockopt(socket, - SOL_SOCKET, - SO_PROTOCOL_INFOW, - (char*) &info, - &opt_len) == SOCKET_ERROR) { - return GetLastError(); - } + /* All known Windows that support SetFileCompletionNotificationModes have a + * bug that makes it impossible to use this function in conjunction with + * datagram sockets. We can work around that but only if the user is using + * the default UDP driver (AFD) and has no other. LSPs stacked on top. Here + * we check whether that is the case. */ + opt_len = (int) sizeof info; + if (getsockopt( + socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) == + SOCKET_ERROR) { + return GetLastError(); + } - if (info.ProtocolChain.ChainLen == 1) { - if (pSetFileCompletionNotificationModes((HANDLE)socket, - FILE_SKIP_SET_EVENT_ON_HANDLE | - FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { - handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; - handle->func_wsarecv = uv_wsarecv_workaround; - handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; - } else if (GetLastError() != ERROR_INVALID_FUNCTION) { - return GetLastError(); - } + if (info.ProtocolChain.ChainLen == 1) { + if (SetFileCompletionNotificationModes( + (HANDLE) socket, + FILE_SKIP_SET_EVENT_ON_HANDLE | + FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { + handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP; + handle->func_wsarecv = uv_wsarecv_workaround; + handle->func_wsarecvfrom = uv_wsarecvfrom_workaround; + } else if (GetLastError() != ERROR_INVALID_FUNCTION) { + return GetLastError(); } } @@ -191,7 +188,7 @@ void uv_udp_close(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) { assert(!(handle->flags & UV_HANDLE_CLOSED)); uv__handle_close(handle); @@ -245,12 +242,12 @@ static int uv_udp_maybe_bind(uv_udp_t* handle, handle->flags |= UV_HANDLE_IPV6; if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) { - /* On windows IPV6ONLY is on by default. */ - /* If the user doesn't specify it libuv turns it off. */ + /* On windows IPV6ONLY is on by default. If the user doesn't specify it + * libuv turns it off. */ - /* TODO: how to handle errors? This may fail if there is no ipv4 stack */ - /* available, or when run on XP/2003 which have no support for dualstack */ - /* sockets. For now we're silently ignoring the error. */ + /* TODO: how to handle errors? This may fail if there is no ipv4 stack + * available, or when run on XP/2003 which have no support for dualstack + * sockets. For now we're silently ignoring the error. */ setsockopt(handle->socket, IPPROTO_IPV6, IPV6_V6ONLY, @@ -369,7 +366,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, int err; if (handle->flags & UV_HANDLE_READING) { - return WSAEALREADY; + return UV_EALREADY; } err = uv_udp_maybe_bind(handle, @@ -377,7 +374,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, sizeof(uv_addr_ip4_any_), 0); if (err) - return err; + return uv_translate_sys_error(err); handle->flags |= UV_HANDLE_READING; INCREASE_ACTIVE_COUNT(loop, handle); @@ -386,8 +383,8 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, handle->recv_cb = recv_cb; handle->alloc_cb = alloc_cb; - /* If reading was stopped and then started again, there could still be a */ - /* recv request pending. */ + /* If reading was stopped and then started again, there could still be a recv + * request pending. */ if (!(handle->flags & UV_HANDLE_READ_PENDING)) uv_udp_queue_recv(loop, handle); @@ -467,19 +464,19 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, if (!REQ_SUCCESS(req)) { DWORD err = GET_REQ_SOCK_ERROR(req); if (err == WSAEMSGSIZE) { - /* Not a real error, it just indicates that the received packet */ - /* was bigger than the receive buffer. */ + /* Not a real error, it just indicates that the received packet was + * bigger than the receive buffer. */ } else if (err == WSAECONNRESET || err == WSAENETRESET) { - /* A previous sendto operation failed; ignore this error. If */ - /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */ - /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */ - /* immediately queue a new receive. */ + /* A previous sendto operation failed; ignore this error. If zero-reading + * we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to + * clear out the error queue. For nonzero reads, immediately queue a new + * receive. */ if (!(handle->flags & UV_HANDLE_ZERO_READ)) { goto done; } } else { - /* A real error occurred. Report the error to the user only if we're */ - /* currently reading. */ + /* A real error occurred. Report the error to the user only if we're + * currently reading. */ if (handle->flags & UV_HANDLE_READING) { uv_udp_recv_stop(handle); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? @@ -503,8 +500,8 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, struct sockaddr_storage from; int from_len; - /* Do a nonblocking receive */ - /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */ + /* Do a nonblocking receive. + * TODO: try to read multiple datagrams at once. FIONREAD maybe? */ buf = uv_buf_init(NULL, 0); handle->alloc_cb((uv_handle_t*) handle, 65536, &buf); if (buf.base == NULL || buf.len == 0) { @@ -741,7 +738,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) return UV_EINVAL; } - if (!(handle->flags & UV_HANDLE_BOUND)) + if (handle->socket == INVALID_SOCKET) return UV_EBADF; if (addr_st.ss_family == AF_INET) { @@ -772,7 +769,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) int uv_udp_set_broadcast(uv_udp_t* handle, int value) { BOOL optval = (BOOL) value; - if (!(handle->flags & UV_HANDLE_BOUND)) + if (handle->socket == INVALID_SOCKET) return UV_EBADF; if (setsockopt(handle->socket, @@ -818,7 +815,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { return UV_EINVAL; \ } \ \ - if (!(handle->flags & UV_HANDLE_BOUND)) \ + if (handle->socket == INVALID_SOCKET) \ return UV_EBADF; \ \ if (!(handle->flags & UV_HANDLE_IPV6)) { \ diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c index 49b5bc7..9237891 100644 --- a/Utilities/cmlibuv/src/win/util.c +++ b/Utilities/cmlibuv/src/win/util.c @@ -74,10 +74,6 @@ static char *process_title; static CRITICAL_SECTION process_title_lock; -/* Cached copy of the process id, written once. */ -static DWORD current_pid = 0; - - /* Interval (in seconds) of the high-resolution clock. */ static double hrtime_interval_ = 0; @@ -149,8 +145,8 @@ int uv_exepath(char* buffer, size_t* size_ptr) { uv__free(utf16_buffer); - /* utf8_len *does* include the terminating null at this point, but the */ - /* returned size shouldn't. */ + /* utf8_len *does* include the terminating null at this point, but the + * returned size shouldn't. */ *size_ptr = utf8_len - 1; return 0; @@ -173,16 +169,16 @@ int uv_cwd(char* buffer, size_t* size) { if (utf16_len == 0) { return uv_translate_sys_error(GetLastError()); } else if (utf16_len > MAX_PATH) { - /* This should be impossible; however the CRT has a code path to deal */ - /* with this scenario, so I added a check anyway. */ + /* This should be impossible; however the CRT has a code path to deal with + * this scenario, so I added a check anyway. */ return UV_EIO; } /* utf16_len contains the length, *not* including the terminating null. */ utf16_buffer[utf16_len] = L'\0'; - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed.*/ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && !(utf16_len == 3 && utf16_buffer[1] == L':')) { utf16_len--; @@ -239,9 +235,9 @@ int uv_chdir(const char* dir) { utf16_buffer, MAX_PATH) == 0) { DWORD error = GetLastError(); - /* The maximum length of the current working directory is 260 chars, */ - /* including terminating null. If it doesn't fit, the path name must be */ - /* too long. */ + /* The maximum length of the current working directory is 260 chars, + * including terminating null. If it doesn't fit, the path name must be too + * long. */ if (error == ERROR_INSUFFICIENT_BUFFER) { return UV_ENAMETOOLONG; } else { @@ -253,9 +249,9 @@ int uv_chdir(const char* dir) { return uv_translate_sys_error(GetLastError()); } - /* Windows stores the drive-local path in an "hidden" environment variable, */ - /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */ - /* update this, so we'll have to do it. */ + /* Windows stores the drive-local path in an "hidden" environment variable, + * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update + * this, so we'll have to do it. */ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer); if (utf16_len == 0) { return uv_translate_sys_error(GetLastError()); @@ -263,8 +259,8 @@ int uv_chdir(const char* dir) { return UV_EIO; } - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed. */ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (utf16_buffer[utf16_len - 1] == L'\\' && !(utf16_len == 3 && utf16_buffer[1] == L':')) { utf16_len--; @@ -272,8 +268,8 @@ int uv_chdir(const char* dir) { } if (utf16_len < 2 || utf16_buffer[1] != L':') { - /* Doesn't look like a drive letter could be there - probably an UNC */ - /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */ + /* Doesn't look like a drive letter could be there - probably an UNC path. + * TODO: Need to handle win32 namespaces like \\?\C:\ ? */ drive_letter = 0; } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') { drive_letter = utf16_buffer[0]; @@ -359,14 +355,6 @@ uv_pid_t uv_os_getppid(void) { } -int uv_current_pid(void) { - if (current_pid == 0) { - current_pid = GetCurrentProcessId(); - } - return current_pid; -} - - char** uv_setup_args(int argc, char** argv) { return argv; } @@ -828,6 +816,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, int is_vista_or_greater; ULONG flags; + *addresses_ptr = NULL; + *count_ptr = 0; + is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0); if (is_vista_or_greater) { flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | @@ -842,17 +833,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } - /* Fetch the size of the adapters reported by windows, and then get the */ - /* list itself. */ + /* Fetch the size of the adapters reported by windows, and then get the list + * itself. */ win_address_buf_size = 0; win_address_buf = NULL; for (;;) { ULONG r; - /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */ - /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */ - /* win_address_buf_size. */ + /* If win_address_buf is 0, then GetAdaptersAddresses will fail with. + * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in + * win_address_buf_size. */ r = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, @@ -866,8 +857,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, switch (r) { case ERROR_BUFFER_OVERFLOW: - /* This happens when win_address_buf is NULL or too small to hold */ - /* all adapters. */ + /* This happens when win_address_buf is NULL or too small to hold all + * adapters. */ win_address_buf = uv__malloc(win_address_buf_size); if (win_address_buf == NULL) return UV_ENOMEM; @@ -901,15 +892,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, return UV_ENOBUFS; default: - /* Other (unspecified) errors can happen, but we don't have any */ - /* special meaning for them. */ + /* Other (unspecified) errors can happen, but we don't have any special + * meaning for them. */ assert(r != ERROR_SUCCESS); return uv_translate_sys_error(r); } } - /* Count the number of enabled interfaces and compute how much space is */ - /* needed to store their info. */ + /* Count the number of enabled interfaces and compute how much space is + * needed to store their info. */ count = 0; uv_address_buf_size = 0; @@ -919,9 +910,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, IP_ADAPTER_UNICAST_ADDRESS* unicast_address; int name_size; - /* Interfaces that are not 'up' should not be reported. Also skip */ - /* interfaces that have no associated unicast address, as to avoid */ - /* allocating space for the name for this interface. */ + /* Interfaces that are not 'up' should not be reported. Also skip + * interfaces that have no associated unicast address, as to avoid + * allocating space for the name for this interface. */ if (adapter->OperStatus != IfOperStatusUp || adapter->FirstUnicastAddress == NULL) continue; @@ -941,8 +932,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } uv_address_buf_size += name_size; - /* Count the number of addresses associated with this interface, and */ - /* compute the size. */ + /* Count the number of addresses associated with this interface, and + * compute the size. */ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*) adapter->FirstUnicastAddress; unicast_address != NULL; @@ -959,8 +950,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, return UV_ENOMEM; } - /* Compute the start of the uv_interface_address_t array, and the place in */ - /* the buffer where the interface names will be stored. */ + /* Compute the start of the uv_interface_address_t array, and the place in + * the buffer where the interface names will be stored. */ uv_address = uv_address_buf; name_buf = (char*) (uv_address_buf + count); @@ -1199,8 +1190,8 @@ int uv_os_tmpdir(char* buffer, size_t* size) { return UV_EIO; } - /* The returned directory should not have a trailing slash, unless it */ - /* points at a drive root, like c:\. Remove it if needed.*/ + /* The returned directory should not have a trailing slash, unless it points + * at a drive root, like c:\. Remove it if needed. */ if (path[len - 1] == L'\\' && !(len == 3 && path[1] == L':')) { len--; @@ -1542,3 +1533,214 @@ int uv_os_gethostname(char* buffer, size_t* size) { *size = len; return 0; } + + +static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) { + int r; + + if (pid == 0) + *handle = GetCurrentProcess(); + else + *handle = OpenProcess(access, FALSE, pid); + + if (*handle == NULL) { + r = GetLastError(); + + if (r == ERROR_INVALID_PARAMETER) + return UV_ESRCH; + else + return uv_translate_sys_error(r); + } + + return 0; +} + + +int uv_os_getpriority(uv_pid_t pid, int* priority) { + HANDLE handle; + int r; + + if (priority == NULL) + return UV_EINVAL; + + r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle); + + if (r != 0) + return r; + + r = GetPriorityClass(handle); + + if (r == 0) { + r = uv_translate_sys_error(GetLastError()); + } else { + /* Map Windows priority classes to Unix nice values. */ + if (r == REALTIME_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGHEST; + else if (r == HIGH_PRIORITY_CLASS) + *priority = UV_PRIORITY_HIGH; + else if (r == ABOVE_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_ABOVE_NORMAL; + else if (r == NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_NORMAL; + else if (r == BELOW_NORMAL_PRIORITY_CLASS) + *priority = UV_PRIORITY_BELOW_NORMAL; + else /* IDLE_PRIORITY_CLASS */ + *priority = UV_PRIORITY_LOW; + + r = 0; + } + + CloseHandle(handle); + return r; +} + + +int uv_os_setpriority(uv_pid_t pid, int priority) { + HANDLE handle; + int priority_class; + int r; + + /* Map Unix nice values to Windows priority classes. */ + if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW) + return UV_EINVAL; + else if (priority < UV_PRIORITY_HIGH) + priority_class = REALTIME_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_ABOVE_NORMAL) + priority_class = HIGH_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_NORMAL) + priority_class = ABOVE_NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_BELOW_NORMAL) + priority_class = NORMAL_PRIORITY_CLASS; + else if (priority < UV_PRIORITY_LOW) + priority_class = BELOW_NORMAL_PRIORITY_CLASS; + else + priority_class = IDLE_PRIORITY_CLASS; + + r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle); + + if (r != 0) + return r; + + if (SetPriorityClass(handle, priority_class) == 0) + r = uv_translate_sys_error(GetLastError()); + + CloseHandle(handle); + return r; +} + + +int uv_os_uname(uv_utsname_t* buffer) { + /* Implementation loosely based on + https://github.com/gagern/gnulib/blob/master/lib/uname.c */ + OSVERSIONINFOW os_info; + SYSTEM_INFO system_info; + int processor_level; + int r; + + if (buffer == NULL) + return UV_EINVAL; + + uv__once_init(); + os_info.dwOSVersionInfoSize = sizeof(os_info); + os_info.szCSDVersion[0] = L'\0'; + + /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx() + if RtlGetVersion() is not available. */ + if (pRtlGetVersion) { + pRtlGetVersion(&os_info); + } else { + /* Silence GetVersionEx() deprecation warning. */ + #pragma warning(suppress : 4996) + if (GetVersionExW(&os_info) == 0) { + r = uv_translate_sys_error(GetLastError()); + goto error; + } + } + + /* Populate the version field. */ + if (WideCharToMultiByte(CP_UTF8, + 0, + os_info.szCSDVersion, + -1, + buffer->version, + sizeof(buffer->version), + NULL, + NULL) == 0) { + r = uv_translate_sys_error(GetLastError()); + goto error; + } + + /* Populate the sysname field. */ +#ifdef __MINGW32__ + r = snprintf(buffer->sysname, + sizeof(buffer->sysname), + "MINGW32_NT-%u.%u", + (unsigned int) os_info.dwMajorVersion, + (unsigned int) os_info.dwMinorVersion); + assert(r < sizeof(buffer->sysname)); +#else + uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname)); +#endif + + /* Populate the release field. */ + r = snprintf(buffer->release, + sizeof(buffer->release), + "%d.%d.%d", + (unsigned int) os_info.dwMajorVersion, + (unsigned int) os_info.dwMinorVersion, + (unsigned int) os_info.dwBuildNumber); + assert(r < sizeof(buffer->release)); + + /* Populate the machine field. */ + GetSystemInfo(&system_info); + + switch (system_info.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_AMD64: + uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_IA64: + uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_INTEL: + uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine)); + + if (system_info.wProcessorLevel > 3) { + processor_level = system_info.wProcessorLevel < 6 ? + system_info.wProcessorLevel : 6; + buffer->machine[1] = '0' + processor_level; + } + + break; + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_MIPS: + uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_ALPHA: + case PROCESSOR_ARCHITECTURE_ALPHA64: + uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_PPC: + uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_SHX: + uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_ARM: + uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine)); + break; + default: + uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine)); + break; + } + + return 0; + +error: + buffer->sysname[0] = '\0'; + buffer->release[0] = '\0'; + buffer->version[0] = '\0'; + buffer->machine[0] = '\0'; + return r; +} diff --git a/Utilities/cmlibuv/src/win/winapi.c b/Utilities/cmlibuv/src/win/winapi.c index c330786..fbbbcee 100644 --- a/Utilities/cmlibuv/src/win/winapi.c +++ b/Utilities/cmlibuv/src/win/winapi.c @@ -26,6 +26,7 @@ /* Ntdll function pointers */ +sRtlGetVersion pRtlGetVersion; sRtlNtStatusToDosError pRtlNtStatusToDosError; sNtDeviceIoControlFile pNtDeviceIoControlFile; sNtQueryInformationFile pNtQueryInformationFile; @@ -34,20 +35,8 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; sNtQueryDirectoryFile pNtQueryDirectoryFile; sNtQuerySystemInformation pNtQuerySystemInformation; - /* Kernel32 function pointers */ sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; -sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; -sCreateSymbolicLinkW pCreateSymbolicLinkW; -sCancelIoEx pCancelIoEx; -sInitializeConditionVariable pInitializeConditionVariable; -sSleepConditionVariableCS pSleepConditionVariableCS; -sSleepConditionVariableSRW pSleepConditionVariableSRW; -sWakeAllConditionVariable pWakeAllConditionVariable; -sWakeConditionVariable pWakeConditionVariable; -sCancelSynchronousIo pCancelSynchronousIo; -sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; - /* Powrprof.dll function pointer */ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -55,22 +44,21 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; /* User32.dll function pointer */ sSetWinEventHook pSetWinEventHook; -/* iphlpapi.dll function pointer */ -sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid = NULL; -sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW = NULL; void uv_winapi_init(void) { HMODULE ntdll_module; - HMODULE kernel32_module; HMODULE powrprof_module; HMODULE user32_module; - HMODULE iphlpapi_module; + HMODULE kernel32_module; ntdll_module = GetModuleHandleA("ntdll.dll"); if (ntdll_module == NULL) { uv_fatal_error(GetLastError(), "GetModuleHandleA"); } + pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module, + "RtlGetVersion"); + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( ntdll_module, "RtlNtStatusToDosError"); @@ -127,37 +115,6 @@ void uv_winapi_init(void) { kernel32_module, "GetQueuedCompletionStatusEx"); - pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes) - GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes"); - - pCreateSymbolicLinkW = (sCreateSymbolicLinkW) - GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); - - pCancelIoEx = (sCancelIoEx) - GetProcAddress(kernel32_module, "CancelIoEx"); - - pInitializeConditionVariable = (sInitializeConditionVariable) - GetProcAddress(kernel32_module, "InitializeConditionVariable"); - - pSleepConditionVariableCS = (sSleepConditionVariableCS) - GetProcAddress(kernel32_module, "SleepConditionVariableCS"); - - pSleepConditionVariableSRW = (sSleepConditionVariableSRW) - GetProcAddress(kernel32_module, "SleepConditionVariableSRW"); - - pWakeAllConditionVariable = (sWakeAllConditionVariable) - GetProcAddress(kernel32_module, "WakeAllConditionVariable"); - - pWakeConditionVariable = (sWakeConditionVariable) - GetProcAddress(kernel32_module, "WakeConditionVariable"); - - pCancelSynchronousIo = (sCancelSynchronousIo) - GetProcAddress(kernel32_module, "CancelSynchronousIo"); - - pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) - GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); - - powrprof_module = LoadLibraryA("powrprof.dll"); if (powrprof_module != NULL) { pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification) @@ -170,11 +127,4 @@ void uv_winapi_init(void) { GetProcAddress(user32_module, "SetWinEventHook"); } - iphlpapi_module = LoadLibraryA("iphlpapi.dll"); - if (iphlpapi_module != NULL) { - pConvertInterfaceIndexToLuid = (sConvertInterfaceIndexToLuid) - GetProcAddress(iphlpapi_module, "ConvertInterfaceIndexToLuid"); - pConvertInterfaceLuidToNameW = (sConvertInterfaceLuidToNameW) - GetProcAddress(iphlpapi_module, "ConvertInterfaceLuidToNameW"); - } } diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h index ae384b7..1e49b57 100644 --- a/Utilities/cmlibuv/src/win/winapi.h +++ b/Utilities/cmlibuv/src/win/winapi.h @@ -4076,8 +4076,8 @@ # define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L) #endif -/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */ -/* DDK got it wrong! */ +/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the DDK + * got it wrong! */ #ifdef NTSTATUS_FROM_WIN32 # undef NTSTATUS_FROM_WIN32 #endif @@ -4109,6 +4109,9 @@ #endif /* from winternl.h */ +#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_) +#define __UNICODE_STRING_DEFINED +#endif typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; @@ -4524,6 +4527,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE) PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved); +typedef NTSTATUS (NTAPI *sRtlGetVersion) + (PRTL_OSVERSIONINFOW lpVersionInformation); + typedef ULONG (NTAPI *sRtlNtStatusToDosError) (NTSTATUS Status); @@ -4659,48 +4665,6 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx) DWORD dwMilliseconds, BOOL fAlertable); -typedef BOOL (WINAPI* sSetFileCompletionNotificationModes) - (HANDLE FileHandle, - UCHAR Flags); - -typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) - (LPCWSTR lpSymlinkFileName, - LPCWSTR lpTargetFileName, - DWORD dwFlags); - -typedef BOOL (WINAPI* sCancelIoEx) - (HANDLE hFile, - LPOVERLAPPED lpOverlapped); - -typedef VOID (WINAPI* sInitializeConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef BOOL (WINAPI* sSleepConditionVariableCS) - (PCONDITION_VARIABLE ConditionVariable, - PCRITICAL_SECTION CriticalSection, - DWORD dwMilliseconds); - -typedef BOOL (WINAPI* sSleepConditionVariableSRW) - (PCONDITION_VARIABLE ConditionVariable, - PSRWLOCK SRWLock, - DWORD dwMilliseconds, - ULONG Flags); - -typedef VOID (WINAPI* sWakeAllConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef VOID (WINAPI* sWakeConditionVariable) - (PCONDITION_VARIABLE ConditionVariable); - -typedef BOOL (WINAPI* sCancelSynchronousIo) - (HANDLE hThread); - -typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) - (HANDLE hFile, - LPWSTR lpszFilePath, - DWORD cchFilePath, - DWORD dwFlags); - /* from powerbase.h */ #ifndef DEVICE_NOTIFY_CALLBACK # define DEVICE_NOTIFY_CALLBACK 2 @@ -4755,6 +4719,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) /* Ntdll function pointers */ +extern sRtlGetVersion pRtlGetVersion; extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; extern sNtQueryInformationFile pNtQueryInformationFile; @@ -4763,20 +4728,8 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile; extern sNtQueryDirectoryFile pNtQueryDirectoryFile; extern sNtQuerySystemInformation pNtQuerySystemInformation; - /* Kernel32 function pointers */ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; -extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; -extern sCreateSymbolicLinkW pCreateSymbolicLinkW; -extern sCancelIoEx pCancelIoEx; -extern sInitializeConditionVariable pInitializeConditionVariable; -extern sSleepConditionVariableCS pSleepConditionVariableCS; -extern sSleepConditionVariableSRW pSleepConditionVariableSRW; -extern sWakeAllConditionVariable pWakeAllConditionVariable; -extern sWakeConditionVariable pWakeConditionVariable; -extern sCancelSynchronousIo pCancelSynchronousIo; -extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; - /* Powrprof.dll function pointer */ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification; @@ -4784,19 +4737,4 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi /* User32.dll function pointer */ extern sSetWinEventHook pSetWinEventHook; -/* iphlpapi.dll function pointer */ -union _NET_LUID_LH; -typedef DWORD (WINAPI *sConvertInterfaceIndexToLuid)( - ULONG InterfaceIndex, - union _NET_LUID_LH *InterfaceLuid); - -typedef DWORD (WINAPI *sConvertInterfaceLuidToNameW)( - const union _NET_LUID_LH *InterfaceLuid, - PWSTR InterfaceName, - size_t Length); - -extern sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid; -extern sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW; - - #endif /* UV_WIN_WINAPI_H_ */ diff --git a/Utilities/cmlibuv/src/win/winsock.c b/Utilities/cmlibuv/src/win/winsock.c index 8418895..5e7da2a 100644 --- a/Utilities/cmlibuv/src/win/winsock.c +++ b/Utilities/cmlibuv/src/win/winsock.c @@ -256,8 +256,8 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) { default: if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) && (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) { - /* It's a windows error that has been previously mapped to an */ - /* ntstatus code. */ + /* It's a windows error that has been previously mapped to an ntstatus + * code. */ return (DWORD) (status & 0xffff); } else { /* The default fallback for unmappable ntstatus codes. */ @@ -519,8 +519,8 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in, sizeof *info_out); if (overlapped == NULL) { - /* If this is a blocking operation, wait for the event to become */ - /* signaled, and then grab the real status from the io status block. */ + /* If this is a blocking operation, wait for the event to become signaled, + * and then grab the real status from the io status block. */ if (status == STATUS_PENDING) { DWORD r = WaitForSingleObject(event, INFINITE); |