mirror of
https://github.com/Kitware/CMake.git
synced 2026-04-21 13:48:33 -05:00
Merge topic 'update-libuv'
630e501f8blibuv: Restore compilation on Apple i386 architecture02a28f1d44libuv: Restore compilation with XLClang 16.1 on AIX82a06d5cb4CTestCustom: Suppress scanbuild warning in libuv722d6b4105Merge branch 'upstream-libuv' into update-libuv394b07af40libuv 2020-04-06 (d21f5aea) Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !4576
This commit is contained in:
@@ -99,6 +99,7 @@ list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION
|
||||
"liblzma/common/index_encoder.c:[0-9]+:[0-9]+: warning: Value stored to .* during its initialization is never read"
|
||||
"libuv/src/.*:[0-9]+:[0-9]+: warning: Dereference of null pointer"
|
||||
"libuv/src/.*:[0-9]+:[0-9]+: warning: The left operand of '==' is a garbage value"
|
||||
"libuv/src/.*:[0-9]+:[0-9]+: warning: 1st function call argument is an uninitialized value"
|
||||
"nghttp2/lib/.*:[0-9]+:[0-9]+: warning: Dereference of null pointer"
|
||||
"nghttp2/lib/.*:[0-9]+:[0-9]+: warning: Value stored to .* is never read"
|
||||
)
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(BUILDING_UV_SHARED) && defined(USING_UV_SHARED)
|
||||
#error "Define either BUILDING_UV_SHARED or USING_UV_SHARED, not both."
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Windows - set up dll import/export decorators. */
|
||||
# if defined(BUILDING_UV_SHARED)
|
||||
@@ -147,6 +151,7 @@ extern "C" {
|
||||
XX(EREMOTEIO, "remote I/O error") \
|
||||
XX(ENOTTY, "inappropriate ioctl for device") \
|
||||
XX(EFTYPE, "inappropriate file type or format") \
|
||||
XX(EILSEQ, "illegal byte sequence") \
|
||||
|
||||
#define UV_HANDLE_TYPE_MAP(XX) \
|
||||
XX(ASYNC, async) \
|
||||
@@ -176,6 +181,7 @@ extern "C" {
|
||||
XX(WORK, work) \
|
||||
XX(GETADDRINFO, getaddrinfo) \
|
||||
XX(GETNAMEINFO, getnameinfo) \
|
||||
XX(RANDOM, random) \
|
||||
|
||||
typedef enum {
|
||||
#define XX(code, _) UV_ ## code = UV__ ## code,
|
||||
@@ -233,13 +239,16 @@ typedef struct uv_connect_s uv_connect_t;
|
||||
typedef struct uv_udp_send_s uv_udp_send_t;
|
||||
typedef struct uv_fs_s uv_fs_t;
|
||||
typedef struct uv_work_s uv_work_t;
|
||||
typedef struct uv_random_s uv_random_t;
|
||||
|
||||
/* None of the above. */
|
||||
typedef struct uv_env_item_s uv_env_item_t;
|
||||
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 struct uv_statfs_s uv_statfs_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
@@ -327,6 +336,10 @@ typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
|
||||
int status,
|
||||
const char* hostname,
|
||||
const char* service);
|
||||
typedef void (*uv_random_cb)(uv_random_t* req,
|
||||
int status,
|
||||
void* buf,
|
||||
size_t buflen);
|
||||
|
||||
typedef struct {
|
||||
long tv_sec;
|
||||
@@ -561,6 +574,7 @@ UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
UV_EXTERN int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb);
|
||||
UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
|
||||
uv_tcp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
@@ -595,7 +609,12 @@ enum uv_udp_flags {
|
||||
* (provided they all set the flag) but only the last one to bind will receive
|
||||
* any traffic, in effect "stealing" the port from the previous listener.
|
||||
*/
|
||||
UV_UDP_REUSEADDR = 4
|
||||
UV_UDP_REUSEADDR = 4,
|
||||
/*
|
||||
* Indicates that the message was received by recvmmsg, so the buffer provided
|
||||
* must not be freed by the recv_cb callback.
|
||||
*/
|
||||
UV_UDP_MMSG_CHUNK = 8
|
||||
};
|
||||
|
||||
typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
|
||||
@@ -647,6 +666,11 @@ UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
uv_membership membership);
|
||||
UV_EXTERN int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership);
|
||||
UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
|
||||
UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
|
||||
UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
|
||||
@@ -691,10 +715,25 @@ typedef enum {
|
||||
UV_TTY_MODE_IO
|
||||
} uv_tty_mode_t;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* The console supports handling of virtual terminal sequences
|
||||
* (Windows10 new console, ConEmu)
|
||||
*/
|
||||
UV_TTY_SUPPORTED,
|
||||
/* The console cannot process the virtual terminal sequence. (Legacy
|
||||
* console)
|
||||
*/
|
||||
UV_TTY_UNSUPPORTED
|
||||
} uv_tty_vtermstate_t;
|
||||
|
||||
|
||||
UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
|
||||
UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
|
||||
UV_EXTERN int uv_tty_reset_mode(void);
|
||||
UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
|
||||
UV_EXTERN void uv_tty_set_vterm_state(uv_tty_vtermstate_t state);
|
||||
UV_EXTERN int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C++" {
|
||||
@@ -1087,6 +1126,17 @@ struct uv_utsname_s {
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
struct uv_statfs_s {
|
||||
uint64_t f_type;
|
||||
uint64_t f_bsize;
|
||||
uint64_t f_blocks;
|
||||
uint64_t f_bfree;
|
||||
uint64_t f_bavail;
|
||||
uint64_t f_files;
|
||||
uint64_t f_ffree;
|
||||
uint64_t f_spare[4];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@@ -1149,12 +1199,22 @@ 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
|
||||
#if defined(__PASE__)
|
||||
/* On IBM i PASE, the highest process priority is -10 */
|
||||
# define UV_PRIORITY_LOW 39 // RUNPTY(99)
|
||||
# define UV_PRIORITY_BELOW_NORMAL 15 // RUNPTY(50)
|
||||
# define UV_PRIORITY_NORMAL 0 // RUNPTY(20)
|
||||
# define UV_PRIORITY_ABOVE_NORMAL -4 // RUNTY(12)
|
||||
# define UV_PRIORITY_HIGH -7 // RUNPTY(6)
|
||||
# define UV_PRIORITY_HIGHEST -10 // RUNPTY(1)
|
||||
#else
|
||||
# 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
|
||||
#endif
|
||||
|
||||
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
|
||||
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
|
||||
@@ -1168,6 +1228,13 @@ UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count);
|
||||
|
||||
struct uv_env_item_s {
|
||||
char* name;
|
||||
char* value;
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_os_environ(uv_env_item_t** envitems, int* count);
|
||||
UV_EXTERN void uv_os_free_environ(uv_env_item_t* envitems, int count);
|
||||
UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
|
||||
UV_EXTERN int uv_os_setenv(const char* name, const char* value);
|
||||
UV_EXTERN int uv_os_unsetenv(const char* name);
|
||||
@@ -1223,7 +1290,9 @@ typedef enum {
|
||||
UV_FS_LCHOWN,
|
||||
UV_FS_OPENDIR,
|
||||
UV_FS_READDIR,
|
||||
UV_FS_CLOSEDIR
|
||||
UV_FS_CLOSEDIR,
|
||||
UV_FS_STATFS,
|
||||
UV_FS_MKSTEMP
|
||||
} uv_fs_type;
|
||||
|
||||
struct uv_dir_s {
|
||||
@@ -1314,6 +1383,10 @@ UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1451,6 +1524,10 @@ UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
enum uv_fs_event {
|
||||
@@ -1556,6 +1633,26 @@ UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size
|
||||
UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
|
||||
UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
|
||||
|
||||
|
||||
struct uv_random_s {
|
||||
UV_REQ_FIELDS
|
||||
/* read-only */
|
||||
uv_loop_t* loop;
|
||||
/* private */
|
||||
int status;
|
||||
void* buf;
|
||||
size_t buflen;
|
||||
uv_random_cb cb;
|
||||
struct uv__work work_req;
|
||||
};
|
||||
|
||||
UV_EXTERN int uv_random(uv_loop_t* loop,
|
||||
uv_random_t* req,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
unsigned flags, /* For future extension; must be 0. */
|
||||
uv_random_cb cb);
|
||||
|
||||
#if defined(IF_NAMESIZE)
|
||||
# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
|
||||
#elif defined(IFNAMSIZ)
|
||||
@@ -1582,6 +1679,7 @@ UV_EXTERN uint64_t uv_get_total_memory(void);
|
||||
UV_EXTERN uint64_t uv_get_constrained_memory(void);
|
||||
|
||||
UV_EXTERN uint64_t uv_hrtime(void);
|
||||
UV_EXTERN void uv_sleep(unsigned int msec);
|
||||
|
||||
UV_EXTERN void uv_disable_stdio_inheritance(void);
|
||||
|
||||
|
||||
@@ -439,5 +439,10 @@
|
||||
# define UV__EFTYPE (-4028)
|
||||
#endif
|
||||
|
||||
#if defined(EILSEQ) && !defined(_WIN32)
|
||||
# define UV__EILSEQ UV__ERR(EILSEQ)
|
||||
#else
|
||||
# define UV__EILSEQ (-4027)
|
||||
#endif
|
||||
|
||||
#endif /* UV_ERRNO_H_ */
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
# include "linux.h"
|
||||
#elif defined (__MVS__)
|
||||
# include "os390.h"
|
||||
#elif defined(__PASE__) /* __PASE__ and _AIX are both defined on IBM i */
|
||||
# include "posix.h" /* IBM i needs uv/posix.h, not uv/aix.h */
|
||||
#elif defined(_AIX)
|
||||
# include "aix.h"
|
||||
#elif defined(__sun)
|
||||
@@ -65,8 +67,7 @@
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "bsd.h"
|
||||
#elif defined(__PASE__) || \
|
||||
defined(__CYGWIN__) || \
|
||||
#elif defined(__CYGWIN__) || \
|
||||
defined(__MSYS__) || \
|
||||
defined(__GNU__)
|
||||
# include "posix.h"
|
||||
@@ -421,11 +422,25 @@ typedef struct {
|
||||
#else
|
||||
# define UV_FS_O_CREAT 0
|
||||
#endif
|
||||
#if defined(O_DIRECT)
|
||||
|
||||
#if defined(__linux__) && defined(__arm__)
|
||||
# define UV_FS_O_DIRECT 0x10000
|
||||
#elif defined(__linux__) && defined(__m68k__)
|
||||
# define UV_FS_O_DIRECT 0x10000
|
||||
#elif defined(__linux__) && defined(__mips__)
|
||||
# define UV_FS_O_DIRECT 0x08000
|
||||
#elif defined(__linux__) && defined(__powerpc__)
|
||||
# define UV_FS_O_DIRECT 0x20000
|
||||
#elif defined(__linux__) && defined(__s390x__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(__linux__) && defined(__x86_64__)
|
||||
# define UV_FS_O_DIRECT 0x04000
|
||||
#elif defined(O_DIRECT)
|
||||
# define UV_FS_O_DIRECT O_DIRECT
|
||||
#else
|
||||
# define UV_FS_O_DIRECT 0
|
||||
#endif
|
||||
|
||||
#if defined(O_DIRECTORY)
|
||||
# define UV_FS_O_DIRECTORY O_DIRECTORY
|
||||
#else
|
||||
@@ -498,6 +513,7 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
/* fs open() flags supported on other platforms: */
|
||||
#define UV_FS_O_FILEMAP 0
|
||||
#define UV_FS_O_RANDOM 0
|
||||
#define UV_FS_O_SHORT_LIVED 0
|
||||
#define UV_FS_O_SEQUENTIAL 0
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 29
|
||||
#define UV_VERSION_PATCH 2
|
||||
#define UV_VERSION_MINOR 35
|
||||
#define UV_VERSION_PATCH 1
|
||||
#define UV_VERSION_IS_RELEASE 0
|
||||
#define UV_VERSION_SUFFIX "dev"
|
||||
|
||||
|
||||
@@ -528,7 +528,7 @@ typedef struct {
|
||||
/* eol conversion state */ \
|
||||
unsigned char previous_eol; \
|
||||
/* ansi parser state */ \
|
||||
unsigned char ansi_parser_state; \
|
||||
unsigned short ansi_parser_state; \
|
||||
unsigned char ansi_csi_argc; \
|
||||
unsigned short ansi_csi_argv[4]; \
|
||||
COORD saved_position; \
|
||||
@@ -679,6 +679,7 @@ typedef struct {
|
||||
#define UV_FS_O_APPEND _O_APPEND
|
||||
#define UV_FS_O_CREAT _O_CREAT
|
||||
#define UV_FS_O_EXCL _O_EXCL
|
||||
#define UV_FS_O_FILEMAP 0x20000000
|
||||
#define UV_FS_O_RANDOM _O_RANDOM
|
||||
#define UV_FS_O_RDONLY _O_RDONLY
|
||||
#define UV_FS_O_RDWR _O_RDWR
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/* Copyright libuv 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 "uv-common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include "win/internal.h"
|
||||
#else
|
||||
# include "unix/internal.h"
|
||||
#endif
|
||||
|
||||
static int uv__random(void* buf, size_t buflen) {
|
||||
int rc;
|
||||
|
||||
#if defined(__PASE__)
|
||||
rc = uv__random_readpath("/dev/urandom", buf, buflen);
|
||||
#elif defined(_AIX)
|
||||
rc = uv__random_readpath("/dev/random", buf, buflen);
|
||||
#elif defined(__APPLE__) || defined(__OpenBSD__) || \
|
||||
(defined(__ANDROID_API__) && __ANDROID_API__ >= 28)
|
||||
rc = uv__random_getentropy(buf, buflen);
|
||||
if (rc == UV_ENOSYS)
|
||||
rc = uv__random_devurandom(buf, buflen);
|
||||
#elif defined(__NetBSD__)
|
||||
rc = uv__random_sysctl(buf, buflen);
|
||||
#elif defined(__FreeBSD__) || defined(__linux__)
|
||||
rc = uv__random_getrandom(buf, buflen);
|
||||
if (rc == UV_ENOSYS)
|
||||
rc = uv__random_devurandom(buf, buflen);
|
||||
# if defined(__linux__)
|
||||
switch (rc) {
|
||||
case UV_EACCES:
|
||||
case UV_EIO:
|
||||
case UV_ELOOP:
|
||||
case UV_EMFILE:
|
||||
case UV_ENFILE:
|
||||
case UV_ENOENT:
|
||||
case UV_EPERM:
|
||||
rc = uv__random_sysctl(buf, buflen);
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
#elif defined(_WIN32)
|
||||
uv__once_init();
|
||||
rc = uv__random_rtlgenrandom(buf, buflen);
|
||||
#else
|
||||
rc = uv__random_devurandom(buf, buflen);
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void uv__random_work(struct uv__work* w) {
|
||||
uv_random_t* req;
|
||||
|
||||
req = container_of(w, uv_random_t, work_req);
|
||||
req->status = uv__random(req->buf, req->buflen);
|
||||
}
|
||||
|
||||
|
||||
static void uv__random_done(struct uv__work* w, int status) {
|
||||
uv_random_t* req;
|
||||
|
||||
req = container_of(w, uv_random_t, work_req);
|
||||
uv__req_unregister(req->loop, req);
|
||||
|
||||
if (status == 0)
|
||||
status = req->status;
|
||||
|
||||
req->cb(req, status, req->buf, req->buflen);
|
||||
}
|
||||
|
||||
|
||||
int uv_random(uv_loop_t* loop,
|
||||
uv_random_t* req,
|
||||
void *buf,
|
||||
size_t buflen,
|
||||
unsigned flags,
|
||||
uv_random_cb cb) {
|
||||
if (buflen > 0x7FFFFFFFu)
|
||||
return UV_E2BIG;
|
||||
|
||||
if (flags != 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (cb == NULL)
|
||||
return uv__random(buf, buflen);
|
||||
|
||||
uv__req_init(loop, req, UV_RANDOM);
|
||||
req->loop = loop;
|
||||
req->status = 0;
|
||||
req->cb = cb;
|
||||
req->buf = buf;
|
||||
req->buflen = buflen;
|
||||
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_CPU,
|
||||
uv__random_work,
|
||||
uv__random_done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -372,6 +372,10 @@ int uv_cancel(uv_req_t* req) {
|
||||
loop = ((uv_getnameinfo_t*) req)->loop;
|
||||
wreq = &((uv_getnameinfo_t*) req)->work_req;
|
||||
break;
|
||||
case UV_RANDOM:
|
||||
loop = ((uv_random_t*) req)->loop;
|
||||
wreq = &((uv_random_t*) req)->work_req;
|
||||
break;
|
||||
case UV_WORK:
|
||||
loop = ((uv_work_t*) req)->loop;
|
||||
wreq = &((uv_work_t*) req)->work_req;
|
||||
|
||||
@@ -74,7 +74,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
uint64_t repeat) {
|
||||
uint64_t clamped_timeout;
|
||||
|
||||
if (cb == NULL)
|
||||
if (uv__is_closing(handle) || cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
@@ -87,7 +87,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
handle->timer_cb = cb;
|
||||
handle->timeout = clamped_timeout;
|
||||
handle->repeat = repeat;
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
/* start_id is the second index to be compared in timer_less_than() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
heap_insert(timer_heap(handle->loop),
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in6_var.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
@@ -155,144 +156,3 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
}
|
||||
}
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
int sockfd, inet6, size = 1;
|
||||
struct ifconf ifc;
|
||||
struct ifreq *ifr, *p, flg;
|
||||
struct sockaddr_dl* sa_addr;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
ifc.ifc_req = (struct ifreq*)uv__malloc(size);
|
||||
ifc.ifc_len = size;
|
||||
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
|
||||
|
||||
/* Count all up and running ipv4/ipv6 addresses */
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
ifr = (struct ifreq*)
|
||||
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
||||
|
||||
if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
||||
p->ifr_addr.sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
(*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)) {
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
ifr = (struct ifreq*)
|
||||
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
||||
|
||||
if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
||||
p->ifr_addr.sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
inet6 = (p->ifr_addr.sa_family == AF_INET6);
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
/* All conditions above must match count loop */
|
||||
|
||||
address->name = uv__strdup(p->ifr_name);
|
||||
|
||||
if (inet6)
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||
else
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
|
||||
sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
|
||||
uv__close(sockfd);
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
if (inet6)
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||
else
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
|
||||
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
#undef ADDR_SIZE
|
||||
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
||||
@@ -1039,6 +1039,186 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
int sockfd, sock6fd, inet6, i, r, size = 1;
|
||||
struct ifconf ifc;
|
||||
struct ifreq *ifr, *p, flg;
|
||||
struct in6_ifreq if6;
|
||||
struct sockaddr_dl* sa_addr;
|
||||
|
||||
ifc.ifc_req = NULL;
|
||||
sock6fd = -1;
|
||||
r = 0;
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
|
||||
r = UV__ERR(errno);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (0 > (sock6fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP))) {
|
||||
r = UV__ERR(errno);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ifc.ifc_req = (struct ifreq*)uv__malloc(size);
|
||||
if (ifc.ifc_req == NULL) {
|
||||
r = UV_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
ifc.ifc_len = size;
|
||||
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
|
||||
|
||||
/* Count all up and running ipv4/ipv6 addresses */
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
ifr = (struct ifreq*)
|
||||
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
||||
|
||||
if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
||||
p->ifr_addr.sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
r = UV_ENOMEM;
|
||||
goto cleanup;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
ifr = (struct ifreq*)
|
||||
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
||||
|
||||
if (!(p->ifr_addr.sa_family == AF_INET6 ||
|
||||
p->ifr_addr.sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
inet6 = (p->ifr_addr.sa_family == AF_INET6);
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1)
|
||||
goto syserror;
|
||||
|
||||
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
/* All conditions above must match count loop */
|
||||
|
||||
address->name = uv__strdup(p->ifr_name);
|
||||
|
||||
if (inet6)
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
|
||||
else
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
|
||||
if (inet6) {
|
||||
memset(&if6, 0, sizeof(if6));
|
||||
r = uv__strscpy(if6.ifr_name, p->ifr_name, sizeof(if6.ifr_name));
|
||||
if (r == UV_E2BIG)
|
||||
goto cleanup;
|
||||
r = 0;
|
||||
memcpy(&if6.ifr_Addr, &p->ifr_addr, sizeof(if6.ifr_Addr));
|
||||
if (ioctl(sock6fd, SIOCGIFNETMASK6, &if6) == -1)
|
||||
goto syserror;
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*) &if6.ifr_Addr);
|
||||
/* Explicitly set family as the ioctl call appears to return it as 0. */
|
||||
address->netmask.netmask6.sin6_family = AF_INET6;
|
||||
} else {
|
||||
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1)
|
||||
goto syserror;
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
/* Explicitly set family as the ioctl call appears to return it as 0. */
|
||||
address->netmask.netmask4.sin_family = AF_INET;
|
||||
}
|
||||
|
||||
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
/* Fill in physical addresses. */
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
ifr = (struct ifreq*)
|
||||
((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
|
||||
|
||||
if (p->ifr_addr.sa_family != AF_LINK)
|
||||
continue;
|
||||
|
||||
address = *addresses;
|
||||
for (i = 0; i < *count; i++) {
|
||||
if (strcmp(address->name, p->ifr_name) == 0) {
|
||||
sa_addr = (struct sockaddr_dl*) &p->ifr_addr;
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
#undef ADDR_SIZE
|
||||
goto cleanup;
|
||||
|
||||
syserror:
|
||||
uv_free_interface_addresses(*addresses, *count);
|
||||
*addresses = NULL;
|
||||
*count = 0;
|
||||
r = UV_ENOSYS;
|
||||
|
||||
cleanup:
|
||||
if (sockfd != -1)
|
||||
uv__close(sockfd);
|
||||
if (sock6fd != -1)
|
||||
uv__close(sock6fd);
|
||||
uv__free(ifc.ifc_req);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct pollfd* events;
|
||||
uintptr_t i;
|
||||
|
||||
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <netinet/in.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
typedef struct NetlinkList
|
||||
{
|
||||
@@ -469,12 +470,14 @@ static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList,
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
case IFA_LOCAL:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
|
||||
{
|
||||
/* Make room for netmask */
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
l_addedNetmask = 1;
|
||||
}
|
||||
break;
|
||||
case IFA_BROADCAST:
|
||||
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
|
||||
break;
|
||||
|
||||
@@ -33,9 +33,12 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
static void uv__async_send(uv_loop_t* loop);
|
||||
static int uv__async_start(uv_loop_t* loop);
|
||||
static int uv__async_eventfd(void);
|
||||
|
||||
|
||||
int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
|
||||
@@ -190,36 +193,18 @@ static int uv__async_start(uv_loop_t* loop) {
|
||||
if (loop->async_io_watcher.fd != -1)
|
||||
return 0;
|
||||
|
||||
err = uv__async_eventfd();
|
||||
if (err >= 0) {
|
||||
pipefd[0] = err;
|
||||
pipefd[1] = -1;
|
||||
}
|
||||
else if (err == UV_ENOSYS) {
|
||||
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
|
||||
#if defined(__linux__)
|
||||
/* Save a file descriptor by opening one of the pipe descriptors as
|
||||
* read/write through the procfs. That file descriptor can then
|
||||
* function as both ends of the pipe.
|
||||
*/
|
||||
if (err == 0) {
|
||||
char buf[32];
|
||||
int fd;
|
||||
|
||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
|
||||
fd = uv__open_cloexec(buf, O_RDWR);
|
||||
if (fd >= 0) {
|
||||
uv__close(pipefd[0]);
|
||||
uv__close(pipefd[1]);
|
||||
pipefd[0] = fd;
|
||||
pipefd[1] = fd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef __linux__
|
||||
err = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (err < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
pipefd[0] = err;
|
||||
pipefd[1] = -1;
|
||||
#else
|
||||
err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
|
||||
if (err < 0)
|
||||
return err;
|
||||
#endif
|
||||
|
||||
uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
|
||||
uv__io_start(loop, &loop->async_io_watcher, POLLIN);
|
||||
@@ -253,46 +238,3 @@ void uv__async_stop(uv_loop_t* loop) {
|
||||
uv__close(loop->async_io_watcher.fd);
|
||||
loop->async_io_watcher.fd = -1;
|
||||
}
|
||||
|
||||
|
||||
static int uv__async_eventfd(void) {
|
||||
#if defined(__linux__)
|
||||
static int no_eventfd2;
|
||||
static int no_eventfd;
|
||||
int fd;
|
||||
|
||||
if (no_eventfd2)
|
||||
goto skip_eventfd2;
|
||||
|
||||
fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_eventfd2 = 1;
|
||||
|
||||
skip_eventfd2:
|
||||
|
||||
if (no_eventfd)
|
||||
goto skip_eventfd;
|
||||
|
||||
fd = uv__eventfd(0);
|
||||
if (fd != -1) {
|
||||
uv__cloexec(fd, 1);
|
||||
uv__nonblock(fd, 1);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_eventfd = 1;
|
||||
|
||||
skip_eventfd:
|
||||
|
||||
#endif
|
||||
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,12 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
|
||||
const int out = (*(volatile int*) ptr);
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
return out;
|
||||
#elif defined(_AIX) && defined(__ibmxl__)
|
||||
/* FIXME: This is not actually atomic but XLClang 16.1 for AIX
|
||||
does not provide __sync_val_compare_and_swap or an equivalent.
|
||||
Its documentation suggests using C++11 atomics but this is C. */
|
||||
__compare_and_swap((volatile int*)ptr, &oldval, newval);
|
||||
return oldval;
|
||||
#elif defined(__MVS__)
|
||||
unsigned int op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
|
||||
@@ -69,7 +69,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
uv_interface_address_t* address;
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__))
|
||||
int i;
|
||||
#endif
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
+173
-119
@@ -30,7 +30,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <fcntl.h> /* O_CLOEXEC */
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
@@ -50,37 +50,36 @@
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
#if defined(__APPLE__)
|
||||
# include <sys/filio.h>
|
||||
# if defined(O_CLOEXEC)
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
# endif /* defined(__APPLE__) */
|
||||
|
||||
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
# include <crt_externs.h>
|
||||
# include <mach-o/dyld.h> /* _NSGetExecutablePath */
|
||||
# define environ (*_NSGetEnviron())
|
||||
#else /* defined(__APPLE__) && !TARGET_OS_IPHONE */
|
||||
extern char** environ;
|
||||
#endif /* !(defined(__APPLE__) && !TARGET_OS_IPHONE) */
|
||||
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__NetBSD__)
|
||||
defined(__NetBSD__) || \
|
||||
defined(__OpenBSD__)
|
||||
# include <sys/sysctl.h>
|
||||
# include <sys/filio.h>
|
||||
# include <sys/wait.h>
|
||||
# include <sys/param.h>
|
||||
# include <sys/cpuset.h>
|
||||
# define UV__O_CLOEXEC O_CLOEXEC
|
||||
# if defined(__FreeBSD__) && __FreeBSD__ >= 10
|
||||
# if defined(__FreeBSD__) || defined(__linux__)
|
||||
# define uv__accept4 accept4
|
||||
# endif
|
||||
# if defined(__NetBSD__)
|
||||
# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
|
||||
# endif
|
||||
# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
|
||||
# endif
|
||||
# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
|
||||
# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
@@ -175,9 +174,7 @@ 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. */
|
||||
return;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
@@ -242,6 +239,8 @@ int uv__getiovmax(void) {
|
||||
|
||||
|
||||
static void uv__finish_close(uv_handle_t* handle) {
|
||||
uv_signal_t* sh;
|
||||
|
||||
/* 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.
|
||||
@@ -264,7 +263,20 @@ static void uv__finish_close(uv_handle_t* handle) {
|
||||
case UV_FS_EVENT:
|
||||
case UV_FS_POLL:
|
||||
case UV_POLL:
|
||||
break;
|
||||
|
||||
case UV_SIGNAL:
|
||||
/* If there are any caught signals "trapped" in the signal pipe,
|
||||
* we can't call the close callback yet. Reinserting the handle
|
||||
* into the closing queue makes the event loop spin but that's
|
||||
* okay because we only need to deliver the pending events.
|
||||
*/
|
||||
sh = (uv_signal_t*) handle;
|
||||
if (sh->caught_signals > sh->dispatched_signals) {
|
||||
handle->flags ^= UV_HANDLE_CLOSED;
|
||||
uv__make_close_pending(handle); /* Back into the queue. */
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case UV_NAMED_PIPE:
|
||||
@@ -468,52 +480,32 @@ int uv__accept(int sockfd) {
|
||||
int peerfd;
|
||||
int err;
|
||||
|
||||
(void) &err;
|
||||
assert(sockfd >= 0);
|
||||
|
||||
while (1) {
|
||||
#if defined(__linux__) || \
|
||||
(defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
|
||||
defined(__NetBSD__)
|
||||
static int no_accept4;
|
||||
do
|
||||
#ifdef uv__accept4
|
||||
peerfd = uv__accept4(sockfd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
#else
|
||||
peerfd = accept(sockfd, NULL, NULL);
|
||||
#endif
|
||||
while (peerfd == -1 && errno == EINTR);
|
||||
|
||||
if (no_accept4)
|
||||
goto skip;
|
||||
if (peerfd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
peerfd = uv__accept4(sockfd,
|
||||
NULL,
|
||||
NULL,
|
||||
UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
|
||||
if (peerfd != -1)
|
||||
return peerfd;
|
||||
#ifndef uv__accept4
|
||||
err = uv__cloexec(peerfd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(peerfd, 1);
|
||||
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_accept4 = 1;
|
||||
skip:
|
||||
if (err != 0) {
|
||||
uv__close(peerfd);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
peerfd = accept(sockfd, NULL, NULL);
|
||||
if (peerfd == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
err = uv__cloexec(peerfd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(peerfd, 1);
|
||||
|
||||
if (err) {
|
||||
uv__close(peerfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return peerfd;
|
||||
}
|
||||
return peerfd;
|
||||
}
|
||||
|
||||
|
||||
@@ -529,7 +521,7 @@ int uv__close_nocancel(int fd) {
|
||||
#if defined(__APPLE__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__)
|
||||
#if defined(__LP64__) || TARGET_OS_IPHONE
|
||||
extern int close$NOCANCEL(int);
|
||||
return close$NOCANCEL(fd);
|
||||
#else
|
||||
@@ -704,16 +696,38 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
|
||||
|
||||
int uv_cwd(char* buffer, size_t* size) {
|
||||
char scratch[1 + UV__PATH_MAX];
|
||||
|
||||
if (buffer == NULL || size == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (getcwd(buffer, *size) == NULL)
|
||||
/* Try to read directly into the user's buffer first... */
|
||||
if (getcwd(buffer, *size) != NULL)
|
||||
goto fixup;
|
||||
|
||||
if (errno != ERANGE)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* ...or into scratch space if the user's buffer is too small
|
||||
* so we can report how much space to provide on the next try.
|
||||
*/
|
||||
if (getcwd(scratch, sizeof(scratch)) == NULL)
|
||||
return UV__ERR(errno);
|
||||
|
||||
buffer = scratch;
|
||||
|
||||
fixup:
|
||||
|
||||
*size = strlen(buffer);
|
||||
|
||||
if (*size > 1 && buffer[*size - 1] == '/') {
|
||||
buffer[*size-1] = '\0';
|
||||
(*size)--;
|
||||
*size -= 1;
|
||||
buffer[*size] = '\0';
|
||||
}
|
||||
|
||||
if (buffer == scratch) {
|
||||
*size += 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -823,8 +837,8 @@ static void maybe_resize(uv_loop_t* loop, unsigned int len) {
|
||||
}
|
||||
|
||||
nwatchers = next_power_of_two(len + 2) - 2;
|
||||
watchers = uv__realloc(loop->watchers,
|
||||
(nwatchers + 2) * sizeof(loop->watchers[0]));
|
||||
watchers = uv__reallocf(loop->watchers,
|
||||
(nwatchers + 2) * sizeof(loop->watchers[0]));
|
||||
|
||||
if (watchers == NULL)
|
||||
abort();
|
||||
@@ -977,24 +991,17 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
|
||||
|
||||
int uv__open_cloexec(const char* path, int flags) {
|
||||
int err;
|
||||
#if defined(O_CLOEXEC)
|
||||
int fd;
|
||||
|
||||
#if defined(UV__O_CLOEXEC)
|
||||
static int no_cloexec;
|
||||
fd = open(path, flags | O_CLOEXEC);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (!no_cloexec) {
|
||||
fd = open(path, flags | UV__O_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* O_CLOEXEC not supported. */
|
||||
no_cloexec = 1;
|
||||
}
|
||||
#endif
|
||||
return fd;
|
||||
#else /* O_CLOEXEC */
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = open(path, flags);
|
||||
if (fd == -1)
|
||||
@@ -1007,58 +1014,35 @@ int uv__open_cloexec(const char* path, int flags) {
|
||||
}
|
||||
|
||||
return fd;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
|
||||
|
||||
int uv__dup2_cloexec(int oldfd, int newfd) {
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__linux__)
|
||||
int r;
|
||||
#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
|
||||
|
||||
r = dup3(oldfd, newfd, O_CLOEXEC);
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return r;
|
||||
#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
|
||||
r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != EINVAL)
|
||||
return UV__ERR(errno);
|
||||
/* Fall through. */
|
||||
#elif defined(__linux__)
|
||||
static int no_dup3;
|
||||
if (!no_dup3) {
|
||||
do
|
||||
r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
|
||||
while (r == -1 && errno == EBUSY);
|
||||
if (r != -1)
|
||||
return r;
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
/* Fall through. */
|
||||
no_dup3 = 1;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
int err;
|
||||
do
|
||||
r = dup2(oldfd, newfd);
|
||||
#if defined(__linux__)
|
||||
while (r == -1 && errno == EBUSY);
|
||||
#else
|
||||
while (0); /* Never retry. */
|
||||
#endif
|
||||
int err;
|
||||
int r;
|
||||
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
r = dup2(oldfd, newfd); /* Never retry. */
|
||||
if (r == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(newfd, 1);
|
||||
if (err) {
|
||||
uv__close(newfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
err = uv__cloexec(newfd, 1);
|
||||
if (err != 0) {
|
||||
uv__close(newfd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1265,6 +1249,62 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
int i, j, cnt;
|
||||
uv_env_item_t* envitem;
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
|
||||
for (i = 0; environ[i] != NULL; i++);
|
||||
|
||||
*envitems = uv__calloc(i, sizeof(**envitems));
|
||||
|
||||
if (envitems == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
for (j = 0, cnt = 0; j < i; j++) {
|
||||
char* buf;
|
||||
char* ptr;
|
||||
|
||||
if (environ[j] == NULL)
|
||||
break;
|
||||
|
||||
buf = uv__strdup(environ[j]);
|
||||
if (buf == NULL)
|
||||
goto fail;
|
||||
|
||||
ptr = strchr(buf, '=');
|
||||
if (ptr == NULL) {
|
||||
uv__free(buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
envitem = &(*envitems)[cnt];
|
||||
envitem->name = buf;
|
||||
envitem->value = ptr + 1;
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < cnt; i++) {
|
||||
envitem = &(*envitems)[cnt];
|
||||
uv__free(envitem->name);
|
||||
}
|
||||
uv__free(*envitems);
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
char* var;
|
||||
size_t len;
|
||||
@@ -1488,3 +1528,17 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
tv->tv_usec = (int32_t) time.tv_usec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sleep(unsigned int msec) {
|
||||
struct timespec timeout;
|
||||
int rc;
|
||||
|
||||
timeout.tv_sec = msec / 1000;
|
||||
timeout.tv_nsec = (msec % 1000) * 1000 * 1000;
|
||||
|
||||
do
|
||||
rc = nanosleep(&timeout, &timeout);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
(void)cpu_infos;
|
||||
(void)count;
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -33,56 +34,51 @@
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int 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*);
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
|
||||
if (core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
if (application_services_handle != NULL) {
|
||||
dlclose(application_services_handle);
|
||||
application_services_handle = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
|
||||
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");
|
||||
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);
|
||||
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
CFTypeRef asn;
|
||||
int err;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
err = UV_ENOENT;
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
@@ -111,6 +107,8 @@ void uv__set_process_title_platform_init(void) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
@@ -141,58 +139,55 @@ void uv__set_process_title_platform_init(void) {
|
||||
"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"));
|
||||
|
||||
if (hi_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
|
||||
hi_services_bundle,
|
||||
S("SetApplicationIsDaemon"));
|
||||
*(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSApplicationCheckIn"));
|
||||
|
||||
if (pLSApplicationCheckIn == NULL)
|
||||
goto out;
|
||||
|
||||
*(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
|
||||
if (pSetApplicationIsDaemon == NULL ||
|
||||
pLSApplicationCheckIn == NULL ||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
|
||||
if (pLSSetApplicationLaunchServicesServerConnectionStatus == NULL)
|
||||
goto out;
|
||||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
|
||||
/* Check into process manager?! */
|
||||
pLSApplicationCheckIn(-2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
|
||||
err = UV_EBUSY;
|
||||
if (asn == NULL)
|
||||
goto out;
|
||||
|
||||
err = UV_EINVAL;
|
||||
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
|
||||
asn,
|
||||
*display_name_key,
|
||||
S(title),
|
||||
NULL) != noErr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
return;
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
uv__set_process_title_platform_fini();
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
int which[] = {CTL_HW, HW_MEMSIZE};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -127,7 +127,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
@@ -162,7 +162,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -223,14 +223,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
mib[3] = -1;
|
||||
|
||||
abspath_size = sizeof abspath;
|
||||
if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), abspath, &abspath_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
assert(abspath_size > 0);
|
||||
@@ -130,7 +130,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -147,7 +147,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
@@ -168,7 +168,7 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
|
||||
kinfo_size = sizeof(kinfo);
|
||||
|
||||
if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &kinfo_size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
page_size = getpagesize();
|
||||
@@ -290,12 +290,26 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags) {
|
||||
#if __FreeBSD__ >= 11
|
||||
return sendmmsg(fd, mmsg, vlen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout) {
|
||||
#if __FreeBSD__ >= 11
|
||||
return recvmmsg(fd, mmsg, vlen, flags, timeout);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
+288
-57
@@ -30,6 +30,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -70,6 +71,20 @@
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
#elif defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||
# include <sys/statvfs.h>
|
||||
#else
|
||||
# include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
@@ -202,7 +217,11 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
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;
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
return utimensat(req->file, NULL, ts, 0);
|
||||
#else
|
||||
return futimens(req->file, ts);
|
||||
#endif
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
@@ -250,21 +269,97 @@ static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
static int no_cloexec_support;
|
||||
int r;
|
||||
static int (*uv__mkostemp)(char*, int);
|
||||
|
||||
/* Try O_CLOEXEC before entering locks */
|
||||
if (no_cloexec_support == 0) {
|
||||
|
||||
static void uv__mkostemp_initonce(void) {
|
||||
/* z/os doesn't have RTLD_DEFAULT but that's okay
|
||||
* because it doesn't have mkostemp(O_CLOEXEC) either.
|
||||
*/
|
||||
#ifdef RTLD_DEFAULT
|
||||
uv__mkostemp = (int (*)(char*, int)) dlsym(RTLD_DEFAULT, "mkostemp");
|
||||
|
||||
/* We don't care about errors, but we do want to clean them up.
|
||||
* If there has been no error, then dlerror() will just return
|
||||
* NULL.
|
||||
*/
|
||||
dlerror();
|
||||
#endif /* RTLD_DEFAULT */
|
||||
}
|
||||
|
||||
|
||||
static int uv__fs_mkstemp(uv_fs_t* req) {
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
int r;
|
||||
#ifdef O_CLOEXEC
|
||||
r = open(req->path, req->flags | O_CLOEXEC, req->mode);
|
||||
static int no_cloexec_support;
|
||||
#endif
|
||||
static const char pattern[] = "XXXXXX";
|
||||
static const size_t pattern_size = sizeof(pattern) - 1;
|
||||
char* path;
|
||||
size_t path_length;
|
||||
|
||||
path = (char*) req->path;
|
||||
path_length = strlen(path);
|
||||
|
||||
/* EINVAL can be returned for 2 reasons:
|
||||
1. The template's last 6 characters were not XXXXXX
|
||||
2. open() didn't support O_CLOEXEC
|
||||
We want to avoid going to the fallback path in case
|
||||
of 1, so it's manually checked before. */
|
||||
if (path_length < pattern_size ||
|
||||
strcmp(path + path_length - pattern_size, pattern)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uv_once(&once, uv__mkostemp_initonce);
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
if (no_cloexec_support == 0 && uv__mkostemp != NULL) {
|
||||
r = uv__mkostemp(path, O_CLOEXEC);
|
||||
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
/* If mkostemp() returns EINVAL, it means the kernel doesn't
|
||||
support O_CLOEXEC, so we just fallback to mkstemp() below. */
|
||||
if (errno != EINVAL)
|
||||
return r;
|
||||
|
||||
/* We set the static variable so that next calls don't even
|
||||
try to use mkostemp. */
|
||||
no_cloexec_support = 1;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
#endif /* O_CLOEXEC */
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
|
||||
r = mkstemp(path);
|
||||
|
||||
/* In case of failure `uv__cloexec` will leave error in `errno`,
|
||||
* so it is enough to just set `r` to `-1`.
|
||||
*/
|
||||
if (r >= 0 && uv__cloexec(r, 1) != 0) {
|
||||
r = uv__close(r);
|
||||
if (r != 0)
|
||||
abort();
|
||||
r = -1;
|
||||
}
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
#ifdef O_CLOEXEC
|
||||
return open(req->path, req->flags | O_CLOEXEC, req->mode);
|
||||
#else /* O_CLOEXEC */
|
||||
int r;
|
||||
|
||||
if (req->cb != NULL)
|
||||
uv_rwlock_rdlock(&req->loop->cloexec_lock);
|
||||
@@ -285,9 +380,60 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
uv_rwlock_rdunlock(&req->loop->cloexec_lock);
|
||||
|
||||
return r;
|
||||
#endif /* O_CLOEXEC */
|
||||
}
|
||||
|
||||
|
||||
#if !HAVE_PREADV
|
||||
static ssize_t uv__fs_preadv(uv_file fd,
|
||||
uv_buf_t* bufs,
|
||||
unsigned int nbufs,
|
||||
off_t off) {
|
||||
uv_buf_t* buf;
|
||||
uv_buf_t* end;
|
||||
ssize_t result;
|
||||
ssize_t rc;
|
||||
size_t pos;
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
result = 0;
|
||||
pos = 0;
|
||||
buf = bufs + 0;
|
||||
end = bufs + nbufs;
|
||||
|
||||
for (;;) {
|
||||
do
|
||||
rc = pread(fd, buf->base + pos, buf->len - pos, off + result);
|
||||
while (rc == -1 && errno == EINTR);
|
||||
|
||||
if (rc == 0)
|
||||
break;
|
||||
|
||||
if (rc == -1 && result == 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (rc == -1)
|
||||
break; /* We read some data so return that, ignore the error. */
|
||||
|
||||
pos += rc;
|
||||
result += rc;
|
||||
|
||||
if (pos < buf->len)
|
||||
continue;
|
||||
|
||||
pos = 0;
|
||||
buf += 1;
|
||||
|
||||
if (buf == end)
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static int no_preadv;
|
||||
@@ -317,7 +463,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
if (no_preadv) retry:
|
||||
# endif
|
||||
{
|
||||
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
@@ -481,14 +627,39 @@ static int uv__fs_closedir(uv_fs_t* req) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_POSIX_PATH_MAX)
|
||||
# define UV__FS_PATH_MAX _POSIX_PATH_MAX
|
||||
#elif defined(PATH_MAX)
|
||||
# define UV__FS_PATH_MAX PATH_MAX
|
||||
static int uv__fs_statfs(uv_fs_t* req) {
|
||||
uv_statfs_t* stat_fs;
|
||||
#if defined(__sun) || defined(__MVS__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||
struct statvfs buf;
|
||||
|
||||
if (0 != statvfs(req->path, &buf))
|
||||
#else
|
||||
# define UV__FS_PATH_MAX_FALLBACK 8192
|
||||
# define UV__FS_PATH_MAX UV__FS_PATH_MAX_FALLBACK
|
||||
struct statfs buf;
|
||||
|
||||
if (0 != statfs(req->path, &buf))
|
||||
#endif /* defined(__sun) */
|
||||
return -1;
|
||||
|
||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||
if (stat_fs == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__sun) || defined(__MVS__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
|
||||
stat_fs->f_type = 0; /* f_type is not supported. */
|
||||
#else
|
||||
stat_fs->f_type = buf.f_type;
|
||||
#endif
|
||||
stat_fs->f_bsize = buf.f_bsize;
|
||||
stat_fs->f_blocks = buf.f_blocks;
|
||||
stat_fs->f_bfree = buf.f_bfree;
|
||||
stat_fs->f_bavail = buf.f_bavail;
|
||||
stat_fs->f_files = buf.f_files;
|
||||
stat_fs->f_ffree = buf.f_ffree;
|
||||
req->ptr = stat_fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
ssize_t pathmax;
|
||||
@@ -496,7 +667,7 @@ static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
pathmax = pathconf(path, _PC_PATH_MAX);
|
||||
|
||||
if (pathmax == -1)
|
||||
pathmax = UV__FS_PATH_MAX;
|
||||
pathmax = UV__PATH_MAX;
|
||||
|
||||
return pathmax;
|
||||
}
|
||||
@@ -505,9 +676,10 @@ 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)
|
||||
#if defined(_POSIX_PATH_MAX) || defined(PATH_MAX)
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#else
|
||||
/* We may not have a real PATH_MAX. Read size of link. */
|
||||
struct stat st;
|
||||
int ret;
|
||||
@@ -525,8 +697,6 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
for some symlinks, such as those in /proc or /sys. */
|
||||
if (maxlen == 0)
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#else
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#endif
|
||||
|
||||
buf = uv__malloc(maxlen);
|
||||
@@ -549,14 +719,10 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
|
||||
/* Uncommon case: resize to make room for the trailing nul byte. */
|
||||
if (len == maxlen) {
|
||||
newbuf = uv__realloc(buf, len + 1);
|
||||
buf = uv__reallocf(buf, len + 1);
|
||||
|
||||
if (newbuf == NULL) {
|
||||
uv__free(buf);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = newbuf;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
@@ -918,12 +1084,14 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
uv_fs_t fs_req;
|
||||
uv_file srcfd;
|
||||
uv_file dstfd;
|
||||
struct stat statsbuf;
|
||||
struct stat src_statsbuf;
|
||||
struct stat dst_statsbuf;
|
||||
int dst_flags;
|
||||
int result;
|
||||
int err;
|
||||
size_t bytes_to_send;
|
||||
int64_t in_offset;
|
||||
ssize_t bytes_written;
|
||||
|
||||
dstfd = -1;
|
||||
err = 0;
|
||||
@@ -936,7 +1104,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
return srcfd;
|
||||
|
||||
/* Get the source file's mode. */
|
||||
if (fstat(srcfd, &statsbuf)) {
|
||||
if (fstat(srcfd, &src_statsbuf)) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
@@ -951,7 +1119,7 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
&fs_req,
|
||||
req->new_path,
|
||||
dst_flags,
|
||||
statsbuf.st_mode,
|
||||
src_statsbuf.st_mode,
|
||||
NULL);
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
|
||||
@@ -960,26 +1128,55 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fchmod(dstfd, statsbuf.st_mode) == -1) {
|
||||
/* Get the destination file's mode. */
|
||||
if (fstat(dstfd, &dst_statsbuf)) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check if srcfd and dstfd refer to the same file */
|
||||
if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
|
||||
src_statsbuf.st_ino == dst_statsbuf.st_ino) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
|
||||
err = UV__ERR(errno);
|
||||
#ifdef __linux__
|
||||
if (err != UV_EPERM)
|
||||
goto out;
|
||||
|
||||
{
|
||||
struct statfs s;
|
||||
|
||||
/* fchmod() on CIFS shares always fails with EPERM unless the share is
|
||||
* mounted with "noperm". As fchmod() is a meaningless operation on such
|
||||
* shares anyway, detect that condition and squelch the error.
|
||||
*/
|
||||
if (fstatfs(dstfd, &s) == -1)
|
||||
goto out;
|
||||
|
||||
if (s.f_type != /* CIFS */ 0xFF534D42u)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
#else /* !__linux__ */
|
||||
goto out;
|
||||
#endif /* !__linux__ */
|
||||
}
|
||||
|
||||
#ifdef FICLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE ||
|
||||
req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
if (ioctl(dstfd, FICLONE, srcfd) == -1) {
|
||||
/* 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) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
} else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = UV_ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
if (ioctl(dstfd, FICLONE, srcfd) == 0) {
|
||||
/* ioctl() with FICLONE succeeded. */
|
||||
goto out;
|
||||
}
|
||||
/* If an error occurred and force was set, return the error to the caller;
|
||||
* fall back to sendfile() when force was not set. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -990,21 +1187,20 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
}
|
||||
#endif
|
||||
|
||||
bytes_to_send = statsbuf.st_size;
|
||||
bytes_to_send = src_statsbuf.st_size;
|
||||
in_offset = 0;
|
||||
while (bytes_to_send != 0) {
|
||||
err = uv_fs_sendfile(NULL,
|
||||
&fs_req,
|
||||
dstfd,
|
||||
srcfd,
|
||||
in_offset,
|
||||
bytes_to_send,
|
||||
NULL);
|
||||
uv_fs_sendfile(NULL, &fs_req, dstfd, srcfd, in_offset, bytes_to_send, NULL);
|
||||
bytes_written = fs_req.result;
|
||||
uv_fs_req_cleanup(&fs_req);
|
||||
if (err < 0)
|
||||
|
||||
if (bytes_written < 0) {
|
||||
err = bytes_written;
|
||||
break;
|
||||
bytes_to_send -= fs_req.result;
|
||||
in_offset += fs_req.result;
|
||||
}
|
||||
|
||||
bytes_to_send -= bytes_written;
|
||||
in_offset += bytes_written;
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -1151,13 +1347,22 @@ static int uv__fs_statx(int fd,
|
||||
|
||||
rc = uv__statx(dirfd, path, flags, mode, &statxbuf);
|
||||
|
||||
if (rc == -1) {
|
||||
switch (rc) {
|
||||
case 0:
|
||||
break;
|
||||
case -1:
|
||||
/* EPERM happens when a seccomp filter rejects the system call.
|
||||
* Has been observed with libseccomp < 2.3.3 and docker < 18.04.
|
||||
*/
|
||||
if (errno != EINVAL && errno != EPERM && errno != ENOSYS)
|
||||
return -1;
|
||||
|
||||
/* Fall through. */
|
||||
default:
|
||||
/* Normally on success, zero is returned and On error, -1 is returned.
|
||||
* Observed on S390 RHEL running in a docker container with statx not
|
||||
* implemented, rc might return 1 with 0 set as the error code in which
|
||||
* case we return ENOSYS.
|
||||
*/
|
||||
no_statx = 1;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
@@ -1332,6 +1537,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(LINK, link(req->path, req->new_path));
|
||||
X(MKDIR, mkdir(req->path, req->mode));
|
||||
X(MKDTEMP, uv__fs_mkdtemp(req));
|
||||
X(MKSTEMP, uv__fs_mkstemp(req));
|
||||
X(OPEN, uv__fs_open(req));
|
||||
X(READ, uv__fs_read(req));
|
||||
X(SCANDIR, uv__fs_scandir(req));
|
||||
@@ -1344,6 +1550,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(RMDIR, rmdir(req->path));
|
||||
X(SENDFILE, uv__fs_sendfile(req));
|
||||
X(STAT, uv__fs_stat(req->path, &req->statbuf));
|
||||
X(STATFS, uv__fs_statfs(req));
|
||||
X(SYMLINK, symlink(req->path, req->new_path));
|
||||
X(UNLINK, unlink(req->path));
|
||||
X(UTIME, uv__fs_utime(req));
|
||||
@@ -1555,6 +1762,18 @@ int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
INIT(MKSTEMP);
|
||||
req->path = uv__strdup(tpl);
|
||||
if (req->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_open(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1773,10 +1992,12 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
|
||||
/* Only necessary for asychronous requests, i.e., requests with a callback.
|
||||
* Synchronous ones don't copy their arguments and have req->path and
|
||||
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
|
||||
* exception to the rule, it always allocates memory.
|
||||
* req->new_path pointing to user-owned memory. UV_FS_MKDTEMP and
|
||||
* UV_FS_MKSTEMP are the exception to the rule, they always allocate memory.
|
||||
*/
|
||||
if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
|
||||
if (req->path != NULL &&
|
||||
(req->cb != NULL ||
|
||||
req->fs_type == UV_FS_MKDTEMP || req->fs_type == UV_FS_MKSTEMP))
|
||||
uv__free((void*) req->path); /* Memory is shared with req->new_path. */
|
||||
|
||||
req->path = NULL;
|
||||
@@ -1816,3 +2037,13 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
req->flags = flags;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
INIT(STATFS);
|
||||
PATH;
|
||||
POST;
|
||||
}
|
||||
|
||||
@@ -263,10 +263,12 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
if (len < handle->realpath_len)
|
||||
continue;
|
||||
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* (unless watching root, which alone keeps a trailing slash on the realpath)
|
||||
* or that we matched the whole string */
|
||||
if (handle->realpath_len != len &&
|
||||
handle->realpath_len > 1 &&
|
||||
path[handle->realpath_len] != '/')
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* or that we matched the whole string */
|
||||
continue;
|
||||
|
||||
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
@@ -745,6 +747,8 @@ static void* uv__cf_loop_runner(void* arg) {
|
||||
state->signal_source,
|
||||
*pkCFRunLoopDefaultMode);
|
||||
|
||||
state->loop = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -797,13 +801,14 @@ int uv__cf_loop_signal(uv_loop_t* loop,
|
||||
|
||||
uv_mutex_lock(&loop->cf_mutex);
|
||||
QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
state = loop->cf_state;
|
||||
assert(state != NULL);
|
||||
pCFRunLoopSourceSignal(state->signal_source);
|
||||
pCFRunLoopWakeUp(state->loop);
|
||||
|
||||
uv_mutex_unlock(&loop->cf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -165,12 +165,3 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
uv__free(cpu_infos[i].model);
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <as400_protos.h>
|
||||
#include <as400_types.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -98,24 +99,91 @@ typedef struct {
|
||||
} SSTS0200;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char header[208];
|
||||
unsigned char loca_adapter_address[12];
|
||||
} LIND0500;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int bytes_provided;
|
||||
int bytes_available;
|
||||
char msgid[7];
|
||||
} errcode_s;
|
||||
|
||||
|
||||
static const unsigned char e2a[256] = {
|
||||
0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
|
||||
128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
|
||||
144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
|
||||
32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
|
||||
38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
|
||||
45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
|
||||
186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
|
||||
195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
|
||||
202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
|
||||
209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
|
||||
216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
|
||||
123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
|
||||
125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
|
||||
92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255};
|
||||
|
||||
|
||||
static const unsigned char a2e[256] = {
|
||||
0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
|
||||
64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
|
||||
124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
|
||||
215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
|
||||
121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
|
||||
151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
|
||||
32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
|
||||
48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
|
||||
65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
|
||||
88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
|
||||
118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
|
||||
159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
|
||||
184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
|
||||
220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255};
|
||||
|
||||
|
||||
static void iconv_e2a(unsigned char src[], unsigned char dst[], size_t length) {
|
||||
size_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
dst[i] = e2a[src[i]];
|
||||
}
|
||||
|
||||
|
||||
static void iconv_a2e(const char* src, unsigned char dst[], size_t length) {
|
||||
size_t srclen;
|
||||
size_t i;
|
||||
|
||||
srclen = strlen(src);
|
||||
if (srclen > length)
|
||||
abort();
|
||||
for (i = 0; i < srclen; i++)
|
||||
dst[i] = a2e[src[i]];
|
||||
/* padding the remaining part with spaces */
|
||||
for (; i < length; i++)
|
||||
dst[i] = a2e[' '];
|
||||
}
|
||||
|
||||
|
||||
static int get_ibmi_system_status(SSTS0200* rcvr) {
|
||||
/* rcvrlen is input parameter 2 to QWCRSSTS */
|
||||
unsigned int rcvrlen = sizeof(*rcvr);
|
||||
unsigned char format[8], reset_status[10];
|
||||
|
||||
/* format is input parameter 3 to QWCRSSTS ("SSTS0200" in EBCDIC) */
|
||||
unsigned char format[] = {0xE2, 0xE2, 0xE3, 0xE2, 0xF0, 0xF2, 0xF0, 0xF0};
|
||||
|
||||
/* reset_status is input parameter 4 to QWCRSSTS ("*NO " in EBCDIC) */
|
||||
unsigned char reset_status[] = {
|
||||
0x5C, 0xD5, 0xD6, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
|
||||
};
|
||||
/* format is input parameter 3 to QWCRSSTS */
|
||||
iconv_a2e("SSTS0200", format, sizeof(format));
|
||||
/* reset_status is input parameter 4 */
|
||||
iconv_a2e("*NO", reset_status, sizeof(reset_status));
|
||||
|
||||
/* errcode is input parameter 5 to QWCRSSTS */
|
||||
struct _errcode {
|
||||
int bytes_provided;
|
||||
int bytes_available;
|
||||
char msgid[7];
|
||||
} errcode;
|
||||
errcode_s errcode;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
|
||||
ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
|
||||
@@ -145,7 +213,7 @@ static int get_ibmi_system_status(SSTS0200* rcvr) {
|
||||
qwcrssts_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QWCRSSTS API from PASE */
|
||||
rc = _PGMCALL(&qwcrssts_pointer, (void**)&qwcrssts_argv, 0);
|
||||
rc = _PGMCALL(&qwcrssts_pointer, qwcrssts_argv, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -157,19 +225,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
if (get_ibmi_system_status(&rcvr))
|
||||
return 0;
|
||||
|
||||
/* The amount of main storage, in kilobytes, in the system. */
|
||||
uint64_t main_storage_size = rcvr.main_storage_size;
|
||||
|
||||
/* The current amount of storage in use for temporary objects.
|
||||
* in millions (M) of bytes.
|
||||
*/
|
||||
uint64_t current_unprotected_storage_used =
|
||||
rcvr.current_unprotected_storage_used * 1024ULL;
|
||||
|
||||
uint64_t free_storage_size =
|
||||
(main_storage_size - current_unprotected_storage_used) * 1024ULL;
|
||||
|
||||
return free_storage_size < 0 ? 0 : free_storage_size;
|
||||
return (uint64_t)rcvr.main_storage_size * 1024ULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,3 +304,159 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int get_ibmi_physical_address(const char* line, char (*phys_addr)[6]) {
|
||||
LIND0500 rcvr;
|
||||
/* rcvrlen is input parameter 2 to QDCRLIND */
|
||||
unsigned int rcvrlen = sizeof(rcvr);
|
||||
unsigned char format[8], line_name[10];
|
||||
unsigned char mac_addr[sizeof(rcvr.loca_adapter_address)];
|
||||
int c[6];
|
||||
|
||||
/* format is input parameter 3 to QDCRLIND */
|
||||
iconv_a2e("LIND0500", format, sizeof(format));
|
||||
|
||||
/* line_name is input parameter 4 to QDCRLIND */
|
||||
iconv_a2e(line, line_name, sizeof(line_name));
|
||||
|
||||
/* err is input parameter 5 to QDCRLIND */
|
||||
errcode_s err;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QDCRLIND */
|
||||
ILEpointer __attribute__((aligned(16))) qdcrlind_pointer;
|
||||
|
||||
/* qwcrssts_argv is the array of argument pointers to QDCRLIND */
|
||||
void* qdcrlind_argv[6];
|
||||
|
||||
/* Set the IBM i pointer to the QSYS/QDCRLIND *PGM object */
|
||||
int rc = _RSLOBJ2(&qdcrlind_pointer, RSLOBJ_TS_PGM, "QDCRLIND", "QSYS");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* initialize the QDCRLIND returned info structure */
|
||||
memset(&rcvr, 0, sizeof(rcvr));
|
||||
|
||||
/* initialize the QDCRLIND error code structure */
|
||||
memset(&err, 0, sizeof(err));
|
||||
err.bytes_provided = sizeof(err);
|
||||
|
||||
/* initialize the array of argument pointers for the QDCRLIND API */
|
||||
qdcrlind_argv[0] = &rcvr;
|
||||
qdcrlind_argv[1] = &rcvrlen;
|
||||
qdcrlind_argv[2] = &format;
|
||||
qdcrlind_argv[3] = &line_name;
|
||||
qdcrlind_argv[4] = &err;
|
||||
qdcrlind_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QDCRLIND API from PASE */
|
||||
rc = _PGMCALL(&qdcrlind_pointer, qdcrlind_argv, 0);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* convert ebcdic loca_adapter_address to ascii first */
|
||||
iconv_e2a(rcvr.loca_adapter_address, mac_addr,
|
||||
sizeof(rcvr.loca_adapter_address));
|
||||
|
||||
/* convert loca_adapter_address(char[12]) to phys_addr(char[6]) */
|
||||
int r = sscanf(mac_addr, "%02x%02x%02x%02x%02x%02x",
|
||||
&c[0], &c[1], &c[2], &c[3], &c[4], &c[5]);
|
||||
|
||||
if (r == ARRAY_SIZE(c)) {
|
||||
(*phys_addr)[0] = c[0];
|
||||
(*phys_addr)[1] = c[1];
|
||||
(*phys_addr)[2] = c[2];
|
||||
(*phys_addr)[3] = c[3];
|
||||
(*phys_addr)[4] = c[4];
|
||||
(*phys_addr)[5] = c[5];
|
||||
} else {
|
||||
memset(*phys_addr, 0, sizeof(*phys_addr));
|
||||
rc = -1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
struct ifaddrs_pase *ifap = NULL, *cur;
|
||||
int inet6, r = 0;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (Qp2getifaddrs(&ifap))
|
||||
return UV_ENOSYS;
|
||||
|
||||
/* The first loop to get the size of the array to be allocated */
|
||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||
cur->ifa_addr->sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
Qp2freeifaddrs(ifap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
if (*addresses == NULL) {
|
||||
Qp2freeifaddrs(ifap);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
/* The second loop to fill in the array */
|
||||
for (cur = ifap; cur; cur = cur->ifa_next) {
|
||||
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
|
||||
cur->ifa_addr->sa_family == AF_INET))
|
||||
continue;
|
||||
|
||||
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
|
||||
continue;
|
||||
|
||||
address->name = uv__strdup(cur->ifa_name);
|
||||
|
||||
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
|
||||
|
||||
if (inet6) {
|
||||
address->address.address6 = *((struct sockaddr_in6*)cur->ifa_addr);
|
||||
address->netmask.netmask6 = *((struct sockaddr_in6*)cur->ifa_netmask);
|
||||
address->netmask.netmask6.sin6_family = AF_INET6;
|
||||
} else {
|
||||
address->address.address4 = *((struct sockaddr_in*)cur->ifa_addr);
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*)cur->ifa_netmask);
|
||||
address->netmask.netmask4.sin_family = AF_INET;
|
||||
}
|
||||
address->is_internal = cur->ifa_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
if (!address->is_internal) {
|
||||
int rc = get_ibmi_physical_address(address->name, &address->phys_addr);
|
||||
if (rc != 0)
|
||||
r = rc;
|
||||
}
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
Qp2freeifaddrs(ifap);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
uv__free(addresses[i].name);
|
||||
}
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,11 +25,13 @@
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
|
||||
#include <stdlib.h> /* abort */
|
||||
#include <string.h> /* strrchr */
|
||||
#include <fcntl.h> /* O_CLOEXEC, may be */
|
||||
#include <fcntl.h> /* O_CLOEXEC and O_NONBLOCK, if supported. */
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__STRICT_ANSI__)
|
||||
# define inline __inline
|
||||
@@ -60,6 +62,14 @@
|
||||
# include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#if defined(_POSIX_PATH_MAX)
|
||||
# define UV__PATH_MAX _POSIX_PATH_MAX
|
||||
#elif defined(PATH_MAX)
|
||||
# define UV__PATH_MAX PATH_MAX
|
||||
#else
|
||||
# define UV__PATH_MAX 8192
|
||||
#endif
|
||||
|
||||
#if defined(CMAKE_BOOTSTRAP)
|
||||
# undef pthread_atfork
|
||||
# define pthread_atfork(prepare, parent, child) \
|
||||
@@ -271,6 +281,12 @@ uv_handle_type uv__handle_type(int fd);
|
||||
FILE* uv__open_file(const char* path);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
|
||||
/* random */
|
||||
int uv__random_devurandom(void* buf, size_t buflen);
|
||||
int uv__random_getrandom(void* buf, size_t buflen);
|
||||
int uv__random_getentropy(void* buf, size_t buflen);
|
||||
int uv__random_readpath(const char* path, void* buf, size_t buflen);
|
||||
int uv__random_sysctl(void* buf, size_t buflen);
|
||||
|
||||
#if defined(__APPLE__) && !defined(CMAKE_BOOTSTRAP)
|
||||
int uv___stream_fd(const uv_stream_t* handle);
|
||||
@@ -279,13 +295,12 @@ int uv___stream_fd(const uv_stream_t* handle);
|
||||
#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#ifdef UV__O_NONBLOCK
|
||||
# define UV__F_NONBLOCK UV__O_NONBLOCK
|
||||
#ifdef O_NONBLOCK
|
||||
# define UV__F_NONBLOCK O_NONBLOCK
|
||||
#else
|
||||
# define UV__F_NONBLOCK 1
|
||||
#endif
|
||||
|
||||
int uv__make_socketpair(int fds[2], int flags);
|
||||
int uv__make_pipe(int fds[2], int flags);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -323,4 +338,27 @@ int uv__getsockpeername(const uv_handle_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
|
||||
#if defined(__linux__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__)
|
||||
#define HAVE_MMSG 1
|
||||
struct uv__mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout);
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags);
|
||||
#else
|
||||
#define HAVE_MMSG 0
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
|
||||
@@ -454,10 +454,26 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
int fd;
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
struct stat statbuf;
|
||||
#endif
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
handle->cb = cb;
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(handle->path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
@@ -465,14 +481,17 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
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;
|
||||
|
||||
if (!uv__has_forked_with_cfrunloop) {
|
||||
int r;
|
||||
/* The fallback fd is not used */
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close_nocheckstdio(fd);
|
||||
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);
|
||||
@@ -482,20 +501,9 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
}
|
||||
return r;
|
||||
}
|
||||
fallback:
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
|
||||
/* 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) {
|
||||
uv__close_nocheckstdio(fd);
|
||||
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);
|
||||
@@ -514,7 +522,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (!uv__has_forked_with_cfrunloop)
|
||||
if (!uv__has_forked_with_cfrunloop && handle->cf_cb != NULL)
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -90,7 +90,12 @@ int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
* a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
|
||||
* architectures, we just use that instead.
|
||||
*/
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
fd = -1;
|
||||
errno = ENOSYS;
|
||||
#else
|
||||
fd = epoll_create1(O_CLOEXEC);
|
||||
#endif
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the O_CLOEXEC flag.
|
||||
@@ -203,6 +208,8 @@ 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 epoll_event events[1024];
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
@@ -210,7 +217,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
sigset_t* psigset;
|
||||
uint64_t sigmask;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
@@ -262,11 +269,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
psigset = NULL;
|
||||
sigmask = 0;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
psigset = &sigset;
|
||||
sigmask |= 1 << (SIGPROF - 1);
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
@@ -281,11 +288,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
psigset);
|
||||
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)) {
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
|
||||
nfds = -1;
|
||||
errno = ENOSYS;
|
||||
#else
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
&sigset);
|
||||
#endif
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_pwait = 1;
|
||||
} else {
|
||||
nfds = 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();
|
||||
|
||||
/* 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
|
||||
@@ -306,6 +337,12 @@ 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();
|
||||
|
||||
@@ -322,9 +359,19 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
have_signals = 0;
|
||||
nevents = 0;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = (void*) events;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
{
|
||||
/* Squelch a -Waddress-of-packed-member warning with gcc >= 9. */
|
||||
union {
|
||||
struct epoll_event* events;
|
||||
uv__io_t* watchers;
|
||||
} x;
|
||||
|
||||
x.events = events;
|
||||
assert(loop->watchers != NULL);
|
||||
loop->watchers[loop->nwatchers] = x.watchers;
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
}
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data.fd;
|
||||
@@ -812,16 +859,6 @@ static uint64_t read_cpufreq(unsigned int cpunum) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
@@ -953,7 +990,7 @@ static uint64_t uv__read_proc_meminfo(const char* what) {
|
||||
rc = 0;
|
||||
fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
|
||||
|
||||
if (fd == -1)
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -64,45 +65,17 @@ static void uv__inotify_read(uv_loop_t* loop,
|
||||
static void maybe_free_watcher_list(struct watcher_list* w,
|
||||
uv_loop_t* loop);
|
||||
|
||||
static int new_inotify_fd(void) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return UV__ERR(errno);
|
||||
|
||||
fd = uv__inotify_init();
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err == 0)
|
||||
err = uv__nonblock(fd, 1);
|
||||
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
static int init_inotify(uv_loop_t* loop) {
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
if (loop->inotify_fd != -1)
|
||||
return 0;
|
||||
|
||||
err = new_inotify_fd();
|
||||
if (err < 0)
|
||||
return err;
|
||||
fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
loop->inotify_fd = err;
|
||||
loop->inotify_fd = fd;
|
||||
uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
|
||||
uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
|
||||
|
||||
@@ -186,7 +159,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
|
||||
/* No watchers left for this path. Clean up. */
|
||||
RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
|
||||
uv__inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
inotify_rm_watch(loop->inotify_fd, w->wd);
|
||||
uv__free(w);
|
||||
}
|
||||
}
|
||||
@@ -194,7 +167,7 @@ static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
|
||||
static void uv__inotify_read(uv_loop_t* loop,
|
||||
uv__io_t* dummy,
|
||||
unsigned int events) {
|
||||
const struct uv__inotify_event* e;
|
||||
const struct inotify_event* e;
|
||||
struct watcher_list* w;
|
||||
uv_fs_event_t* h;
|
||||
QUEUE queue;
|
||||
@@ -219,12 +192,12 @@ static void uv__inotify_read(uv_loop_t* loop,
|
||||
|
||||
/* Now we have one or more inotify_event structs. */
|
||||
for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
|
||||
e = (const struct uv__inotify_event*)p;
|
||||
e = (const struct inotify_event*) p;
|
||||
|
||||
events = 0;
|
||||
if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
if (e->mask & (IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_CHANGE;
|
||||
if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
|
||||
if (e->mask & ~(IN_ATTRIB|IN_MODIFY))
|
||||
events |= UV_RENAME;
|
||||
|
||||
w = find_watcher(loop, e->wd);
|
||||
@@ -290,16 +263,16 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
events = UV__IN_ATTRIB
|
||||
| UV__IN_CREATE
|
||||
| UV__IN_MODIFY
|
||||
| UV__IN_DELETE
|
||||
| UV__IN_DELETE_SELF
|
||||
| UV__IN_MOVE_SELF
|
||||
| UV__IN_MOVED_FROM
|
||||
| UV__IN_MOVED_TO;
|
||||
events = IN_ATTRIB
|
||||
| IN_CREATE
|
||||
| IN_MODIFY
|
||||
| IN_DELETE
|
||||
| IN_DELETE_SELF
|
||||
| IN_MOVE_SELF
|
||||
| IN_MOVED_FROM
|
||||
| IN_MOVED_TO;
|
||||
|
||||
wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
wd = inotify_add_watch(handle->loop->inotify_fd, path, events);
|
||||
if (wd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
|
||||
@@ -26,19 +26,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__has_feature)
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# define MSAN_ACTIVE 1
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__i386__)
|
||||
# ifndef __NR_socketcall
|
||||
# define __NR_socketcall 102
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__arm__)
|
||||
# if defined(__thumb__) || defined(__ARM_EABI__)
|
||||
# define UV_SYSCALL_BASE 0
|
||||
@@ -47,86 +34,6 @@
|
||||
# endif
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifndef __NR_accept4
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_accept4 288
|
||||
# elif defined(__i386__)
|
||||
/* Nothing. Handled through socketcall(). */
|
||||
# elif defined(__arm__)
|
||||
# define __NR_accept4 (UV_SYSCALL_BASE + 366)
|
||||
# endif
|
||||
#endif /* __NR_accept4 */
|
||||
|
||||
#ifndef __NR_eventfd
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd 284
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd 323
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd (UV_SYSCALL_BASE + 351)
|
||||
# endif
|
||||
#endif /* __NR_eventfd */
|
||||
|
||||
#ifndef __NR_eventfd2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_eventfd2 290
|
||||
# elif defined(__i386__)
|
||||
# define __NR_eventfd2 328
|
||||
# elif defined(__arm__)
|
||||
# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
|
||||
# endif
|
||||
#endif /* __NR_eventfd2 */
|
||||
|
||||
#ifndef __NR_inotify_init
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init 253
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init 291
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init */
|
||||
|
||||
#ifndef __NR_inotify_init1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init1 294
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_init1 332
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
|
||||
# endif
|
||||
#endif /* __NR_inotify_init1 */
|
||||
|
||||
#ifndef __NR_inotify_add_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_add_watch 254
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_add_watch 292
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
|
||||
# endif
|
||||
#endif /* __NR_inotify_add_watch */
|
||||
|
||||
#ifndef __NR_inotify_rm_watch
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_rm_watch 255
|
||||
# elif defined(__i386__)
|
||||
# define __NR_inotify_rm_watch 293
|
||||
# elif defined(__arm__)
|
||||
# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
|
||||
# endif
|
||||
#endif /* __NR_inotify_rm_watch */
|
||||
|
||||
#ifndef __NR_pipe2
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_pipe2 293
|
||||
# elif defined(__i386__)
|
||||
# define __NR_pipe2 331
|
||||
# elif defined(__arm__)
|
||||
# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
|
||||
# endif
|
||||
#endif /* __NR_pipe2 */
|
||||
|
||||
#ifndef __NR_recvmmsg
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_recvmmsg 299
|
||||
@@ -203,103 +110,23 @@
|
||||
# endif
|
||||
#endif /* __NR_statx */
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
|
||||
#if defined(__i386__)
|
||||
unsigned long args[4];
|
||||
int r;
|
||||
|
||||
args[0] = (unsigned long) fd;
|
||||
args[1] = (unsigned long) addr;
|
||||
args[2] = (unsigned long) addrlen;
|
||||
args[3] = (unsigned long) flags;
|
||||
|
||||
r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
|
||||
|
||||
/* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
|
||||
* a bad flags argument. Try to distinguish between the two cases.
|
||||
*/
|
||||
if (r == -1)
|
||||
if (errno == EINVAL)
|
||||
if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
|
||||
errno = ENOSYS;
|
||||
|
||||
return r;
|
||||
#elif defined(__NR_accept4)
|
||||
return syscall(__NR_accept4, fd, addr, addrlen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__eventfd(unsigned int count) {
|
||||
#if defined(__NR_eventfd)
|
||||
return syscall(__NR_eventfd, count);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__eventfd2(unsigned int count, int flags) {
|
||||
#if defined(__NR_eventfd2)
|
||||
return syscall(__NR_eventfd2, count, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init(void) {
|
||||
#if defined(__NR_inotify_init)
|
||||
return syscall(__NR_inotify_init);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init1(int flags) {
|
||||
#if defined(__NR_inotify_init1)
|
||||
return syscall(__NR_inotify_init1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
|
||||
#if defined(__NR_inotify_add_watch)
|
||||
return syscall(__NR_inotify_add_watch, fd, path, mask);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd) {
|
||||
#if defined(__NR_inotify_rm_watch)
|
||||
return syscall(__NR_inotify_rm_watch, fd, wd);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__pipe2(int pipefd[2], int flags) {
|
||||
#if defined(__NR_pipe2)
|
||||
int result;
|
||||
result = syscall(__NR_pipe2, pipefd, flags);
|
||||
#if MSAN_ACTIVE
|
||||
if (!result)
|
||||
__msan_unpoison(pipefd, sizeof(int[2]));
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
#ifndef __NR_getrandom
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_getrandom 318
|
||||
# elif defined(__i386__)
|
||||
# define __NR_getrandom 355
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_getrandom 384
|
||||
# elif defined(__arm__)
|
||||
# define __NR_getrandom (UV_SYSCALL_BASE + 384)
|
||||
# elif defined(__ppc__)
|
||||
# define __NR_getrandom 359
|
||||
# elif defined(__s390__)
|
||||
# define __NR_getrandom 349
|
||||
# endif
|
||||
#endif /* __NR_getrandom */
|
||||
|
||||
struct uv__mmsghdr;
|
||||
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
@@ -367,3 +194,12 @@ int uv__statx(int dirfd,
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags) {
|
||||
#if defined(__NR_getrandom)
|
||||
return syscall(__NR_getrandom, buf, buflen, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -31,55 +31,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_CLOEXEC 0x200000
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_CLOEXEC 0x400000
|
||||
#else
|
||||
# define UV__O_CLOEXEC 0x80000
|
||||
#endif
|
||||
|
||||
#if defined(__alpha__)
|
||||
# define UV__O_NONBLOCK 0x4
|
||||
#elif defined(__hppa__)
|
||||
# define UV__O_NONBLOCK O_NONBLOCK
|
||||
#elif defined(__mips__)
|
||||
# define UV__O_NONBLOCK 0x80
|
||||
#elif defined(__sparc__)
|
||||
# define UV__O_NONBLOCK 0x4000
|
||||
#else
|
||||
# define UV__O_NONBLOCK 0x800
|
||||
#endif
|
||||
|
||||
#define UV__EFD_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EFD_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__IN_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__IN_NONBLOCK UV__O_NONBLOCK
|
||||
|
||||
#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
|
||||
#if defined(SOCK_NONBLOCK)
|
||||
# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
|
||||
#else
|
||||
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/* inotify flags */
|
||||
#define UV__IN_ACCESS 0x001
|
||||
#define UV__IN_MODIFY 0x002
|
||||
#define UV__IN_ATTRIB 0x004
|
||||
#define UV__IN_CLOSE_WRITE 0x008
|
||||
#define UV__IN_CLOSE_NOWRITE 0x010
|
||||
#define UV__IN_OPEN 0x020
|
||||
#define UV__IN_MOVED_FROM 0x040
|
||||
#define UV__IN_MOVED_TO 0x080
|
||||
#define UV__IN_CREATE 0x100
|
||||
#define UV__IN_DELETE 0x200
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
struct uv__statx_timestamp {
|
||||
int64_t tv_sec;
|
||||
uint32_t tv_nsec;
|
||||
@@ -110,36 +61,6 @@ struct uv__statx {
|
||||
uint64_t unused1[14];
|
||||
};
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
uint32_t mask;
|
||||
uint32_t cookie;
|
||||
uint32_t len;
|
||||
/* char name[0]; */
|
||||
};
|
||||
|
||||
struct uv__mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
|
||||
int uv__eventfd(unsigned int count);
|
||||
int uv__eventfd2(unsigned int count, int flags);
|
||||
int uv__inotify_init(void);
|
||||
int uv__inotify_init1(int flags);
|
||||
int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
|
||||
int uv__inotify_rm_watch(int fd, int32_t wd);
|
||||
int uv__pipe2(int pipefd[2], int flags);
|
||||
int uv__recvmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags,
|
||||
struct timespec* timeout);
|
||||
int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned 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);
|
||||
@@ -148,5 +69,6 @@ int uv__statx(int dirfd,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf);
|
||||
ssize_t uv__getrandom(void* buf, size_t buflen, unsigned flags);
|
||||
|
||||
#endif /* UV_LINUX_SYSCALL_H_ */
|
||||
|
||||
@@ -55,7 +55,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) == -1) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
@@ -102,7 +102,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
@@ -119,7 +119,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
#endif
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -167,7 +167,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -235,13 +235,25 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv__random_sysctl(void* buf, size_t len) {
|
||||
static int name[] = {CTL_KERN, KERN_ARND};
|
||||
size_t count, req;
|
||||
unsigned char* p;
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
p = buf;
|
||||
while (len) {
|
||||
req = len < 32 ? len : 32;
|
||||
count = req;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
if (sysctl(name, ARRAY_SIZE(name), p, &count, NULL, 0) == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (count != req)
|
||||
return UV_EIO; /* Can't happen. */
|
||||
|
||||
p += count;
|
||||
len -= count;
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void uv_loadavg(double avg[3]) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_LOADAVG};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0) < 0) return;
|
||||
|
||||
avg[0] = (double) info.ldavg[0] / info.fscale;
|
||||
avg[1] = (double) info.ldavg[1] / info.fscale;
|
||||
@@ -61,7 +61,6 @@ void uv_loadavg(double avg[3]) {
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
int mib[4];
|
||||
char **argsbuf = NULL;
|
||||
char **argsbuf_tmp;
|
||||
size_t argsbuf_size = 100U;
|
||||
size_t exepath_size;
|
||||
pid_t mypid;
|
||||
@@ -73,15 +72,14 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
mypid = getpid();
|
||||
for (;;) {
|
||||
err = UV_ENOMEM;
|
||||
argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
|
||||
if (argsbuf_tmp == NULL)
|
||||
argsbuf = uv__reallocf(argsbuf, argsbuf_size);
|
||||
if (argsbuf == NULL)
|
||||
goto out;
|
||||
argsbuf = argsbuf_tmp;
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC_ARGS;
|
||||
mib[2] = mypid;
|
||||
mib[3] = KERN_PROC_ARGV;
|
||||
if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), argsbuf, &argsbuf_size, NULL, 0) == 0) {
|
||||
break;
|
||||
}
|
||||
if (errno != ENOMEM) {
|
||||
@@ -117,7 +115,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
size_t size = sizeof(info);
|
||||
int which[] = {CTL_VM, VM_UVMEXP};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
|
||||
@@ -129,7 +127,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
int which[] = {CTL_HW, HW_PHYSMEM64};
|
||||
size_t size = sizeof(info);
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return (uint64_t) info;
|
||||
@@ -154,7 +152,7 @@ int uv_resident_set_memory(size_t* rss) {
|
||||
mib[4] = sizeof(struct kinfo_proc);
|
||||
mib[5] = 1;
|
||||
|
||||
if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
|
||||
if (sysctl(mib, ARRAY_SIZE(mib), &kinfo, &size, NULL, 0) < 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*rss = kinfo.p_vm_rssize * page_size;
|
||||
@@ -168,7 +166,7 @@ int uv_uptime(double* uptime) {
|
||||
size_t size = sizeof(info);
|
||||
static int which[] = {CTL_KERN, KERN_BOOTTIME};
|
||||
|
||||
if (sysctl(which, 2, &info, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &info, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
now = time(NULL);
|
||||
@@ -184,43 +182,38 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
uint64_t info[CPUSTATES];
|
||||
char model[512];
|
||||
int numcpus = 1;
|
||||
int which[] = {CTL_HW,HW_MODEL,0};
|
||||
int which[] = {CTL_HW,HW_MODEL};
|
||||
int percpu[] = {CTL_KERN,KERN_CPTIME2,0};
|
||||
size_t size;
|
||||
int i;
|
||||
int i, j;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
size = sizeof(model);
|
||||
if (sysctl(which, 2, &model, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &model, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
which[1] = HW_NCPU;
|
||||
which[1] = HW_NCPUONLINE;
|
||||
size = sizeof(numcpus);
|
||||
if (sysctl(which, 2, &numcpus, &size, NULL, 0))
|
||||
if (sysctl(which, ARRAY_SIZE(which), &numcpus, &size, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
|
||||
if (!(*cpu_infos))
|
||||
return UV_ENOMEM;
|
||||
|
||||
i = 0;
|
||||
*count = numcpus;
|
||||
|
||||
which[1] = HW_CPUSPEED;
|
||||
size = sizeof(cpuspeed);
|
||||
if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
if (sysctl(which, ARRAY_SIZE(which), &cpuspeed, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
size = sizeof(info);
|
||||
which[0] = CTL_KERN;
|
||||
which[1] = KERN_CPTIME2;
|
||||
for (i = 0; i < numcpus; i++) {
|
||||
which[2] = i;
|
||||
size = sizeof(info);
|
||||
if (sysctl(which, 3, &info, &size, NULL, 0)) {
|
||||
uv__free(*cpu_infos);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
percpu[2] = i;
|
||||
if (sysctl(percpu, ARRAY_SIZE(percpu), &info, &size, NULL, 0))
|
||||
goto error;
|
||||
|
||||
cpu_info = &(*cpu_infos)[i];
|
||||
|
||||
@@ -235,15 +228,13 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
|
||||
error:
|
||||
*count = 0;
|
||||
for (j = 0; j < i; j++)
|
||||
uv__free((*cpu_infos)[j].model);
|
||||
|
||||
uv__free(*cpu_infos);
|
||||
*cpu_infos = NULL;
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
#include "os390-syscalls.h"
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <search.h>
|
||||
#include <termios.h>
|
||||
#include <sys/msg.h>
|
||||
|
||||
#define CW_INTRPT 1
|
||||
#define CW_CONDVAR 32
|
||||
|
||||
#pragma linkage(BPX4CTW, OS)
|
||||
@@ -43,6 +43,7 @@ int scandir(const char* maindir, struct dirent*** namelist,
|
||||
int (*compar)(const struct dirent**,
|
||||
const struct dirent **)) {
|
||||
struct dirent** nl;
|
||||
struct dirent** nl_copy;
|
||||
struct dirent* dirent;
|
||||
unsigned count;
|
||||
size_t allocated;
|
||||
@@ -62,19 +63,17 @@ int scandir(const char* maindir, struct dirent*** namelist,
|
||||
if (!filter || filter(dirent)) {
|
||||
struct dirent* copy;
|
||||
copy = uv__malloc(sizeof(*copy));
|
||||
if (!copy) {
|
||||
while (count) {
|
||||
dirent = nl[--count];
|
||||
uv__free(dirent);
|
||||
}
|
||||
uv__free(nl);
|
||||
closedir(mdir);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (!copy)
|
||||
goto error;
|
||||
memcpy(copy, dirent, sizeof(*copy));
|
||||
|
||||
nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
|
||||
nl_copy = uv__realloc(nl, sizeof(*copy) * (count + 1));
|
||||
if (nl_copy == NULL) {
|
||||
uv__free(copy);
|
||||
goto error;
|
||||
}
|
||||
|
||||
nl = nl_copy;
|
||||
nl[count++] = copy;
|
||||
}
|
||||
}
|
||||
@@ -86,6 +85,16 @@ int scandir(const char* maindir, struct dirent*** namelist,
|
||||
|
||||
*namelist = nl;
|
||||
return count;
|
||||
|
||||
error:
|
||||
while (count > 0) {
|
||||
dirent = nl[--count];
|
||||
uv__free(dirent);
|
||||
}
|
||||
uv__free(nl);
|
||||
closedir(mdir);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +128,7 @@ static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
|
||||
}
|
||||
|
||||
newsize = next_power_of_two(len);
|
||||
newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
|
||||
newlst = uv__reallocf(lst->items, newsize * sizeof(lst->items[0]));
|
||||
|
||||
if (newlst == NULL)
|
||||
abort();
|
||||
@@ -269,6 +278,8 @@ int epoll_ctl(uv__os390_epoll* lst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define EP_MAX_PFDS (ULONG_MAX / sizeof(struct pollfd))
|
||||
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
|
||||
|
||||
int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
int maxevents, int timeout) {
|
||||
@@ -277,18 +288,41 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
int pollret;
|
||||
int reventcount;
|
||||
int nevents;
|
||||
struct pollfd msg_fd;
|
||||
int i;
|
||||
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
if (!lst || !lst->items || !events) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lst->size > EP_MAX_PFDS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lst->size > 0)
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
else
|
||||
_SET_FDS_MSGS(size, 0, 0);
|
||||
pfds = lst->items;
|
||||
pollret = poll(pfds, size, timeout);
|
||||
if (pollret <= 0)
|
||||
return pollret;
|
||||
|
||||
assert(lst->size > 0);
|
||||
|
||||
pollret = _NFDS(pollret) + _NMSGS(pollret);
|
||||
|
||||
reventcount = 0;
|
||||
nevents = 0;
|
||||
for (int i = 0;
|
||||
msg_fd = pfds[lst->size - 1];
|
||||
for (i = 0;
|
||||
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
|
||||
struct epoll_event ev;
|
||||
struct pollfd* pfd;
|
||||
@@ -299,6 +333,7 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
|
||||
ev.fd = pfd->fd;
|
||||
ev.events = pfd->revents;
|
||||
ev.is_msg = 0;
|
||||
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
|
||||
reventcount += 2;
|
||||
else if (pfd->revents & (POLLIN | POLLOUT))
|
||||
@@ -308,6 +343,10 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
events[nevents++] = ev;
|
||||
}
|
||||
|
||||
if (msg_fd.revents != 0 && msg_fd.fd != -1)
|
||||
if (i == lst->size)
|
||||
events[nevents - 1].is_msg = 1;
|
||||
|
||||
return nevents;
|
||||
}
|
||||
|
||||
@@ -350,27 +389,36 @@ int nanosleep(const struct timespec* req, struct timespec* rem) {
|
||||
unsigned secrem;
|
||||
unsigned nanorem;
|
||||
int rv;
|
||||
int rc;
|
||||
int err;
|
||||
int rsn;
|
||||
|
||||
nano = (int)req->tv_nsec;
|
||||
seconds = req->tv_sec;
|
||||
events = CW_CONDVAR;
|
||||
events = CW_CONDVAR | CW_INTRPT;
|
||||
secrem = 0;
|
||||
nanorem = 0;
|
||||
|
||||
#if defined(_LP64)
|
||||
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
|
||||
BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
|
||||
#else
|
||||
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
|
||||
BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &err, &rsn);
|
||||
#endif
|
||||
|
||||
assert(rv == -1 && errno == EAGAIN);
|
||||
/* Don't clobber errno unless BPX1CTW/BPX4CTW errored.
|
||||
* Don't leak EAGAIN, that just means the timeout expired.
|
||||
*/
|
||||
if (rv == -1)
|
||||
if (err == EAGAIN)
|
||||
rv = 0;
|
||||
else
|
||||
errno = err;
|
||||
|
||||
if(rem != NULL) {
|
||||
if (rem != NULL && (rv == 0 || err == EINTR)) {
|
||||
rem->tv_nsec = nanorem;
|
||||
rem->tv_sec = secrem;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -510,3 +558,28 @@ size_t strnlen(const char* str, size_t maxlen) {
|
||||
else
|
||||
return p - str;
|
||||
}
|
||||
|
||||
|
||||
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_destroy(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_post(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_trywait(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
int sem_wait(UV_PLATFORM_SEM_T* semid) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
struct epoll_event {
|
||||
int events;
|
||||
int fd;
|
||||
int is_msg;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -64,5 +65,10 @@ int scandir(const char* maindir, struct dirent*** namelist,
|
||||
char *mkdtemp(char* path);
|
||||
ssize_t os390_readlink(const char* path, char* buf, size_t len);
|
||||
size_t strnlen(const char* str, size_t maxlen);
|
||||
int sem_init(UV_PLATFORM_SEM_T* semid, int pshared, unsigned int value);
|
||||
int sem_destroy(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_post(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_trywait(UV_PLATFORM_SEM_T* semid);
|
||||
int sem_wait(UV_PLATFORM_SEM_T* semid);
|
||||
|
||||
#endif /* UV_OS390_SYSCALL_H_ */
|
||||
|
||||
@@ -433,13 +433,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
for (int i = 0; i < count; ++i)
|
||||
uv__free(cpu_infos[i].model);
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
uv_interface_address_t* address;
|
||||
@@ -930,7 +923,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
continue;
|
||||
|
||||
ep = loop->ep;
|
||||
if (fd == ep->msg_queue) {
|
||||
if (pe->is_msg) {
|
||||
os390_message_queue_handler(ep);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -93,8 +93,12 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
if (uv__stream_fd(handle) == -1)
|
||||
return UV_EINVAL;
|
||||
|
||||
#if defined(__MVS__)
|
||||
if (handle->ipc)
|
||||
return UV_EINVAL;
|
||||
|
||||
#if defined(__MVS__) || defined(__PASE__)
|
||||
/* On zOS, backlog=0 has undefined behaviour */
|
||||
/* On IBMi PASE, backlog=0 leads to "Connection refused" error */
|
||||
if (backlog == 0)
|
||||
backlog = 1;
|
||||
else if (backlog < 0)
|
||||
@@ -259,7 +263,7 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
addrlen = strlen(sa.sun_path);
|
||||
|
||||
|
||||
if (addrlen >= *size) {
|
||||
if ((size_t)addrlen >= *size) {
|
||||
*size = addrlen + 1;
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
|
||||
return;
|
||||
|
||||
n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
|
||||
p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds));
|
||||
p = uv__reallocf(loop->poll_fds, n * sizeof(*loop->poll_fds));
|
||||
if (p == NULL)
|
||||
abort();
|
||||
|
||||
|
||||
@@ -123,72 +123,64 @@ static void uv__chld(uv_signal_t* handle, int signum) {
|
||||
}
|
||||
|
||||
|
||||
int uv__make_socketpair(int fds[2], int flags) {
|
||||
#if defined(__linux__)
|
||||
static int no_cloexec;
|
||||
|
||||
if (no_cloexec)
|
||||
goto skip;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
|
||||
return 0;
|
||||
|
||||
/* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
|
||||
* Anything else is a genuine error.
|
||||
*/
|
||||
if (errno != EINVAL)
|
||||
static int uv__make_socketpair(int fds[2]) {
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_cloexec = 1;
|
||||
|
||||
skip:
|
||||
#endif
|
||||
return 0;
|
||||
#else
|
||||
int err;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__cloexec(fds[0], 1);
|
||||
uv__cloexec(fds[1], 1);
|
||||
err = uv__cloexec(fds[0], 1);
|
||||
if (err == 0)
|
||||
err = uv__cloexec(fds[1], 1);
|
||||
|
||||
if (flags & UV__F_NONBLOCK) {
|
||||
uv__nonblock(fds[0], 1);
|
||||
uv__nonblock(fds[1], 1);
|
||||
if (err != 0) {
|
||||
uv__close(fds[0]);
|
||||
uv__close(fds[1]);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__make_pipe(int fds[2], int flags) {
|
||||
#if defined(__linux__)
|
||||
static int no_pipe2;
|
||||
|
||||
if (no_pipe2)
|
||||
goto skip;
|
||||
|
||||
if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
|
||||
return 0;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
#if defined(__FreeBSD__) || defined(__linux__)
|
||||
if (pipe2(fds, flags | O_CLOEXEC))
|
||||
return UV__ERR(errno);
|
||||
|
||||
no_pipe2 = 1;
|
||||
|
||||
skip:
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (pipe(fds))
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__cloexec(fds[0], 1);
|
||||
uv__cloexec(fds[1], 1);
|
||||
if (uv__cloexec(fds[0], 1))
|
||||
goto fail;
|
||||
|
||||
if (uv__cloexec(fds[1], 1))
|
||||
goto fail;
|
||||
|
||||
if (flags & UV__F_NONBLOCK) {
|
||||
uv__nonblock(fds[0], 1);
|
||||
uv__nonblock(fds[1], 1);
|
||||
if (uv__nonblock(fds[0], 1))
|
||||
goto fail;
|
||||
|
||||
if (uv__nonblock(fds[1], 1))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
uv__close(fds[0]);
|
||||
uv__close(fds[1]);
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -211,7 +203,7 @@ static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
|
||||
if (container->data.stream->type != UV_NAMED_PIPE)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
return uv__make_socketpair(fds, 0);
|
||||
return uv__make_socketpair(fds);
|
||||
|
||||
case UV_INHERIT_FD:
|
||||
case UV_INHERIT_STREAM:
|
||||
@@ -260,7 +252,7 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
|
||||
|
||||
static void uv__process_close_stream(uv_stdio_container_t* container) {
|
||||
if (!(container->flags & UV_CREATE_PIPE)) return;
|
||||
uv__stream_close((uv_stream_t*)container->data.stream);
|
||||
uv__stream_close(container->data.stream);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,28 +24,27 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void uv__set_process_title_platform_init(void);
|
||||
struct uv__process_title {
|
||||
char* str;
|
||||
size_t len; /* Length of the current process title. */
|
||||
size_t cap; /* Maximum capacity. Computed once in uv_setup_args(). */
|
||||
};
|
||||
|
||||
extern void uv__set_process_title(const char* title);
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static struct uv__process_title process_title;
|
||||
static void* args_mem;
|
||||
|
||||
static struct {
|
||||
char* str;
|
||||
size_t len;
|
||||
} process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
#ifdef __APPLE__
|
||||
uv__set_process_title_platform_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
struct uv__process_title pt;
|
||||
char** new_argv;
|
||||
size_t size;
|
||||
char* s;
|
||||
@@ -54,20 +53,14 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
if (argc <= 0)
|
||||
return argv;
|
||||
|
||||
/* Calculate how much memory we need for the argv strings. */
|
||||
size = 0;
|
||||
for (i = 0; i < argc; i++)
|
||||
size += strlen(argv[i]) + 1;
|
||||
pt.str = argv[0];
|
||||
pt.len = strlen(argv[0]);
|
||||
pt.cap = pt.len + 1;
|
||||
|
||||
#if defined(__MVS__)
|
||||
/* argv is not adjacent. So just use argv[0] */
|
||||
process_title.str = argv[0];
|
||||
process_title.len = strlen(argv[0]);
|
||||
#else
|
||||
process_title.str = argv[0];
|
||||
process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
|
||||
assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
|
||||
#endif
|
||||
/* Calculate how much memory we need for the argv strings. */
|
||||
size = pt.cap;
|
||||
for (i = 1; i < argc; i++)
|
||||
size += strlen(argv[i]) + 1;
|
||||
|
||||
/* Add space for the argv pointers. */
|
||||
size += (argc + 1) * sizeof(char*);
|
||||
@@ -75,32 +68,54 @@ char** uv_setup_args(int argc, char** argv) {
|
||||
new_argv = uv__malloc(size);
|
||||
if (new_argv == NULL)
|
||||
return argv;
|
||||
args_mem = new_argv;
|
||||
|
||||
/* Copy over the strings and set up the pointer table. */
|
||||
i = 0;
|
||||
s = (char*) &new_argv[argc + 1];
|
||||
for (i = 0; i < argc; i++) {
|
||||
size = pt.cap;
|
||||
goto loop;
|
||||
|
||||
for (/* empty */; i < argc; i++) {
|
||||
size = strlen(argv[i]) + 1;
|
||||
loop:
|
||||
memcpy(s, argv[i], size);
|
||||
new_argv[i] = s;
|
||||
s += size;
|
||||
}
|
||||
new_argv[i] = NULL;
|
||||
|
||||
/* argv is not adjacent on z/os, we use just argv[0] on that platform. */
|
||||
#ifndef __MVS__
|
||||
pt.cap = argv[i - 1] + size - argv[0];
|
||||
#endif
|
||||
|
||||
args_mem = new_argv;
|
||||
process_title = pt;
|
||||
|
||||
return new_argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
struct uv__process_title* pt;
|
||||
size_t len;
|
||||
|
||||
pt = &process_title;
|
||||
len = strlen(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title.len != 0) {
|
||||
/* No need to terminate, byte after is always '\0'. */
|
||||
strncpy(process_title.str, title, process_title.len);
|
||||
uv__set_process_title(title);
|
||||
if (len >= pt->cap) {
|
||||
len = 0;
|
||||
if (pt->cap > 0)
|
||||
len = pt->cap - 1;
|
||||
}
|
||||
|
||||
memcpy(pt->str, title, len);
|
||||
memset(pt->str + len, '\0', pt->cap - len);
|
||||
pt->len = len;
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Copyright libuv 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/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static int status;
|
||||
|
||||
|
||||
int uv__random_readpath(const char* path, void* buf, size_t buflen) {
|
||||
struct stat s;
|
||||
size_t pos;
|
||||
ssize_t n;
|
||||
int fd;
|
||||
|
||||
fd = uv__open_cloexec(path, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
if (fstat(fd, &s)) {
|
||||
uv__close(fd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (!S_ISCHR(s.st_mode)) {
|
||||
uv__close(fd);
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
for (pos = 0; pos != buflen; pos += n) {
|
||||
do
|
||||
n = read(fd, (char*) buf + pos, buflen - pos);
|
||||
while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1) {
|
||||
uv__close(fd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
uv__close(fd);
|
||||
return UV_EIO;
|
||||
}
|
||||
}
|
||||
|
||||
uv__close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__random_devurandom_init(void) {
|
||||
char c;
|
||||
|
||||
/* Linux's random(4) man page suggests applications should read at least
|
||||
* once from /dev/random before switching to /dev/urandom in order to seed
|
||||
* the system RNG. Reads from /dev/random can of course block indefinitely
|
||||
* until entropy is available but that's the point.
|
||||
*/
|
||||
status = uv__random_readpath("/dev/random", &c, 1);
|
||||
}
|
||||
|
||||
|
||||
int uv__random_devurandom(void* buf, size_t buflen) {
|
||||
uv_once(&once, uv__random_devurandom_init);
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
return uv__random_readpath("/dev/urandom", buf, buflen);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright libuv 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 <stddef.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef int (*uv__getentropy_cb)(void *, size_t);
|
||||
|
||||
static uv__getentropy_cb uv__getentropy;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
|
||||
static void uv__random_getentropy_init(void) {
|
||||
uv__getentropy = (uv__getentropy_cb) dlsym(RTLD_DEFAULT, "getentropy");
|
||||
}
|
||||
|
||||
|
||||
int uv__random_getentropy(void* buf, size_t buflen) {
|
||||
size_t pos;
|
||||
size_t stride;
|
||||
|
||||
uv_once(&once, uv__random_getentropy_init);
|
||||
|
||||
if (uv__getentropy == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
/* getentropy() returns an error for requests > 256 bytes. */
|
||||
for (pos = 0, stride = 256; pos + stride < buflen; pos += stride)
|
||||
if (uv__getentropy((char *) buf + pos, stride))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (uv__getentropy((char *) buf + pos, buflen - pos))
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* Copyright libuv 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"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include "linux-syscalls.h"
|
||||
|
||||
#define uv__random_getrandom_init() 0
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef ssize_t (*uv__getrandom_cb)(void *, size_t, unsigned);
|
||||
|
||||
static uv__getrandom_cb uv__getrandom;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
static void uv__random_getrandom_init_once(void) {
|
||||
uv__getrandom = (uv__getrandom_cb) dlsym(RTLD_DEFAULT, "getrandom");
|
||||
}
|
||||
|
||||
static int uv__random_getrandom_init(void) {
|
||||
uv_once(&once, uv__random_getrandom_init_once);
|
||||
|
||||
if (uv__getrandom == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* !__linux__ */
|
||||
|
||||
int uv__random_getrandom(void* buf, size_t buflen) {
|
||||
ssize_t n;
|
||||
size_t pos;
|
||||
int rc;
|
||||
|
||||
rc = uv__random_getrandom_init();
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
for (pos = 0; pos != buflen; pos += n) {
|
||||
do {
|
||||
n = buflen - pos;
|
||||
|
||||
/* Most getrandom() implementations promise that reads <= 256 bytes
|
||||
* will always succeed and won't be interrupted by signals.
|
||||
* It's therefore useful to split it up in smaller reads because
|
||||
* one big read may, in theory, continuously fail with EINTR.
|
||||
*/
|
||||
if (n > 256)
|
||||
n = 256;
|
||||
|
||||
n = uv__getrandom((char *) buf + pos, n, 0);
|
||||
} while (n == -1 && errno == EINTR);
|
||||
|
||||
if (n == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (n == 0)
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Copyright libuv 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 <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
struct uv__sysctl_args {
|
||||
int* name;
|
||||
int nlen;
|
||||
void* oldval;
|
||||
size_t* oldlenp;
|
||||
void* newval;
|
||||
size_t newlen;
|
||||
unsigned long unused[4];
|
||||
};
|
||||
|
||||
|
||||
int uv__random_sysctl(void* buf, size_t buflen) {
|
||||
static int name[] = {1 /*CTL_KERN*/, 40 /*KERN_RANDOM*/, 6 /*RANDOM_UUID*/};
|
||||
struct uv__sysctl_args args;
|
||||
char uuid[16];
|
||||
char* p;
|
||||
char* pe;
|
||||
size_t n;
|
||||
|
||||
p = buf;
|
||||
pe = p + buflen;
|
||||
|
||||
while (p < pe) {
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
args.name = name;
|
||||
args.nlen = ARRAY_SIZE(name);
|
||||
args.oldval = uuid;
|
||||
args.oldlenp = &n;
|
||||
n = sizeof(uuid);
|
||||
|
||||
/* Emits a deprecation warning with some kernels but that seems like
|
||||
* an okay trade-off for the fallback of the fallback: this function is
|
||||
* only called when neither getrandom(2) nor /dev/urandom are available.
|
||||
* Fails with ENOSYS on kernels configured without CONFIG_SYSCTL_SYSCALL.
|
||||
* At least arm64 never had a _sysctl system call and therefore doesn't
|
||||
* have a SYS__sysctl define either.
|
||||
*/
|
||||
#ifdef SYS__sysctl
|
||||
if (syscall(SYS__sysctl, &args) == -1)
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
{
|
||||
(void) &args;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (n != sizeof(uuid))
|
||||
return UV_EIO; /* Can't happen. */
|
||||
|
||||
/* uuid[] is now a type 4 UUID. Bytes 6 and 8 (counting from zero) contain
|
||||
* 4 and 5 bits of entropy, respectively. For ease of use, we skip those
|
||||
* and only use 14 of the 16 bytes.
|
||||
*/
|
||||
uuid[6] = uuid[14];
|
||||
uuid[8] = uuid[15];
|
||||
|
||||
n = pe - p;
|
||||
if (n > 14)
|
||||
n = 14;
|
||||
|
||||
memcpy(p, uuid, n);
|
||||
p += n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -331,16 +331,7 @@ int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
|
||||
|
||||
void uv__signal_close(uv_signal_t* handle) {
|
||||
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If there are any caught signals "trapped" in the signal pipe, we can't
|
||||
* call the close callback yet. Otherwise, add the handle to the finish_close
|
||||
* queue.
|
||||
*/
|
||||
if (handle->caught_signals == handle->dispatched_signals) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,7 +366,7 @@ static int uv__signal_start(uv_signal_t* handle,
|
||||
|
||||
/* 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
|
||||
* Additionally, this avoids pending signals getting lost in the small
|
||||
* time frame that handle->signum == 0.
|
||||
*/
|
||||
if (signum == handle->signum) {
|
||||
@@ -472,15 +463,6 @@ static void uv__signal_event(uv_loop_t* loop,
|
||||
|
||||
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_HANDLE_CLOSING) &&
|
||||
(handle->caught_signals == handle->dispatched_signals)) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
}
|
||||
|
||||
bytes -= end;
|
||||
@@ -563,6 +545,7 @@ static void uv__signal_stop(uv_signal_t* handle) {
|
||||
if (first_oneshot && !rem_oneshot) {
|
||||
ret = uv__signal_register_handler(handle->signum, 1);
|
||||
assert(ret == 0);
|
||||
(void)ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1000,12 +1000,12 @@ 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_HANDLE_READ_EOF;
|
||||
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);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
stream->read_cb(stream, UV_EOF, buf);
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
}
|
||||
|
||||
|
||||
@@ -1048,7 +1048,12 @@ static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
|
||||
}
|
||||
|
||||
|
||||
#define UV__CMSG_FD_COUNT 64
|
||||
#if defined(__PASE__)
|
||||
/* on IBMi PASE the control message length can not exceed 256. */
|
||||
# define UV__CMSG_FD_COUNT 60
|
||||
#else
|
||||
# define UV__CMSG_FD_COUNT 64
|
||||
#endif
|
||||
#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
|
||||
|
||||
|
||||
@@ -1403,7 +1408,7 @@ int uv_write2(uv_write_t* req,
|
||||
return UV_EBADF;
|
||||
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return -EPIPE;
|
||||
return UV_EPIPE;
|
||||
|
||||
if (send_handle) {
|
||||
if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
|
||||
@@ -1557,7 +1562,7 @@ int uv_read_start(uv_stream_t* stream,
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!(stream->flags & UV_HANDLE_READABLE))
|
||||
return -ENOTCONN;
|
||||
return UV_ENOTCONN;
|
||||
|
||||
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
|
||||
* expresses the desired state of the user.
|
||||
|
||||
@@ -700,16 +700,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
#ifdef SUNOS_NO_IFADDRS
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
*count = 0;
|
||||
|
||||
@@ -308,6 +308,23 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
int fd;
|
||||
struct linger l = { 1, 0 };
|
||||
|
||||
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
return UV_EINVAL;
|
||||
|
||||
fd = uv__stream_fd(handle);
|
||||
if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
static int single_accept = -1;
|
||||
unsigned long flags;
|
||||
@@ -362,8 +379,16 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
||||
return UV__ERR(errno);
|
||||
|
||||
#ifdef TCP_KEEPIDLE
|
||||
if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
if (on) {
|
||||
int intvl = 1; /* 1 second; same as default on Win32 */
|
||||
int cnt = 10; /* 10 retries; same as hardcoded on Win32 */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
||||
return UV__ERR(errno);
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Solaris/SmartOS, if you don't support keep-alive,
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
|
||||
#endif
|
||||
|
||||
@@ -222,6 +222,12 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
size_t pagesize;
|
||||
size_t stack_size;
|
||||
|
||||
/* Used to squelch a -Wcast-function-type warning. */
|
||||
union {
|
||||
void (*in)(void*);
|
||||
void* (*out)(void*);
|
||||
} f;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
@@ -248,7 +254,8 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
abort();
|
||||
}
|
||||
|
||||
err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
|
||||
f.in = entry;
|
||||
err = pthread_create(tid, attr, f.out, arg);
|
||||
|
||||
if (attr != NULL)
|
||||
pthread_attr_destroy(attr);
|
||||
@@ -474,7 +481,7 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
||||
|
||||
#else /* !(defined(__APPLE__) && defined(__MACH__)) */
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
|
||||
/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674
|
||||
* by providing a custom implementation for glibc < 2.21 in terms of other
|
||||
@@ -510,7 +517,8 @@ typedef struct uv_semaphore_s {
|
||||
unsigned int value;
|
||||
} uv_semaphore_t;
|
||||
|
||||
#if defined(__GLIBC__) || platform_needs_custom_semaphore
|
||||
#if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \
|
||||
platform_needs_custom_semaphore
|
||||
STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*));
|
||||
#endif
|
||||
|
||||
@@ -639,7 +647,7 @@ static int uv__sem_trywait(uv_sem_t* sem) {
|
||||
}
|
||||
|
||||
int uv_sem_init(uv_sem_t* sem, unsigned int value) {
|
||||
#ifdef __GLIBC__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
uv_once(&glibc_version_check_once, glibc_version_check);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,6 +34,34 @@
|
||||
#define IMAXBEL 0
|
||||
#endif
|
||||
|
||||
#if defined(__PASE__)
|
||||
/* On IBM i PASE, for better compatibility with running interactive programs in
|
||||
* a 5250 environment, isatty() will return true for the stdin/stdout/stderr
|
||||
* streams created by QSH/QP2TERM.
|
||||
*
|
||||
* For more, see docs on PASE_STDIO_ISATTY in
|
||||
* https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/apis/pase_environ.htm
|
||||
*
|
||||
* This behavior causes problems for Node as it expects that if isatty() returns
|
||||
* true that TTY ioctls will be supported by that fd (which is not an
|
||||
* unreasonable expectation) and when they don't it crashes with assertion
|
||||
* errors.
|
||||
*
|
||||
* Here, we create our own version of isatty() that uses ioctl() to identify
|
||||
* whether the fd is *really* a TTY or not.
|
||||
*/
|
||||
static int isreallyatty(int file) {
|
||||
int rc;
|
||||
|
||||
rc = !ioctl(file, TXISATTY + 0x81, NULL);
|
||||
if (!rc && errno != EBADF)
|
||||
errno = ENOTTY;
|
||||
|
||||
return rc;
|
||||
}
|
||||
#define isatty(fd) isreallyatty(fd)
|
||||
#endif
|
||||
|
||||
static int orig_termios_fd = -1;
|
||||
static struct termios orig_termios;
|
||||
static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
|
||||
@@ -136,7 +164,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, mode);
|
||||
r = uv__open_cloexec(path, mode | O_NOCTTY);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
@@ -362,3 +390,10 @@ int uv_tty_reset_mode(void) {
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
|
||||
}
|
||||
|
||||
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#endif
|
||||
#include <sys/un.h>
|
||||
|
||||
#define UV__UDP_DGRAM_MAXSIZE (64 * 1024)
|
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
|
||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
@@ -49,6 +51,36 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
int domain,
|
||||
unsigned int flags);
|
||||
|
||||
#if HAVE_MMSG
|
||||
|
||||
#define UV__MMSG_MAXWIDTH 20
|
||||
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf);
|
||||
static void uv__udp_sendmmsg(uv_udp_t* handle);
|
||||
|
||||
static int uv__recvmmsg_avail;
|
||||
static int uv__sendmmsg_avail;
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
|
||||
static void uv__udp_mmsg_init(void) {
|
||||
int ret;
|
||||
int s;
|
||||
s = uv__socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0)
|
||||
return;
|
||||
ret = uv__sendmmsg(s, NULL, 0, 0);
|
||||
if (ret == 0 || errno != ENOSYS) {
|
||||
uv__sendmmsg_avail = 1;
|
||||
uv__recvmmsg_avail = 1;
|
||||
} else {
|
||||
ret = uv__recvmmsg(s, NULL, 0, 0, NULL);
|
||||
if (ret == 0 || errno != ENOSYS)
|
||||
uv__recvmmsg_avail = 1;
|
||||
}
|
||||
uv__close(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void uv__udp_close(uv_udp_t* handle) {
|
||||
uv__io_close(handle->loop, &handle->io_watcher);
|
||||
@@ -148,6 +180,61 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_MMSG
|
||||
static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf) {
|
||||
struct sockaddr_in6 peers[UV__MMSG_MAXWIDTH];
|
||||
struct iovec iov[UV__MMSG_MAXWIDTH];
|
||||
struct uv__mmsghdr msgs[UV__MMSG_MAXWIDTH];
|
||||
ssize_t nread;
|
||||
uv_buf_t chunk_buf;
|
||||
size_t chunks;
|
||||
int flags;
|
||||
size_t k;
|
||||
|
||||
/* prepare structures for recvmmsg */
|
||||
chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
|
||||
if (chunks > ARRAY_SIZE(iov))
|
||||
chunks = ARRAY_SIZE(iov);
|
||||
for (k = 0; k < chunks; ++k) {
|
||||
iov[k].iov_base = buf->base + k * UV__UDP_DGRAM_MAXSIZE;
|
||||
iov[k].iov_len = UV__UDP_DGRAM_MAXSIZE;
|
||||
msgs[k].msg_hdr.msg_iov = iov + k;
|
||||
msgs[k].msg_hdr.msg_iovlen = 1;
|
||||
msgs[k].msg_hdr.msg_name = peers + k;
|
||||
msgs[k].msg_hdr.msg_namelen = sizeof(peers[0]);
|
||||
}
|
||||
|
||||
do
|
||||
nread = uv__recvmmsg(handle->io_watcher.fd, msgs, chunks, 0, NULL);
|
||||
while (nread == -1 && errno == EINTR);
|
||||
|
||||
if (nread < 1) {
|
||||
if (nread == 0 || errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
handle->recv_cb(handle, 0, buf, NULL, 0);
|
||||
else
|
||||
handle->recv_cb(handle, UV__ERR(errno), buf, NULL, 0);
|
||||
} else {
|
||||
/* pass each chunk to the application */
|
||||
for (k = 0; k < (size_t) nread && handle->recv_cb != NULL; k++) {
|
||||
flags = UV_UDP_MMSG_CHUNK;
|
||||
if (msgs[k].msg_hdr.msg_flags & MSG_TRUNC)
|
||||
flags |= UV_UDP_PARTIAL;
|
||||
|
||||
chunk_buf = uv_buf_init(iov[k].iov_base, iov[k].iov_len);
|
||||
handle->recv_cb(handle,
|
||||
msgs[k].msg_len,
|
||||
&chunk_buf,
|
||||
msgs[k].msg_hdr.msg_name,
|
||||
flags);
|
||||
}
|
||||
|
||||
/* one last callback so the original buffer is freed */
|
||||
if (handle->recv_cb != NULL)
|
||||
handle->recv_cb(handle, 0, buf, NULL, 0);
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
struct sockaddr_storage peer;
|
||||
@@ -165,18 +252,32 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
*/
|
||||
count = 32;
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.msg_name = &peer;
|
||||
|
||||
do {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
assert(buf.base != NULL);
|
||||
|
||||
#if HAVE_MMSG
|
||||
uv_once(&once, uv__udp_mmsg_init);
|
||||
if (uv__recvmmsg_avail) {
|
||||
/* Returned space for more than 1 datagram, use it to receive
|
||||
* multiple datagrams. */
|
||||
if (buf.len >= 2 * UV__UDP_DGRAM_MAXSIZE) {
|
||||
nread = uv__udp_recvmmsg(handle, &buf);
|
||||
if (nread > 0)
|
||||
count -= nread;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
h.msg_name = &peer;
|
||||
h.msg_namelen = sizeof(peer);
|
||||
h.msg_iov = (void*) &buf;
|
||||
h.msg_iovlen = 1;
|
||||
@@ -193,33 +294,126 @@ static void uv__udp_recvmsg(uv_udp_t* handle) {
|
||||
handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0);
|
||||
}
|
||||
else {
|
||||
const struct sockaddr *addr;
|
||||
if (h.msg_namelen == 0)
|
||||
addr = NULL;
|
||||
else
|
||||
addr = (const struct sockaddr*) &peer;
|
||||
|
||||
flags = 0;
|
||||
if (h.msg_flags & MSG_TRUNC)
|
||||
flags |= UV_UDP_PARTIAL;
|
||||
|
||||
handle->recv_cb(handle, nread, &buf, addr, flags);
|
||||
handle->recv_cb(handle, nread, &buf, (const struct sockaddr*) &peer, flags);
|
||||
}
|
||||
count--;
|
||||
}
|
||||
/* recv_cb callback may decide to pause or close the handle */
|
||||
while (nread != -1
|
||||
&& count-- > 0
|
||||
&& count > 0
|
||||
&& handle->io_watcher.fd != -1
|
||||
&& handle->recv_cb != NULL);
|
||||
}
|
||||
|
||||
#if HAVE_MMSG
|
||||
static void uv__udp_sendmmsg(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
struct uv__mmsghdr h[UV__MMSG_MAXWIDTH];
|
||||
struct uv__mmsghdr *p;
|
||||
QUEUE* q;
|
||||
ssize_t npkts;
|
||||
size_t pkts;
|
||||
size_t i;
|
||||
|
||||
if (QUEUE_EMPTY(&handle->write_queue))
|
||||
return;
|
||||
|
||||
write_queue_drain:
|
||||
for (pkts = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
pkts < UV__MMSG_MAXWIDTH && q != &handle->write_queue;
|
||||
++pkts, q = QUEUE_HEAD(q)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
p = &h[pkts];
|
||||
memset(p, 0, sizeof(*p));
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
p->msg_hdr.msg_name = NULL;
|
||||
p->msg_hdr.msg_namelen = 0;
|
||||
} else {
|
||||
p->msg_hdr.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
p->msg_hdr.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h[pkts].msg_hdr.msg_iov = (struct iovec*) req->bufs;
|
||||
h[pkts].msg_hdr.msg_iovlen = req->nbufs;
|
||||
}
|
||||
|
||||
do
|
||||
npkts = uv__sendmmsg(handle->io_watcher.fd, h, pkts, 0);
|
||||
while (npkts == -1 && errno == EINTR);
|
||||
|
||||
if (npkts < 1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
return;
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < pkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(q)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = UV__ERR(errno);
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, q = QUEUE_HEAD(&handle->write_queue);
|
||||
i < pkts && q != &handle->write_queue;
|
||||
++i, q = QUEUE_HEAD(&handle->write_queue)) {
|
||||
assert(q != NULL);
|
||||
req = QUEUE_DATA(q, uv_udp_send_t, queue);
|
||||
assert(req != NULL);
|
||||
|
||||
req->status = req->bufs[0].len;
|
||||
|
||||
/* Sending a datagram is an atomic operation: either all data
|
||||
* is written or nothing is (and EMSGSIZE is raised). That is
|
||||
* why we don't handle partial writes. Just pop the request
|
||||
* off the write queue and onto the completed queue, done.
|
||||
*/
|
||||
QUEUE_REMOVE(&req->queue);
|
||||
QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
|
||||
}
|
||||
|
||||
/* couldn't batch everything, continue sending (jump to avoid stack growth) */
|
||||
if (!QUEUE_EMPTY(&handle->write_queue))
|
||||
goto write_queue_drain;
|
||||
uv__io_feed(handle->loop, &handle->io_watcher);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
struct msghdr h;
|
||||
QUEUE* q;
|
||||
ssize_t size;
|
||||
|
||||
#if HAVE_MMSG
|
||||
uv_once(&once, uv__udp_mmsg_init);
|
||||
if (uv__sendmmsg_avail) {
|
||||
uv__udp_sendmmsg(handle);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_queue);
|
||||
assert(q != NULL);
|
||||
@@ -269,7 +463,6 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
|
||||
* refinements for programs that use multicast.
|
||||
*
|
||||
@@ -659,6 +852,100 @@ static int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
|
||||
static int uv__udp_set_source_membership4(uv_udp_t* handle,
|
||||
const struct sockaddr_in* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in* source_addr,
|
||||
uv_membership membership) {
|
||||
struct ip_mreq_source mreq;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
||||
mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = IP_ADD_SOURCE_MEMBERSHIP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = IP_DROP_SOURCE_MEMBERSHIP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IP,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_source_membership6(uv_udp_t* handle,
|
||||
const struct sockaddr_in6* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in6* source_addr,
|
||||
uv_membership membership) {
|
||||
struct group_source_req mreq;
|
||||
struct sockaddr_in6 addr6;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_ip6_addr(interface_addr, 0, &addr6);
|
||||
if (err)
|
||||
return err;
|
||||
mreq.gsr_interface = addr6.sin6_scope_id;
|
||||
} else {
|
||||
mreq.gsr_interface = 0;
|
||||
}
|
||||
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = MCAST_JOIN_SOURCE_GROUP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = MCAST_LEAVE_SOURCE_GROUP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->io_watcher.fd,
|
||||
IPPROTO_IPV6,
|
||||
optname,
|
||||
&mreq,
|
||||
sizeof(mreq))) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
int domain;
|
||||
int err;
|
||||
@@ -748,11 +1035,60 @@ int uv_udp_set_membership(uv_udp_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership) {
|
||||
#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__ANDROID__)
|
||||
int err;
|
||||
struct sockaddr_storage mcast_addr;
|
||||
struct sockaddr_in* mcast_addr4;
|
||||
struct sockaddr_in6* mcast_addr6;
|
||||
struct sockaddr_storage src_addr;
|
||||
struct sockaddr_in* src_addr4;
|
||||
struct sockaddr_in6* src_addr6;
|
||||
|
||||
mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
|
||||
mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
|
||||
src_addr4 = (struct sockaddr_in*)&src_addr;
|
||||
src_addr6 = (struct sockaddr_in6*)&src_addr;
|
||||
|
||||
err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
|
||||
if (err) {
|
||||
err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
err = uv_ip6_addr(source_addr, 0, src_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership6(handle,
|
||||
mcast_addr6,
|
||||
interface_addr,
|
||||
src_addr6,
|
||||
membership);
|
||||
}
|
||||
|
||||
err = uv_ip4_addr(source_addr, 0, src_addr4);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership4(handle,
|
||||
mcast_addr4,
|
||||
interface_addr,
|
||||
src_addr4,
|
||||
membership);
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int uv__setsockopt(uv_udp_t* handle,
|
||||
int option4,
|
||||
int option6,
|
||||
const void* val,
|
||||
size_t size) {
|
||||
socklen_t size) {
|
||||
int r;
|
||||
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
@@ -875,7 +1211,7 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
|
||||
@@ -100,6 +100,17 @@ void* uv__realloc(void* ptr, size_t size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* uv__reallocf(void* ptr, size_t size) {
|
||||
void* newptr;
|
||||
|
||||
newptr = uv__realloc(ptr, size);
|
||||
if (newptr == NULL)
|
||||
if (size > 0)
|
||||
uv__free(ptr);
|
||||
|
||||
return newptr;
|
||||
}
|
||||
|
||||
int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
uv_realloc_func realloc_func,
|
||||
uv_calloc_func calloc_func,
|
||||
@@ -212,6 +223,9 @@ int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->sin_family = AF_INET;
|
||||
addr->sin_port = htons(port);
|
||||
#ifdef SIN6_LEN
|
||||
addr->sin_len = sizeof(*addr);
|
||||
#endif
|
||||
return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
|
||||
}
|
||||
|
||||
@@ -788,3 +802,24 @@ void uv_loop_delete(uv_loop_t* loop) {
|
||||
if (loop != default_loop)
|
||||
uv__free(loop);
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_environ(uv_env_item_t* envitems, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(envitems[i].name);
|
||||
}
|
||||
|
||||
uv__free(envitems);
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
uv__free(cpu_infos[i].model);
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
@@ -322,5 +322,6 @@ char *uv__strndup(const char* s, size_t n);
|
||||
void* uv__malloc(size_t size);
|
||||
void uv__free(void* ptr);
|
||||
void* uv__realloc(void* ptr, size_t size);
|
||||
void* uv__reallocf(void* ptr, size_t size);
|
||||
|
||||
#endif /* UV_COMMON_H_ */
|
||||
|
||||
@@ -321,8 +321,13 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
|
||||
uv__loops_remove(loop);
|
||||
|
||||
/* close the async handle without needing an extra loop iteration */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
/* Close the async handle without needing an extra loop iteration.
|
||||
* We might have a pending message, but we're just going to destroy the IOCP
|
||||
* soon, so we can just discard it now without the usual risk of a getting
|
||||
* another notification from GetQueuedCompletionStatusEx after calling the
|
||||
* close_cb (which we also skip defining). We'll assert later that queue was
|
||||
* actually empty and all reqs handled. */
|
||||
loop->wq_async.async_sent = 0;
|
||||
loop->wq_async.close_cb = NULL;
|
||||
uv__handle_closing(&loop->wq_async);
|
||||
uv__handle_close(&loop->wq_async);
|
||||
|
||||
@@ -132,6 +132,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
case WSAENOBUFS: return UV_ENOBUFS;
|
||||
case ERROR_BAD_PATHNAME: return UV_ENOENT;
|
||||
case ERROR_DIRECTORY: return UV_ENOENT;
|
||||
case ERROR_ENVVAR_NOT_FOUND: return UV_ENOENT;
|
||||
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
|
||||
case ERROR_INVALID_NAME: return UV_ENOENT;
|
||||
case ERROR_INVALID_DRIVE: return UV_ENOENT;
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
#ifndef UV_WIN_FS_FD_HASH_INL_H_
|
||||
#define UV_WIN_FS_FD_HASH_INL_H_
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
/* Files are only inserted in uv__fd_hash when the UV_FS_O_FILEMAP flag is
|
||||
* specified. Thus, when uv__fd_hash_get returns true, the file mapping in the
|
||||
* info structure should be used for read/write operations.
|
||||
*
|
||||
* If the file is empty, the mapping field will be set to
|
||||
* INVALID_HANDLE_VALUE. This is not an issue since the file mapping needs to
|
||||
* be created anyway when the file size changes.
|
||||
*
|
||||
* Since file descriptors are sequential integers, the modulo operator is used
|
||||
* as hashing function. For each bucket, a single linked list of arrays is
|
||||
* kept to minimize allocations. A statically allocated memory buffer is kept
|
||||
* for the first array in each bucket. */
|
||||
|
||||
|
||||
#define UV__FD_HASH_SIZE 256
|
||||
#define UV__FD_HASH_GROUP_SIZE 16
|
||||
|
||||
struct uv__fd_info_s {
|
||||
int flags;
|
||||
BOOLEAN is_directory;
|
||||
HANDLE mapping;
|
||||
LARGE_INTEGER size;
|
||||
LARGE_INTEGER current_pos;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_entry_s {
|
||||
uv_file fd;
|
||||
struct uv__fd_info_s info;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_entry_group_s {
|
||||
struct uv__fd_hash_entry_s entries[UV__FD_HASH_GROUP_SIZE];
|
||||
struct uv__fd_hash_entry_group_s* next;
|
||||
};
|
||||
|
||||
struct uv__fd_hash_bucket_s {
|
||||
size_t size;
|
||||
struct uv__fd_hash_entry_group_s* data;
|
||||
};
|
||||
|
||||
|
||||
static uv_mutex_t uv__fd_hash_mutex;
|
||||
|
||||
static struct uv__fd_hash_entry_group_s
|
||||
uv__fd_hash_entry_initial[UV__FD_HASH_SIZE * UV__FD_HASH_GROUP_SIZE];
|
||||
static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE];
|
||||
|
||||
|
||||
INLINE static void uv__fd_hash_init(void) {
|
||||
int i, err;
|
||||
|
||||
err = uv_mutex_init(&uv__fd_hash_mutex);
|
||||
if (err) {
|
||||
uv_fatal_error(err, "uv_mutex_init");
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uv__fd_hash); ++i) {
|
||||
uv__fd_hash[i].size = 0;
|
||||
uv__fd_hash[i].data =
|
||||
uv__fd_hash_entry_initial + i * UV__FD_HASH_GROUP_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
#define FIND_COMMON_VARIABLES \
|
||||
unsigned i; \
|
||||
unsigned bucket = fd % ARRAY_SIZE(uv__fd_hash); \
|
||||
struct uv__fd_hash_entry_s* entry_ptr = NULL; \
|
||||
struct uv__fd_hash_entry_group_s* group_ptr; \
|
||||
struct uv__fd_hash_bucket_s* bucket_ptr = &uv__fd_hash[bucket];
|
||||
|
||||
#define FIND_IN_GROUP_PTR(group_size) \
|
||||
do { \
|
||||
for (i = 0; i < group_size; ++i) { \
|
||||
if (group_ptr->entries[i].fd == fd) { \
|
||||
entry_ptr = &group_ptr->entries[i]; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define FIND_IN_BUCKET_PTR() \
|
||||
do { \
|
||||
size_t first_group_size = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE; \
|
||||
if (bucket_ptr->size != 0 && first_group_size == 0) \
|
||||
first_group_size = UV__FD_HASH_GROUP_SIZE; \
|
||||
group_ptr = bucket_ptr->data; \
|
||||
FIND_IN_GROUP_PTR(first_group_size); \
|
||||
for (group_ptr = group_ptr->next; \
|
||||
group_ptr != NULL && entry_ptr == NULL; \
|
||||
group_ptr = group_ptr->next) \
|
||||
FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \
|
||||
} while (0)
|
||||
|
||||
INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr != NULL) {
|
||||
*info = entry_ptr->info;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
return entry_ptr != NULL;
|
||||
}
|
||||
|
||||
INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr == NULL) {
|
||||
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
|
||||
|
||||
if (bucket_ptr->size != 0 && i == 0) {
|
||||
struct uv__fd_hash_entry_group_s* new_group_ptr =
|
||||
uv__malloc(sizeof(*new_group_ptr));
|
||||
if (new_group_ptr == NULL) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
new_group_ptr->next = bucket_ptr->data;
|
||||
bucket_ptr->data = new_group_ptr;
|
||||
}
|
||||
|
||||
bucket_ptr->size += 1;
|
||||
entry_ptr = &bucket_ptr->data->entries[i];
|
||||
entry_ptr->fd = fd;
|
||||
}
|
||||
|
||||
entry_ptr->info = *info;
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
}
|
||||
|
||||
INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) {
|
||||
FIND_COMMON_VARIABLES
|
||||
|
||||
uv_mutex_lock(&uv__fd_hash_mutex);
|
||||
|
||||
FIND_IN_BUCKET_PTR();
|
||||
|
||||
if (entry_ptr != NULL) {
|
||||
*info = entry_ptr->info;
|
||||
|
||||
bucket_ptr->size -= 1;
|
||||
|
||||
i = bucket_ptr->size % UV__FD_HASH_GROUP_SIZE;
|
||||
if (entry_ptr != &bucket_ptr->data->entries[i]) {
|
||||
*entry_ptr = bucket_ptr->data->entries[i];
|
||||
}
|
||||
|
||||
if (bucket_ptr->size != 0 &&
|
||||
bucket_ptr->size % UV__FD_HASH_GROUP_SIZE == 0) {
|
||||
struct uv__fd_hash_entry_group_s* old_group_ptr = bucket_ptr->data;
|
||||
bucket_ptr->data = old_group_ptr->next;
|
||||
uv__free(old_group_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&uv__fd_hash_mutex);
|
||||
return entry_ptr != NULL;
|
||||
}
|
||||
|
||||
#undef FIND_COMMON_VARIABLES
|
||||
#undef FIND_IN_GROUP_PTR
|
||||
#undef FIND_IN_BUCKET_PTR
|
||||
|
||||
#endif /* UV_WIN_FS_FD_HASH_INL_H_ */
|
||||
+593
-48
@@ -34,8 +34,7 @@
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
#include <wincrypt.h>
|
||||
#include "fs-fd-hash-inl.h"
|
||||
|
||||
|
||||
#define UV_FS_FREE_PATHS 0x0002
|
||||
@@ -126,6 +125,8 @@
|
||||
#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
|
||||
((c) >= L'A' && (c) <= L'Z'))
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
|
||||
const WCHAR JUNCTION_PREFIX_LEN = 4;
|
||||
|
||||
@@ -137,8 +138,16 @@ const WCHAR UNC_PATH_PREFIX_LEN = 8;
|
||||
|
||||
static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
|
||||
|
||||
static DWORD uv__allocation_granularity;
|
||||
|
||||
|
||||
void uv_fs_init(void) {
|
||||
_fmode = _O_BINARY;
|
||||
SYSTEM_INFO system_info;
|
||||
|
||||
GetSystemInfo(&system_info);
|
||||
uv__allocation_granularity = system_info.dwAllocationGranularity;
|
||||
|
||||
uv__fd_hash_init();
|
||||
}
|
||||
|
||||
|
||||
@@ -414,6 +423,27 @@ void fs__open(uv_fs_t* req) {
|
||||
HANDLE file;
|
||||
int fd, current_umask;
|
||||
int flags = req->fs.info.file_flags;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
/* Adjust flags to be compatible with the memory file mapping. Save the
|
||||
* original flags to emulate the correct behavior. */
|
||||
if (flags & UV_FS_O_FILEMAP) {
|
||||
fd_info.flags = flags;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
|
||||
if ((flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) ==
|
||||
UV_FS_O_WRONLY) {
|
||||
/* CreateFileMapping always needs read access */
|
||||
flags = (flags & ~UV_FS_O_WRONLY) | UV_FS_O_RDWR;
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_APPEND) {
|
||||
/* Clear the append flag and ensure RDRW mode */
|
||||
flags &= ~UV_FS_O_APPEND;
|
||||
flags &= ~(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
flags |= UV_FS_O_RDWR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Obtain the active umask. umask() never fails and returns the previous
|
||||
* umask. */
|
||||
@@ -444,7 +474,8 @@ void fs__open(uv_fs_t* req) {
|
||||
* Here is where we deviate significantly from what CRT's _open()
|
||||
* does. We indiscriminately use all the sharing modes, to match
|
||||
* UNIX semantics. In particular, this ensures that the file can
|
||||
* be deleted even whilst it's open, fixing issue #1449.
|
||||
* be deleted even whilst it's open, fixing issue
|
||||
* https://github.com/nodejs/node-v0.x-archive/issues/1449.
|
||||
* We still support exclusive sharing mode, since it is necessary
|
||||
* for opening raw block devices, otherwise Windows will prevent
|
||||
* any attempt to write past the master boot record.
|
||||
@@ -583,11 +614,55 @@ void fs__open(uv_fs_t* req) {
|
||||
else if (GetLastError() != ERROR_SUCCESS)
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
else
|
||||
SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
|
||||
SET_REQ_WIN32_ERROR(req, (DWORD) UV_UNKNOWN);
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_FILEMAP) {
|
||||
FILE_STANDARD_INFO file_info;
|
||||
if (!GetFileInformationByHandleEx(file,
|
||||
FileStandardInfo,
|
||||
&file_info,
|
||||
sizeof file_info)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
fd_info.is_directory = file_info.Directory;
|
||||
|
||||
if (fd_info.is_directory) {
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
if (!GetFileSizeEx(file, &fd_info.size)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd_info.size.QuadPart == 0) {
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
|
||||
UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
|
||||
fd_info.mapping = CreateFileMapping(file,
|
||||
NULL,
|
||||
flProtect,
|
||||
fd_info.size.HighPart,
|
||||
fd_info.size.LowPart,
|
||||
NULL);
|
||||
if (fd_info.mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, fd);
|
||||
return;
|
||||
|
||||
@@ -598,9 +673,16 @@ void fs__open(uv_fs_t* req) {
|
||||
void fs__close(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int result;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
if (uv__fd_hash_remove(fd, &fd_info)) {
|
||||
if (fd_info.mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info.mapping);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd > 2)
|
||||
result = _close(fd);
|
||||
else
|
||||
@@ -618,6 +700,123 @@ void fs__close(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
LONG fs__filemap_ex_filter(LONG excode, PEXCEPTION_POINTERS pep,
|
||||
int* perror) {
|
||||
if (excode != EXCEPTION_IN_PAGE_ERROR) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
assert(perror != NULL);
|
||||
if (pep != NULL && pep->ExceptionRecord != NULL &&
|
||||
pep->ExceptionRecord->NumberParameters >= 3) {
|
||||
NTSTATUS status = (NTSTATUS)pep->ExceptionRecord->ExceptionInformation[3];
|
||||
*perror = pRtlNtStatusToDosError(status);
|
||||
if (*perror != ERROR_SUCCESS) {
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
}
|
||||
*perror = UV_UNKNOWN;
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
|
||||
void fs__read_filemap(uv_fs_t* req, struct uv__fd_info_s* fd_info) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__read */
|
||||
int rw_flags = fd_info->flags &
|
||||
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
size_t read_size, done_read;
|
||||
unsigned int index;
|
||||
LARGE_INTEGER pos, end_pos;
|
||||
size_t view_offset;
|
||||
LARGE_INTEGER view_base;
|
||||
void* view;
|
||||
|
||||
if (rw_flags == UV_FS_O_WRONLY) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
if (fd_info->is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
pos = fd_info->current_pos;
|
||||
} else {
|
||||
pos.QuadPart = req->fs.info.offset;
|
||||
}
|
||||
|
||||
/* Make sure we wont read past EOF. */
|
||||
if (pos.QuadPart >= fd_info->size.QuadPart) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
read_size = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
read_size += req->fs.info.bufs[index].len;
|
||||
}
|
||||
read_size = (size_t) MIN((LONGLONG) read_size,
|
||||
fd_info->size.QuadPart - pos.QuadPart);
|
||||
if (read_size == 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
end_pos.QuadPart = pos.QuadPart + read_size;
|
||||
|
||||
view_offset = pos.QuadPart % uv__allocation_granularity;
|
||||
view_base.QuadPart = pos.QuadPart - view_offset;
|
||||
view = MapViewOfFile(fd_info->mapping,
|
||||
FILE_MAP_READ,
|
||||
view_base.HighPart,
|
||||
view_base.LowPart,
|
||||
view_offset + read_size);
|
||||
if (view == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
done_read = 0;
|
||||
for (index = 0;
|
||||
index < req->fs.info.nbufs && done_read < read_size;
|
||||
++index) {
|
||||
int err = 0;
|
||||
size_t this_read_size = MIN(req->fs.info.bufs[index].len,
|
||||
read_size - done_read);
|
||||
#ifdef _MSC_VER
|
||||
__try {
|
||||
#endif
|
||||
memcpy(req->fs.info.bufs[index].base,
|
||||
(char*)view + view_offset + done_read,
|
||||
this_read_size);
|
||||
#ifdef _MSC_VER
|
||||
}
|
||||
__except (fs__filemap_ex_filter(GetExceptionCode(),
|
||||
GetExceptionInformation(), &err)) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
done_read += this_read_size;
|
||||
}
|
||||
assert(done_read == read_size);
|
||||
|
||||
if (!UnmapViewOfFile(view)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
fd_info->current_pos = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, read_size);
|
||||
return;
|
||||
}
|
||||
|
||||
void fs__read(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
@@ -631,9 +830,15 @@ void fs__read(uv_fs_t* req) {
|
||||
LARGE_INTEGER original_position;
|
||||
LARGE_INTEGER zero_offset;
|
||||
int restore_position;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
fs__read_filemap(req, &fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
zero_offset.QuadPart = 0;
|
||||
restore_position = 0;
|
||||
handle = uv__get_osfhandle(fd);
|
||||
@@ -690,6 +895,131 @@ void fs__read(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
void fs__write_filemap(uv_fs_t* req, HANDLE file,
|
||||
struct uv__fd_info_s* fd_info) {
|
||||
int fd = req->file.fd; /* VERIFY_FD done in fs__write */
|
||||
int force_append = fd_info->flags & UV_FS_O_APPEND;
|
||||
int rw_flags = fd_info->flags &
|
||||
(UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR);
|
||||
size_t write_size, done_write;
|
||||
unsigned int index;
|
||||
LARGE_INTEGER zero, pos, end_pos;
|
||||
size_t view_offset;
|
||||
LARGE_INTEGER view_base;
|
||||
void* view;
|
||||
FILETIME ft;
|
||||
|
||||
if (rw_flags == UV_FS_O_RDONLY) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
if (fd_info->is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_INVALID_FUNCTION);
|
||||
return;
|
||||
}
|
||||
|
||||
write_size = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
write_size += req->fs.info.bufs[index].len;
|
||||
}
|
||||
|
||||
if (write_size == 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
zero.QuadPart = 0;
|
||||
if (force_append) {
|
||||
pos = fd_info->size;
|
||||
} else if (req->fs.info.offset == -1) {
|
||||
pos = fd_info->current_pos;
|
||||
} else {
|
||||
pos.QuadPart = req->fs.info.offset;
|
||||
}
|
||||
|
||||
end_pos.QuadPart = pos.QuadPart + write_size;
|
||||
|
||||
/* Recreate the mapping to enlarge the file if needed */
|
||||
if (end_pos.QuadPart > fd_info->size.QuadPart) {
|
||||
if (fd_info->mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info->mapping);
|
||||
}
|
||||
|
||||
fd_info->mapping = CreateFileMapping(file,
|
||||
NULL,
|
||||
PAGE_READWRITE,
|
||||
end_pos.HighPart,
|
||||
end_pos.LowPart,
|
||||
NULL);
|
||||
if (fd_info->mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(file);
|
||||
fd_info->mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info->size.QuadPart = 0;
|
||||
fd_info->current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
fd_info->size = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
view_offset = pos.QuadPart % uv__allocation_granularity;
|
||||
view_base.QuadPart = pos.QuadPart - view_offset;
|
||||
view = MapViewOfFile(fd_info->mapping,
|
||||
FILE_MAP_WRITE,
|
||||
view_base.HighPart,
|
||||
view_base.LowPart,
|
||||
view_offset + write_size);
|
||||
if (view == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
done_write = 0;
|
||||
for (index = 0; index < req->fs.info.nbufs; ++index) {
|
||||
int err = 0;
|
||||
#ifdef _MSC_VER
|
||||
__try {
|
||||
#endif
|
||||
memcpy((char*)view + view_offset + done_write,
|
||||
req->fs.info.bufs[index].base,
|
||||
req->fs.info.bufs[index].len);
|
||||
#ifdef _MSC_VER
|
||||
}
|
||||
__except (fs__filemap_ex_filter(GetExceptionCode(),
|
||||
GetExceptionInformation(), &err)) {
|
||||
SET_REQ_WIN32_ERROR(req, err);
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
done_write += req->fs.info.bufs[index].len;
|
||||
}
|
||||
assert(done_write == write_size);
|
||||
|
||||
if (!FlushViewOfFile(view, 0)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
UnmapViewOfFile(view);
|
||||
return;
|
||||
}
|
||||
if (!UnmapViewOfFile(view)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.offset == -1) {
|
||||
fd_info->current_pos = end_pos;
|
||||
uv__fd_hash_add(fd, fd_info);
|
||||
}
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
SetFileTime(file, NULL, NULL, &ft);
|
||||
|
||||
SET_REQ_RESULT(req, done_write);
|
||||
}
|
||||
|
||||
void fs__write(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int64_t offset = req->fs.info.offset;
|
||||
@@ -702,6 +1032,7 @@ void fs__write(uv_fs_t* req) {
|
||||
LARGE_INTEGER original_position;
|
||||
LARGE_INTEGER zero_offset;
|
||||
int restore_position;
|
||||
struct uv__fd_info_s fd_info;
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
@@ -713,6 +1044,11 @@ void fs__write(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
fs__write_filemap(req, handle, &fd_info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset != -1) {
|
||||
memset(&overlapped, 0, sizeof overlapped);
|
||||
overlapped_ptr = &overlapped;
|
||||
@@ -850,13 +1186,19 @@ void fs__unlink(uv_fs_t* req) {
|
||||
|
||||
void fs__mkdir(uv_fs_t* req) {
|
||||
/* TODO: use req->mode. */
|
||||
int result = _wmkdir(req->file.pathw);
|
||||
SET_REQ_RESULT(req, result);
|
||||
req->result = _wmkdir(req->file.pathw);
|
||||
if (req->result == -1) {
|
||||
req->sys_errno_ = _doserrno;
|
||||
req->result = req->sys_errno_ == ERROR_INVALID_NAME
|
||||
? UV_EINVAL
|
||||
: uv_translate_sys_error(req->sys_errno_);
|
||||
}
|
||||
}
|
||||
|
||||
typedef int (*uv__fs_mktemp_func)(uv_fs_t* req);
|
||||
|
||||
/* OpenBSD original: lib/libc/stdio/mktemp.c */
|
||||
void fs__mkdtemp(uv_fs_t* req) {
|
||||
void fs__mktemp(uv_fs_t* req, uv__fs_mktemp_func func) {
|
||||
static const WCHAR *tempchars =
|
||||
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
static const size_t num_chars = 62;
|
||||
@@ -864,9 +1206,7 @@ void fs__mkdtemp(uv_fs_t* req) {
|
||||
WCHAR *cp, *ep;
|
||||
unsigned int tries, i;
|
||||
size_t len;
|
||||
HCRYPTPROV h_crypt_prov;
|
||||
uint64_t v;
|
||||
BOOL released;
|
||||
|
||||
len = wcslen(req->file.pathw);
|
||||
ep = req->file.pathw + len;
|
||||
@@ -875,16 +1215,10 @@ void fs__mkdtemp(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
|
||||
CRYPT_VERIFYCONTEXT)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
tries = TMP_MAX;
|
||||
do {
|
||||
if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
if (uv__random_rtlgenrandom((void *)&v, sizeof(v)) < 0) {
|
||||
SET_REQ_UV_ERROR(req, UV_EIO, ERROR_IO_DEVICE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -894,25 +1228,92 @@ void fs__mkdtemp(uv_fs_t* req) {
|
||||
v /= num_chars;
|
||||
}
|
||||
|
||||
if (_wmkdir(req->file.pathw) == 0) {
|
||||
len = strlen(req->path);
|
||||
wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
|
||||
SET_REQ_RESULT(req, 0);
|
||||
break;
|
||||
} else if (errno != EEXIST) {
|
||||
SET_REQ_RESULT(req, -1);
|
||||
if (func(req)) {
|
||||
if (req->result >= 0) {
|
||||
len = strlen(req->path);
|
||||
wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (--tries);
|
||||
|
||||
released = CryptReleaseContext(h_crypt_prov, 0);
|
||||
assert(released);
|
||||
if (tries == 0) {
|
||||
SET_REQ_RESULT(req, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int fs__mkdtemp_func(uv_fs_t* req) {
|
||||
if (_wmkdir(req->file.pathw) == 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return 1;
|
||||
} else if (errno != EEXIST) {
|
||||
SET_REQ_RESULT(req, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void fs__mkdtemp(uv_fs_t* req) {
|
||||
fs__mktemp(req, fs__mkdtemp_func);
|
||||
}
|
||||
|
||||
|
||||
static int fs__mkstemp_func(uv_fs_t* req) {
|
||||
HANDLE file;
|
||||
int fd;
|
||||
|
||||
file = CreateFileW(req->file.pathw,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
DWORD error;
|
||||
error = GetLastError();
|
||||
|
||||
/* If the file exists, the main fs__mktemp() function
|
||||
will retry. If it's another error, we want to stop. */
|
||||
if (error != ERROR_FILE_EXISTS) {
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = _open_osfhandle((intptr_t) file, 0);
|
||||
if (fd < 0) {
|
||||
/* The only known failure mode for _open_osfhandle() is EMFILE, in which
|
||||
* case GetLastError() will return zero. However we'll try to handle other
|
||||
* errors as well, should they ever occur.
|
||||
*/
|
||||
if (errno == EMFILE)
|
||||
SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
|
||||
else if (GetLastError() != ERROR_SUCCESS)
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
else
|
||||
SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
|
||||
CloseHandle(file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void fs__mkstemp(uv_fs_t* req) {
|
||||
fs__mktemp(req, fs__mkstemp_func);
|
||||
}
|
||||
|
||||
|
||||
void fs__scandir(uv_fs_t* req) {
|
||||
static const size_t dirents_initial_size = 32;
|
||||
|
||||
@@ -1409,47 +1810,57 @@ INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
|
||||
}
|
||||
|
||||
|
||||
INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
|
||||
INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
|
||||
int do_lstat,
|
||||
uv_stat_t* statbuf) {
|
||||
HANDLE handle;
|
||||
DWORD flags;
|
||||
DWORD ret;
|
||||
|
||||
flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (do_lstat) {
|
||||
if (do_lstat)
|
||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
}
|
||||
|
||||
handle = CreateFileW(req->file.pathw,
|
||||
handle = CreateFileW(path,
|
||||
FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
flags,
|
||||
NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs__stat_handle(handle, &req->statbuf, do_lstat) != 0) {
|
||||
DWORD error = GetLastError();
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
ret = GetLastError();
|
||||
else if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
|
||||
ret = GetLastError();
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
CloseHandle(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
|
||||
DWORD error;
|
||||
|
||||
error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf);
|
||||
if (error != 0) {
|
||||
if (do_lstat &&
|
||||
(error == ERROR_SYMLINK_NOT_SUPPORTED ||
|
||||
error == ERROR_NOT_A_REPARSE_POINT)) {
|
||||
/* We opened a reparse point but it was not a symlink. Try again. */
|
||||
fs__stat_impl(req, 0);
|
||||
|
||||
} else {
|
||||
/* Stat failed. */
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
req->ptr = &req->statbuf;
|
||||
req->result = 0;
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -1526,6 +1937,7 @@ static void fs__fdatasync(uv_fs_t* req) {
|
||||
static void fs__ftruncate(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
HANDLE handle;
|
||||
struct uv__fd_info_s fd_info = { 0 };
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
FILE_END_OF_FILE_INFORMATION eof_info;
|
||||
@@ -1534,6 +1946,17 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
|
||||
handle = uv__get_osfhandle(fd);
|
||||
|
||||
if (uv__fd_hash_get(fd, &fd_info)) {
|
||||
if (fd_info.is_directory) {
|
||||
SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fd_info.mapping != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(fd_info.mapping);
|
||||
}
|
||||
}
|
||||
|
||||
eof_info.EndOfFile.QuadPart = req->fs.info.offset;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
@@ -1546,6 +1969,43 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
|
||||
|
||||
if (fd_info.flags) {
|
||||
CloseHandle(handle);
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd_info.flags) {
|
||||
fd_info.size = eof_info.EndOfFile;
|
||||
|
||||
if (fd_info.size.QuadPart == 0) {
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
} else {
|
||||
DWORD flProtect = (fd_info.flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY |
|
||||
UV_FS_O_RDWR)) == UV_FS_O_RDONLY ? PAGE_READONLY : PAGE_READWRITE;
|
||||
fd_info.mapping = CreateFileMapping(handle,
|
||||
NULL,
|
||||
flProtect,
|
||||
fd_info.size.HighPart,
|
||||
fd_info.size.LowPart,
|
||||
NULL);
|
||||
if (fd_info.mapping == NULL) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
CloseHandle(handle);
|
||||
fd_info.mapping = INVALID_HANDLE_VALUE;
|
||||
fd_info.size.QuadPart = 0;
|
||||
fd_info.current_pos.QuadPart = 0;
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uv__fd_hash_add(fd, &fd_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,6 +2013,8 @@ static void fs__ftruncate(uv_fs_t* req) {
|
||||
static void fs__copyfile(uv_fs_t* req) {
|
||||
int flags;
|
||||
int overwrite;
|
||||
uv_stat_t statbuf;
|
||||
uv_stat_t new_statbuf;
|
||||
|
||||
flags = req->fs.info.file_flags;
|
||||
|
||||
@@ -1563,12 +2025,25 @@ static void fs__copyfile(uv_fs_t* req) {
|
||||
|
||||
overwrite = flags & UV_FS_COPYFILE_EXCL;
|
||||
|
||||
if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) == 0) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) != 0) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, 0);
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
if (req->result != UV_EBUSY)
|
||||
return;
|
||||
|
||||
/* if error UV_EBUSY check if src and dst file are the same */
|
||||
if (fs__stat_impl_from_path(req->file.pathw, 0, &statbuf) != 0 ||
|
||||
fs__stat_impl_from_path(req->fs.info.new_pathw, 0, &new_statbuf) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (statbuf.st_dev == new_statbuf.st_dev &&
|
||||
statbuf.st_ino == new_statbuf.st_ino) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2139,6 +2614,42 @@ static void fs__lchown(uv_fs_t* req) {
|
||||
req->result = 0;
|
||||
}
|
||||
|
||||
|
||||
static void fs__statfs(uv_fs_t* req) {
|
||||
uv_statfs_t* stat_fs;
|
||||
DWORD sectors_per_cluster;
|
||||
DWORD bytes_per_sector;
|
||||
DWORD free_clusters;
|
||||
DWORD total_clusters;
|
||||
|
||||
if (0 == GetDiskFreeSpaceW(req->file.pathw,
|
||||
§ors_per_cluster,
|
||||
&bytes_per_sector,
|
||||
&free_clusters,
|
||||
&total_clusters)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||
if (stat_fs == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
stat_fs->f_type = 0;
|
||||
stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster;
|
||||
stat_fs->f_blocks = total_clusters;
|
||||
stat_fs->f_bfree = free_clusters;
|
||||
stat_fs->f_bavail = free_clusters;
|
||||
stat_fs->f_files = 0;
|
||||
stat_fs->f_ffree = 0;
|
||||
req->ptr = stat_fs;
|
||||
req->flags |= UV_FS_FREE_PTR;
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_work(struct uv__work* w) {
|
||||
uv_fs_t* req;
|
||||
|
||||
@@ -2168,6 +2679,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(RMDIR, rmdir)
|
||||
XX(MKDIR, mkdir)
|
||||
XX(MKDTEMP, mkdtemp)
|
||||
XX(MKSTEMP, mkstemp)
|
||||
XX(RENAME, rename)
|
||||
XX(SCANDIR, scandir)
|
||||
XX(READDIR, readdir)
|
||||
@@ -2178,8 +2690,9 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(READLINK, readlink)
|
||||
XX(REALPATH, realpath)
|
||||
XX(CHOWN, chown)
|
||||
XX(FCHOWN, fchown);
|
||||
XX(LCHOWN, lchown);
|
||||
XX(FCHOWN, fchown)
|
||||
XX(LCHOWN, lchown)
|
||||
XX(STATFS, statfs)
|
||||
default:
|
||||
assert(!"bad uv_fs_type");
|
||||
}
|
||||
@@ -2343,8 +2856,10 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
int uv_fs_mkdtemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_MKDTEMP);
|
||||
@@ -2356,6 +2871,21 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_mkstemp(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* tpl,
|
||||
uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_MKSTEMP);
|
||||
err = fs__capture_path(req, tpl, NULL, TRUE);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
@@ -2691,3 +3221,18 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
|
||||
req->fs.time.mtime = mtime;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_STATFS);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
POST;
|
||||
}
|
||||
|
||||
@@ -284,6 +284,8 @@ int uv__getsockpeername(const uv_handle_t* handle,
|
||||
int* namelen,
|
||||
int delayed_error);
|
||||
|
||||
int uv__random_rtlgenrandom(void* buf, size_t buflen);
|
||||
|
||||
|
||||
/*
|
||||
* Process stdio handles.
|
||||
|
||||
@@ -264,8 +264,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
DWORD current_mode = 0;
|
||||
DWORD err = 0;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
|
||||
handle->handle != INVALID_HANDLE_VALUE)
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER)
|
||||
return UV_EINVAL;
|
||||
if (handle->handle != INVALID_HANDLE_VALUE)
|
||||
return UV_EBUSY;
|
||||
|
||||
if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
|
||||
@@ -312,7 +313,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
/* Overlapped pipe. Try to associate with IOCP. */
|
||||
if (CreateIoCompletionPort(pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)handle,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
handle->flags |= UV_HANDLE_EMULATE_IOCP;
|
||||
}
|
||||
@@ -326,6 +327,38 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
static int pipe_alloc_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle =
|
||||
CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC |
|
||||
(firstInstance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0),
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Associate it with IOCP so we can get events. */
|
||||
if (CreateIoCompletionPort(req->pipeHandle,
|
||||
loop->iocp,
|
||||
(ULONG_PTR) handle,
|
||||
0) == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateIoCompletionPort");
|
||||
}
|
||||
|
||||
/* Stash a handle in the server object for use from places such as
|
||||
* getsockname and chmod. As we transfer ownership of these to client
|
||||
* objects, we'll allocate new ones here. */
|
||||
handle->handle = req->pipeHandle;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
|
||||
uv_loop_t* loop;
|
||||
uv_pipe_t* handle;
|
||||
@@ -458,7 +491,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -540,13 +573,10 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
* Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
|
||||
* If this fails then there's already a pipe server for the given pipe name.
|
||||
*/
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
|
||||
FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
if (!pipe_alloc_accept(loop,
|
||||
handle,
|
||||
&handle->pipe.serv.accept_reqs[0],
|
||||
TRUE)) {
|
||||
err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED) {
|
||||
err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
|
||||
@@ -556,15 +586,6 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop,
|
||||
handle,
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle,
|
||||
-1,
|
||||
0)) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
handle->pipe.serv.pending_accepts = NULL;
|
||||
handle->flags |= UV_HANDLE_PIPESERVER;
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
@@ -577,11 +598,6 @@ error:
|
||||
handle->name = NULL;
|
||||
}
|
||||
|
||||
if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
|
||||
handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -827,29 +843,11 @@ static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_pipe_accept_t* req, BOOL firstInstance) {
|
||||
assert(handle->flags & UV_HANDLE_LISTENING);
|
||||
|
||||
if (!firstInstance) {
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
|
||||
req->pipeHandle = CreateNamedPipeW(handle->name,
|
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
|
||||
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
|
||||
PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
|
||||
|
||||
if (req->pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
|
||||
CloseHandle(req->pipeHandle);
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
if (!firstInstance && !pipe_alloc_accept(loop, handle, req, FALSE)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
uv_insert_pending_req(loop, (uv_req_t*) req);
|
||||
handle->reqs_pending++;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(req->pipeHandle != INVALID_HANDLE_VALUE);
|
||||
@@ -904,7 +902,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
uv__free(item);
|
||||
|
||||
} else {
|
||||
pipe_client = (uv_pipe_t*)client;
|
||||
pipe_client = (uv_pipe_t*) client;
|
||||
|
||||
/* Find a connection instance that has been connected, but not yet
|
||||
* accepted. */
|
||||
@@ -925,6 +923,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
server->handle = INVALID_HANDLE_VALUE;
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, server, req, FALSE);
|
||||
}
|
||||
@@ -955,6 +954,10 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (handle->ipc) {
|
||||
return WSAEINVAL;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_LISTENING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
handle->stream.serv.connection_cb = cb;
|
||||
@@ -1131,6 +1134,7 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
} else {
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -1148,15 +1152,9 @@ static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
if (!req->event_handle) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
if (req->wait_handle == INVALID_HANDLE_VALUE) {
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
|
||||
req->event_handle, post_completion_read_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
@@ -1190,8 +1188,16 @@ int uv_pipe_read_start(uv_pipe_t* handle,
|
||||
|
||||
/* 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_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
uv_pipe_queue_read(loop, handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1326,7 +1332,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
req->coalesced = 0;
|
||||
req->event_handle = NULL;
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & (UV_HANDLE_EMULATE_IOCP | UV_HANDLE_BLOCKING_WRITES)) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
|
||||
}
|
||||
req->write_buffer = uv_null_buf_;
|
||||
|
||||
if (nbufs == 0) {
|
||||
@@ -1375,11 +1390,6 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
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 */
|
||||
req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
|
||||
if (!req->u.io.overlapped.hEvent) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
|
||||
result = WriteFile(handle->handle,
|
||||
write_buf.base,
|
||||
write_buf.len,
|
||||
@@ -1388,7 +1398,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
|
||||
if (!result && GetLastError() != ERROR_IO_PENDING) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1399,14 +1410,16 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
/* Request queued by the kernel. */
|
||||
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) !=
|
||||
if (WaitForSingleObject(req->event_handle, INFINITE) !=
|
||||
WAIT_OBJECT_0) {
|
||||
err = GetLastError();
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
handle->reqs_pending++;
|
||||
@@ -1433,12 +1446,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
if (!RegisterWaitForSingleObject(&req->wait_handle,
|
||||
req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
|
||||
req->event_handle, post_completion_write_wait, (void*) req,
|
||||
INFINITE, WT_EXECUTEINWAITTHREAD)) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
@@ -714,7 +714,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
|
||||
/* second pass: copy to UTF-16 environment block */
|
||||
dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
|
||||
if (!dst_copy) {
|
||||
if (dst_copy == NULL && env_len > 0) {
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
env_copy = alloca(env_block_count * sizeof(WCHAR*));
|
||||
@@ -739,7 +739,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
}
|
||||
*ptr_copy = NULL;
|
||||
assert(env_len == (size_t) (ptr - dst_copy));
|
||||
assert(env_len == 0 || env_len == (size_t) (ptr - dst_copy));
|
||||
|
||||
/* sort our (UTF-16) copy */
|
||||
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
|
||||
|
||||
@@ -198,8 +198,10 @@ int uv_try_write(uv_stream_t* stream,
|
||||
int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_WRITABLE)) {
|
||||
return UV_EPIPE;
|
||||
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
|
||||
handle->flags & UV_HANDLE_SHUTTING ||
|
||||
uv__is_closing(handle)) {
|
||||
return UV_ENOTCONN;
|
||||
}
|
||||
|
||||
UV_REQ_INIT(req, UV_SHUTDOWN);
|
||||
@@ -207,6 +209,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
req->cb = cb;
|
||||
|
||||
handle->flags &= ~UV_HANDLE_WRITABLE;
|
||||
handle->flags |= UV_HANDLE_SHUTTING;
|
||||
handle->stream.conn.shutdown_req = req;
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
@@ -251,7 +251,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
@@ -268,7 +268,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UnregisterWait(handle->read_req.wait_handle);
|
||||
handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle != NULL) {
|
||||
CloseHandle(handle->read_req.event_handle);
|
||||
handle->read_req.event_handle = NULL;
|
||||
}
|
||||
@@ -428,6 +428,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -466,7 +467,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
|
||||
closesocket(accept_socket);
|
||||
/* Destroy the event handle */
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
CloseHandle(req->u.io.overlapped.hEvent);
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
}
|
||||
@@ -509,7 +510,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
assert(req->event_handle);
|
||||
assert(req->event_handle != NULL);
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
}
|
||||
|
||||
@@ -549,6 +550,21 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
struct linger l = { 1, 0 };
|
||||
|
||||
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l)))
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
uv_close((uv_handle_t*) handle, close_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
unsigned int i, simultaneous_accepts;
|
||||
uv_tcp_accept_t* req;
|
||||
@@ -597,8 +613,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
|
||||
: uv_simultaneous_server_accepts;
|
||||
|
||||
if(!handle->tcp.serv.accept_reqs) {
|
||||
handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
|
||||
if (handle->tcp.serv.accept_reqs == NULL) {
|
||||
handle->tcp.serv.accept_reqs =
|
||||
uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
|
||||
if (!handle->tcp.serv.accept_reqs) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
@@ -613,7 +629,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
} else {
|
||||
@@ -722,9 +738,9 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
!handle->read_req.event_handle) {
|
||||
handle->read_req.event_handle == NULL) {
|
||||
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!handle->read_req.event_handle) {
|
||||
if (handle->read_req.event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
}
|
||||
@@ -847,7 +863,7 @@ int uv_tcp_write(uv_loop_t* loop,
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
|
||||
req->event_handle = CreateEvent(NULL, 0, 0, NULL);
|
||||
if (!req->event_handle) {
|
||||
if (req->event_handle == NULL) {
|
||||
uv_fatal_error(GetLastError(), "CreateEvent");
|
||||
}
|
||||
req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
|
||||
@@ -1065,7 +1081,7 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
UnregisterWait(req->wait_handle);
|
||||
req->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (req->event_handle) {
|
||||
if (req->event_handle != NULL) {
|
||||
CloseHandle(req->event_handle);
|
||||
req->event_handle = NULL;
|
||||
}
|
||||
|
||||
+318
-198
@@ -46,14 +46,16 @@
|
||||
|
||||
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
||||
|
||||
#define ANSI_NORMAL 0x00
|
||||
#define ANSI_ESCAPE_SEEN 0x02
|
||||
#define ANSI_CSI 0x04
|
||||
#define ANSI_ST_CONTROL 0x08
|
||||
#define ANSI_IGNORE 0x10
|
||||
#define ANSI_IN_ARG 0x20
|
||||
#define ANSI_IN_STRING 0x40
|
||||
#define ANSI_BACKSLASH_SEEN 0x80
|
||||
#define ANSI_NORMAL 0x0000
|
||||
#define ANSI_ESCAPE_SEEN 0x0002
|
||||
#define ANSI_CSI 0x0004
|
||||
#define ANSI_ST_CONTROL 0x0008
|
||||
#define ANSI_IGNORE 0x0010
|
||||
#define ANSI_IN_ARG 0x0020
|
||||
#define ANSI_IN_STRING 0x0040
|
||||
#define ANSI_BACKSLASH_SEEN 0x0080
|
||||
#define ANSI_EXTENSION 0x0100
|
||||
#define ANSI_DECSCUSR 0x0200
|
||||
|
||||
#define MAX_INPUT_BUFFER_LENGTH 8192
|
||||
#define MAX_CONSOLE_CHAR 8192
|
||||
@@ -62,7 +64,12 @@
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
#define CURSOR_SIZE_SMALL 25
|
||||
#define CURSOR_SIZE_LARGE 100
|
||||
|
||||
static void uv_tty_capture_initial_style(
|
||||
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
|
||||
CONSOLE_CURSOR_INFO* cursor_info);
|
||||
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
static int uv__cancel_read_console(uv_tty_t* handle);
|
||||
|
||||
@@ -120,6 +127,8 @@ static int uv_tty_virtual_width = -1;
|
||||
static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
|
||||
static int uv__tty_console_height = -1;
|
||||
static int uv__tty_console_width = -1;
|
||||
static HANDLE uv__tty_console_resized = INVALID_HANDLE_VALUE;
|
||||
static uv_mutex_t uv__tty_console_resize_mutex;
|
||||
|
||||
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
|
||||
static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
||||
@@ -129,6 +138,8 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
||||
LONG idChild,
|
||||
DWORD dwEventThread,
|
||||
DWORD dwmsEventTime);
|
||||
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param);
|
||||
static void uv__tty_console_signal_resize(void);
|
||||
|
||||
/* We use a semaphore rather than a mutex or critical section because in some
|
||||
cases (uv__cancel_read_console) we need take the lock in the main thread and
|
||||
@@ -145,13 +156,11 @@ static char uv_tty_default_fg_bright = 0;
|
||||
static char uv_tty_default_bg_bright = 0;
|
||||
static char uv_tty_default_inverse = 0;
|
||||
|
||||
typedef enum {
|
||||
UV_SUPPORTED,
|
||||
UV_UNCHECKED,
|
||||
UV_UNSUPPORTED
|
||||
} uv_vtermstate_t;
|
||||
static CONSOLE_CURSOR_INFO uv_tty_default_cursor_info;
|
||||
|
||||
/* Determine whether or not ANSI support is enabled. */
|
||||
static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
|
||||
static BOOL uv__need_check_vterm_state = TRUE;
|
||||
static uv_tty_vtermstate_t uv__vterm_state = UV_TTY_UNSUPPORTED;
|
||||
static void uv__determine_vterm_state(HANDLE handle);
|
||||
|
||||
void uv_console_init(void) {
|
||||
@@ -165,9 +174,15 @@ void uv_console_init(void) {
|
||||
0,
|
||||
0);
|
||||
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
uv_mutex_init(&uv__tty_console_resize_mutex);
|
||||
if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
|
||||
uv__tty_console_width = sb_info.dwSize.X;
|
||||
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,6 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
DWORD NumberOfEvents;
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
CONSOLE_CURSOR_INFO cursor_info;
|
||||
(void)unused;
|
||||
|
||||
uv__once_init();
|
||||
@@ -209,15 +225,20 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Obtain the cursor info with the output handle. */
|
||||
if (!GetConsoleCursorInfo(handle, &cursor_info)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* 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)
|
||||
if (uv__need_check_vterm_state)
|
||||
uv__determine_vterm_state(handle);
|
||||
|
||||
/* Remember the original console text attributes. */
|
||||
uv_tty_capture_initial_style(&screen_buffer_info);
|
||||
/* Remember the original console text attributes and cursor info. */
|
||||
uv_tty_capture_initial_style(&screen_buffer_info, &cursor_info);
|
||||
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
@@ -268,7 +289,9 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
/* Set the default console text attributes based on how the console was
|
||||
* configured when libuv started.
|
||||
*/
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
static void uv_tty_capture_initial_style(
|
||||
CONSOLE_SCREEN_BUFFER_INFO* screen_buffer_info,
|
||||
CONSOLE_CURSOR_INFO* cursor_info) {
|
||||
static int style_captured = 0;
|
||||
|
||||
/* Only do this once.
|
||||
@@ -277,7 +300,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
return;
|
||||
|
||||
/* Save raw win32 attributes. */
|
||||
uv_tty_default_text_attributes = info->wAttributes;
|
||||
uv_tty_default_text_attributes = screen_buffer_info->wAttributes;
|
||||
|
||||
/* Convert black text on black background to use white text. */
|
||||
if (uv_tty_default_text_attributes == 0)
|
||||
@@ -317,6 +340,9 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
|
||||
uv_tty_default_inverse = 1;
|
||||
|
||||
/* Save the cursor size and the cursor state. */
|
||||
uv_tty_default_cursor_info = *cursor_info;
|
||||
|
||||
style_captured = 1;
|
||||
}
|
||||
|
||||
@@ -728,6 +754,12 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
}
|
||||
records_left--;
|
||||
|
||||
/* We might be not subscribed to EVENT_CONSOLE_LAYOUT or we might be
|
||||
* running under some TTY emulator that does not send those events. */
|
||||
if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
|
||||
uv__tty_console_signal_resize();
|
||||
}
|
||||
|
||||
/* Ignore other events that are not key events. */
|
||||
if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
|
||||
continue;
|
||||
@@ -1218,7 +1250,7 @@ static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
|
||||
static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
const COORD origin = {0, 0};
|
||||
const WORD char_attrs = uv_tty_default_text_attributes;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
DWORD count, written;
|
||||
|
||||
if (*error != ERROR_SUCCESS) {
|
||||
@@ -1239,12 +1271,12 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
|
||||
/* Clear the screen buffer. */
|
||||
retry:
|
||||
if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
if (!GetConsoleScreenBufferInfo(handle->handle, &screen_buffer_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
count = info.dwSize.X * info.dwSize.Y;
|
||||
count = screen_buffer_info.dwSize.X * screen_buffer_info.dwSize.Y;
|
||||
|
||||
if (!(FillConsoleOutputCharacterW(handle->handle,
|
||||
L'\x20',
|
||||
@@ -1267,7 +1299,13 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
|
||||
|
||||
/* Move the virtual window up to the top. */
|
||||
uv_tty_virtual_offset = 0;
|
||||
uv_tty_update_virtual_window(&info);
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
/* Reset the cursor size and the cursor state. */
|
||||
if (!SetConsoleCursorInfo(handle->handle, &uv_tty_default_cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1606,6 +1644,31 @@ static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv_tty_set_cursor_shape(uv_tty_t* handle, int style, DWORD* error) {
|
||||
CONSOLE_CURSOR_INFO cursor_info;
|
||||
|
||||
if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (style == 0) {
|
||||
cursor_info.dwSize = uv_tty_default_cursor_info.dwSize;
|
||||
} else if (style <= 2) {
|
||||
cursor_info.dwSize = CURSOR_SIZE_LARGE;
|
||||
} else {
|
||||
cursor_info.dwSize = CURSOR_SIZE_SMALL;
|
||||
}
|
||||
|
||||
if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
|
||||
*error = GetLastError();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
@@ -1613,28 +1676,16 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
/* 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;
|
||||
unsigned int i, len, max_len, pos;
|
||||
int allocate = 0;
|
||||
unsigned int i;
|
||||
|
||||
#define FLUSH_TEXT() \
|
||||
do { \
|
||||
pos = 0; \
|
||||
do { \
|
||||
len = utf16_buf_used - pos; \
|
||||
if (len > MAX_CONSOLE_CHAR) \
|
||||
len = MAX_CONSOLE_CHAR; \
|
||||
uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
|
||||
pos += len; \
|
||||
} while (pos < utf16_buf_used); \
|
||||
if (allocate) { \
|
||||
uv__free(utf16_buffer); \
|
||||
allocate = 0; \
|
||||
utf16_buffer = utf16_buf; \
|
||||
} \
|
||||
utf16_buf_used = 0; \
|
||||
} while (0)
|
||||
#define FLUSH_TEXT() \
|
||||
do { \
|
||||
if (utf16_buf_used > 0) { \
|
||||
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
|
||||
utf16_buf_used = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE_BUFFER_SPACE(wchars_needed) \
|
||||
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
|
||||
@@ -1645,54 +1696,18 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
|
||||
unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
|
||||
unsigned char previous_eol = handle->tty.wr.previous_eol;
|
||||
unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
|
||||
unsigned short 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. */
|
||||
*error = ERROR_SUCCESS;
|
||||
|
||||
utf16_buffer = utf16_buf;
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
for (i = 0; i < nbufs; i++) {
|
||||
uv_buf_t buf = bufs[i];
|
||||
unsigned int j;
|
||||
|
||||
if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
|
||||
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (utf16_buf_used == 0) {
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
|
||||
allocate = max_len > MAX_CONSOLE_CHAR;
|
||||
if (allocate)
|
||||
utf16_buffer = uv__malloc(max_len);
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
utf16_buffer,
|
||||
utf16_buf_used)) {
|
||||
if (allocate)
|
||||
uv__free(utf16_buffer);
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
FLUSH_TEXT();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < buf.len; j++) {
|
||||
unsigned char c = buf.base[j];
|
||||
|
||||
@@ -1749,7 +1764,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
}
|
||||
|
||||
/* Parse vt100/ansi escape codes */
|
||||
if (ansi_parser_state == ANSI_NORMAL) {
|
||||
if (uv__vterm_state == UV_TTY_SUPPORTED) {
|
||||
/* Pass through escape codes if conhost supports them. */
|
||||
} else if (ansi_parser_state == ANSI_NORMAL) {
|
||||
switch (utf8_codepoint) {
|
||||
case '\033':
|
||||
ansi_parser_state = ANSI_ESCAPE_SEEN;
|
||||
@@ -1795,7 +1812,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
case '8':
|
||||
case '8':
|
||||
/* Restore the cursor position and text attributes */
|
||||
FLUSH_TEXT();
|
||||
uv_tty_restore_state(handle, 1, error);
|
||||
@@ -1813,121 +1830,193 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
} else if (ansi_parser_state == ANSI_IGNORE) {
|
||||
/* We're ignoring this command. Stop only on command character. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
}
|
||||
continue;
|
||||
|
||||
} else if (ansi_parser_state == ANSI_DECSCUSR) {
|
||||
/* So far we've the sequence `ESC [ arg space`, and we're waiting for
|
||||
* the final command byte. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
/* Command byte */
|
||||
if (utf8_codepoint == 'q') {
|
||||
/* Change the cursor shape */
|
||||
int style = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
if (style >= 0 && style <= 6) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_shape(handle, style, error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
}
|
||||
/* Unexpected character, but sequence hasn't ended yet. Ignore the rest
|
||||
* of the sequence. */
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
|
||||
} else if (ansi_parser_state & ANSI_CSI) {
|
||||
if (!(ansi_parser_state & ANSI_IGNORE)) {
|
||||
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
|
||||
/* Parsing a numerical argument */
|
||||
/* So far we've seen `ESC [`, and we may or may not have already parsed
|
||||
* some of the arguments that follow. */
|
||||
|
||||
if (!(ansi_parser_state & ANSI_IN_ARG)) {
|
||||
/* We were not currently parsing a number */
|
||||
|
||||
/* 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
ansi_parser_state |= ANSI_IN_ARG;
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) utf8_codepoint - '0';
|
||||
continue;
|
||||
} else {
|
||||
/* We were already parsing a number. Parse next digit. */
|
||||
uint32_t value = 10 *
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
|
||||
|
||||
/* Check for overflow. */
|
||||
if (value > UINT16_MAX) {
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) value + (utf8_codepoint - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == ';') {
|
||||
/* Denotes the end of an argument. */
|
||||
if (ansi_parser_state & ANSI_IN_ARG) {
|
||||
ansi_parser_state &= ~ANSI_IN_ARG;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
|
||||
if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
|
||||
/* Parse a numerical argument. */
|
||||
if (!(ansi_parser_state & ANSI_IN_ARG)) {
|
||||
/* We were not currently parsing a number, add a new one. */
|
||||
/* Check for that there are too many arguments. */
|
||||
if (handle->tty.wr.ansi_csi_argc >=
|
||||
ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
} 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. */
|
||||
ansi_parser_state |= ANSI_IN_ARG;
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) utf8_codepoint - '0';
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
|
||||
(handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
|
||||
int x, y, d;
|
||||
} else {
|
||||
/* We were already parsing a number. Parse next digit. */
|
||||
uint32_t value = 10 *
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
|
||||
|
||||
/* Command byte */
|
||||
/* Check for overflow. */
|
||||
if (value > UINT16_MAX) {
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
|
||||
(unsigned short) value + (utf8_codepoint - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == ';') {
|
||||
/* Denotes the end of an argument. */
|
||||
if (ansi_parser_state & ANSI_IN_ARG) {
|
||||
ansi_parser_state &= ~ANSI_IN_ARG;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* 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;
|
||||
continue;
|
||||
}
|
||||
|
||||
handle->tty.wr.ansi_csi_argc++;
|
||||
handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (utf8_codepoint == '?' &&
|
||||
!(ansi_parser_state & ANSI_IN_ARG) &&
|
||||
!(ansi_parser_state & ANSI_EXTENSION) &&
|
||||
handle->tty.wr.ansi_csi_argc == 0) {
|
||||
/* Pass through '?' 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. */
|
||||
ansi_parser_state |= ANSI_EXTENSION;
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint == ' ' &&
|
||||
!(ansi_parser_state & ANSI_EXTENSION)) {
|
||||
/* We expect a command byte to follow after this space. The only
|
||||
* command that we current support is 'set cursor style'. */
|
||||
ansi_parser_state = ANSI_DECSCUSR;
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
/* Command byte */
|
||||
if (ansi_parser_state & ANSI_EXTENSION) {
|
||||
/* Sequence is `ESC [ ? args command`. */
|
||||
switch (utf8_codepoint) {
|
||||
case 'l':
|
||||
/* Hide the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 0, error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* Show the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 1, error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Sequence is `ESC [ args command`. */
|
||||
int x, y, d;
|
||||
switch (utf8_codepoint) {
|
||||
case 'A':
|
||||
/* cursor up */
|
||||
FLUSH_TEXT();
|
||||
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
y = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
/* cursor down */
|
||||
FLUSH_TEXT();
|
||||
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
y = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, 0, 1, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
/* cursor forward */
|
||||
FLUSH_TEXT();
|
||||
x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
x = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
/* cursor back */
|
||||
FLUSH_TEXT();
|
||||
x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
x = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, x, 1, 0, 1, error);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
/* cursor next line */
|
||||
FLUSH_TEXT();
|
||||
y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
y = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1;
|
||||
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
/* cursor previous line */
|
||||
FLUSH_TEXT();
|
||||
y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
y = -(handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 1);
|
||||
uv_tty_move_caret(handle, 0, 0, y, 1, error);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
/* cursor horizontal move absolute */
|
||||
FLUSH_TEXT();
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0])
|
||||
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
|
||||
uv_tty_move_caret(handle, x, 0, 0, 1, error);
|
||||
break;
|
||||
@@ -1936,9 +2025,11 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'f':
|
||||
/* cursor move absolute */
|
||||
FLUSH_TEXT();
|
||||
y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
|
||||
y = (handle->tty.wr.ansi_csi_argc >= 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0])
|
||||
? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
|
||||
x = (handle->tty.wr.ansi_csi_argc >= 2 &&
|
||||
handle->tty.wr.ansi_csi_argv[1])
|
||||
? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
|
||||
uv_tty_move_caret(handle, x, 0, y, 0, error);
|
||||
break;
|
||||
@@ -1946,7 +2037,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'J':
|
||||
/* Erase screen */
|
||||
FLUSH_TEXT();
|
||||
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
d = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
if (d >= 0 && d <= 2) {
|
||||
uv_tty_clear(handle, d, 1, error);
|
||||
}
|
||||
@@ -1955,7 +2047,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case 'K':
|
||||
/* Erase line */
|
||||
FLUSH_TEXT();
|
||||
d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
d = handle->tty.wr.ansi_csi_argc
|
||||
? handle->tty.wr.ansi_csi_argv[0] : 0;
|
||||
if (d >= 0 && d <= 2) {
|
||||
uv_tty_clear(handle, d, 0, error);
|
||||
}
|
||||
@@ -1978,41 +2071,17 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
FLUSH_TEXT();
|
||||
uv_tty_restore_state(handle, 0, error);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
/* Hide the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 0, error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
/* Show the cursor */
|
||||
if (handle->tty.wr.ansi_csi_argc == 1 &&
|
||||
handle->tty.wr.ansi_csi_argv[0] == 25) {
|
||||
FLUSH_TEXT();
|
||||
uv_tty_set_cursor_visibility(handle, 1, error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* We don't support commands that use private mode characters or
|
||||
* intermediaries. Ignore the rest of the sequence. */
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Sequence ended - go back to normal state. */
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* We're ignoring this command. Stop only on command character. */
|
||||
if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
|
||||
ansi_parser_state = ANSI_NORMAL;
|
||||
}
|
||||
/* We don't support commands that use private mode characters or
|
||||
* intermediaries. Ignore the rest of the sequence. */
|
||||
ansi_parser_state = ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2264,38 +2333,56 @@ int uv_tty_reset_mode(void) {
|
||||
static void uv__determine_vterm_state(HANDLE handle) {
|
||||
DWORD dwMode = 0;
|
||||
|
||||
uv__need_check_vterm_state = FALSE;
|
||||
if (!GetConsoleMode(handle, &dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(handle, dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
uv__vterm_state = UV_SUPPORTED;
|
||||
uv__vterm_state = UV_TTY_SUPPORTED;
|
||||
}
|
||||
|
||||
static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||
NTSTATUS status;
|
||||
ULONG_PTR conhost_pid;
|
||||
MSG msg;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
|
||||
if (pSetWinEventHook == NULL || pNtQueryInformationProcess == NULL)
|
||||
return 0;
|
||||
|
||||
uv__tty_console_width = sb_info.dwSize.X;
|
||||
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||
status = pNtQueryInformationProcess(GetCurrentProcess(),
|
||||
ProcessConsoleHostProcess,
|
||||
&conhost_pid,
|
||||
sizeof(conhost_pid),
|
||||
NULL);
|
||||
|
||||
if (pSetWinEventHook == NULL)
|
||||
if (!NT_SUCCESS(status)) {
|
||||
/* We couldn't retrieve our console host process, probably because this
|
||||
* is a 32-bit process running on 64-bit Windows. Fall back to receiving
|
||||
* console events from the input stream only. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ensure the PID is a multiple of 4, which is required by SetWinEventHook */
|
||||
conhost_pid &= ~(ULONG_PTR)0x3;
|
||||
|
||||
uv__tty_console_resized = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (uv__tty_console_resized == NULL)
|
||||
return 0;
|
||||
if (QueueUserWorkItem(uv__tty_console_resize_watcher_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION) == 0)
|
||||
return 0;
|
||||
|
||||
if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
|
||||
EVENT_CONSOLE_LAYOUT,
|
||||
NULL,
|
||||
uv__tty_console_resize_event,
|
||||
0,
|
||||
(DWORD)conhost_pid,
|
||||
0,
|
||||
WINEVENT_OUTOFCONTEXT))
|
||||
return 0;
|
||||
@@ -2314,6 +2401,20 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
||||
LONG idChild,
|
||||
DWORD dwEventThread,
|
||||
DWORD dwmsEventTime) {
|
||||
SetEvent(uv__tty_console_resized);
|
||||
}
|
||||
|
||||
static DWORD WINAPI uv__tty_console_resize_watcher_thread(void* param) {
|
||||
for (;;) {
|
||||
/* Make sure to not overwhelm the system with resize events */
|
||||
Sleep(33);
|
||||
WaitForSingleObject(uv__tty_console_resized, INFINITE);
|
||||
uv__tty_console_signal_resize();
|
||||
ResetEvent(uv__tty_console_resized);
|
||||
}
|
||||
}
|
||||
|
||||
static void uv__tty_console_signal_resize(void) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||
int width, height;
|
||||
|
||||
@@ -2323,9 +2424,28 @@ static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
|
||||
width = sb_info.dwSize.X;
|
||||
height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||
|
||||
uv_mutex_lock(&uv__tty_console_resize_mutex);
|
||||
assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
|
||||
if (width != uv__tty_console_width || height != uv__tty_console_height) {
|
||||
uv__tty_console_width = width;
|
||||
uv__tty_console_height = height;
|
||||
uv_mutex_unlock(&uv__tty_console_resize_mutex);
|
||||
uv__signal_dispatch(SIGWINCH);
|
||||
} else {
|
||||
uv_mutex_unlock(&uv__tty_console_resize_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void uv_tty_set_vterm_state(uv_tty_vtermstate_t state) {
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
uv__need_check_vterm_state = FALSE;
|
||||
uv__vterm_state = state;
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
int uv_tty_get_vterm_state(uv_tty_vtermstate_t* state) {
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
*state = uv__vterm_state;
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -702,6 +702,112 @@ int uv__udp_set_membership6(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static int uv__udp_set_source_membership4(uv_udp_t* handle,
|
||||
const struct sockaddr_in* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in* source_addr,
|
||||
uv_membership membership) {
|
||||
struct ip_mreq_source mreq;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* If the socket is unbound, bind to inaddr_any. */
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip4_any_,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
}
|
||||
|
||||
mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
|
||||
mreq.imr_sourceaddr.s_addr = source_addr->sin_addr.s_addr;
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = IP_ADD_SOURCE_MEMBERSHIP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = IP_DROP_SOURCE_MEMBERSHIP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->socket,
|
||||
IPPROTO_IP,
|
||||
optname,
|
||||
(char*) &mreq,
|
||||
sizeof(mreq)) == SOCKET_ERROR) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_set_source_membership6(uv_udp_t* handle,
|
||||
const struct sockaddr_in6* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const struct sockaddr_in6* source_addr,
|
||||
uv_membership membership) {
|
||||
struct group_source_req mreq;
|
||||
struct sockaddr_in6 addr6;
|
||||
int optname;
|
||||
int err;
|
||||
|
||||
if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
(const struct sockaddr*) &uv_addr_ip6_any_,
|
||||
sizeof(uv_addr_ip6_any_),
|
||||
UV_UDP_REUSEADDR);
|
||||
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
|
||||
if (interface_addr != NULL) {
|
||||
err = uv_ip6_addr(interface_addr, 0, &addr6);
|
||||
if (err)
|
||||
return err;
|
||||
mreq.gsr_interface = addr6.sin6_scope_id;
|
||||
} else {
|
||||
mreq.gsr_interface = 0;
|
||||
}
|
||||
|
||||
memcpy(&mreq.gsr_group, multicast_addr, sizeof(mreq.gsr_group));
|
||||
memcpy(&mreq.gsr_source, source_addr, sizeof(mreq.gsr_source));
|
||||
|
||||
if (membership == UV_JOIN_GROUP)
|
||||
optname = MCAST_JOIN_SOURCE_GROUP;
|
||||
else if (membership == UV_LEAVE_GROUP)
|
||||
optname = MCAST_LEAVE_SOURCE_GROUP;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setsockopt(handle->socket,
|
||||
IPPROTO_IPV6,
|
||||
optname,
|
||||
(char*) &mreq,
|
||||
sizeof(mreq)) == SOCKET_ERROR) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
@@ -718,6 +824,50 @@ int uv_udp_set_membership(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_source_membership(uv_udp_t* handle,
|
||||
const char* multicast_addr,
|
||||
const char* interface_addr,
|
||||
const char* source_addr,
|
||||
uv_membership membership) {
|
||||
int err;
|
||||
struct sockaddr_storage mcast_addr;
|
||||
struct sockaddr_in* mcast_addr4;
|
||||
struct sockaddr_in6* mcast_addr6;
|
||||
struct sockaddr_storage src_addr;
|
||||
struct sockaddr_in* src_addr4;
|
||||
struct sockaddr_in6* src_addr6;
|
||||
|
||||
mcast_addr4 = (struct sockaddr_in*)&mcast_addr;
|
||||
mcast_addr6 = (struct sockaddr_in6*)&mcast_addr;
|
||||
src_addr4 = (struct sockaddr_in*)&src_addr;
|
||||
src_addr6 = (struct sockaddr_in6*)&src_addr;
|
||||
|
||||
err = uv_ip4_addr(multicast_addr, 0, mcast_addr4);
|
||||
if (err) {
|
||||
err = uv_ip6_addr(multicast_addr, 0, mcast_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
err = uv_ip6_addr(source_addr, 0, src_addr6);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership6(handle,
|
||||
mcast_addr6,
|
||||
interface_addr,
|
||||
src_addr6,
|
||||
membership);
|
||||
}
|
||||
|
||||
err = uv_ip4_addr(source_addr, 0, src_addr4);
|
||||
if (err)
|
||||
return err;
|
||||
return uv__udp_set_source_membership4(handle,
|
||||
mcast_addr4,
|
||||
interface_addr,
|
||||
src_addr4,
|
||||
membership);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
|
||||
struct sockaddr_storage addr_st;
|
||||
struct sockaddr_in* addr4;
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
/* Maximum environment variable size, including the terminating null */
|
||||
#define MAX_ENV_VAR_LENGTH 32767
|
||||
|
||||
/* A RtlGenRandom() by any other name... */
|
||||
extern BOOLEAN NTAPI SystemFunction036(PVOID Buffer, ULONG BufferLength);
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
static CRITICAL_SECTION process_title_lock;
|
||||
@@ -721,17 +724,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||
}
|
||||
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
|
||||
|
||||
static int is_windows_version_or_greater(DWORD os_major,
|
||||
DWORD os_minor,
|
||||
WORD service_pack_major,
|
||||
@@ -1171,18 +1163,18 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
|
||||
|
||||
int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
wchar_t path[MAX_PATH + 1];
|
||||
wchar_t path[MAX_PATH + 2];
|
||||
DWORD bufsize;
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
len = GetTempPathW(MAX_PATH + 1, path);
|
||||
len = GetTempPathW(ARRAY_SIZE(path), path);
|
||||
|
||||
if (len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (len > MAX_PATH + 1) {
|
||||
} else if (len > ARRAY_SIZE(path)) {
|
||||
/* This should not be possible */
|
||||
return UV_EIO;
|
||||
}
|
||||
@@ -1325,7 +1317,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
(*utf16)[bufsize] = '\0';
|
||||
(*utf16)[bufsize] = L'\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1397,6 +1389,77 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
wchar_t* env;
|
||||
wchar_t* penv;
|
||||
int i, cnt;
|
||||
uv_env_item_t* envitem;
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
|
||||
env = GetEnvironmentStringsW();
|
||||
if (env == NULL)
|
||||
return 0;
|
||||
|
||||
for (penv = env, i = 0; *penv != L'\0'; penv += wcslen(penv) + 1, i++);
|
||||
|
||||
*envitems = uv__calloc(i, sizeof(**envitems));
|
||||
if (envitems == NULL) {
|
||||
FreeEnvironmentStringsW(env);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
penv = env;
|
||||
cnt = 0;
|
||||
|
||||
while (*penv != L'\0' && cnt < i) {
|
||||
char* buf;
|
||||
char* ptr;
|
||||
|
||||
if (uv__convert_utf16_to_utf8(penv, -1, &buf) != 0)
|
||||
goto fail;
|
||||
|
||||
/* Using buf + 1 here because we know that `buf` has length at least 1,
|
||||
* and some special environment variables on Windows start with a = sign. */
|
||||
ptr = strchr(buf + 1, '=');
|
||||
if (ptr == NULL) {
|
||||
uv__free(buf);
|
||||
goto do_continue;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
envitem = &(*envitems)[cnt];
|
||||
envitem->name = buf;
|
||||
envitem->value = ptr + 1;
|
||||
|
||||
cnt++;
|
||||
|
||||
do_continue:
|
||||
penv += wcslen(penv) + 1;
|
||||
}
|
||||
|
||||
FreeEnvironmentStringsW(env);
|
||||
|
||||
*count = cnt;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
FreeEnvironmentStringsW(env);
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
envitem = &(*envitems)[cnt];
|
||||
uv__free(envitem->name);
|
||||
}
|
||||
uv__free(*envitems);
|
||||
|
||||
*envitems = NULL;
|
||||
*count = 0;
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
wchar_t var[MAX_ENV_VAR_LENGTH];
|
||||
wchar_t* name_w;
|
||||
@@ -1412,17 +1475,15 @@ int uv_os_getenv(const char* name, char* buffer, size_t* size) {
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
|
||||
uv__free(name_w);
|
||||
assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
|
||||
|
||||
if (len == 0) {
|
||||
r = GetLastError();
|
||||
|
||||
if (r == ERROR_ENVVAR_NOT_FOUND)
|
||||
return UV_ENOENT;
|
||||
|
||||
return uv_translate_sys_error(r);
|
||||
if (r != ERROR_SUCCESS)
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
/* Check how much space we need */
|
||||
@@ -1802,3 +1863,17 @@ int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv__random_rtlgenrandom(void* buf, size_t buflen) {
|
||||
if (buflen == 0)
|
||||
return 0;
|
||||
|
||||
if (SystemFunction036(buf, buflen) == FALSE)
|
||||
return UV_EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_sleep(unsigned int msec) {
|
||||
Sleep(msec);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ sNtSetInformationFile pNtSetInformationFile;
|
||||
sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
@@ -106,6 +107,13 @@ void uv_winapi_init(void) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
pNtQueryInformationProcess = (sNtQueryInformationProcess) GetProcAddress(
|
||||
ntdll_module,
|
||||
"NtQueryInformationProcess");
|
||||
if (pNtQueryInformationProcess == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
@@ -126,5 +134,4 @@ void uv_winapi_init(void) {
|
||||
pSetWinEventHook = (sSetWinEventHook)
|
||||
GetProcAddress(user32_module, "SetWinEventHook");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4109,7 +4109,7 @@
|
||||
#endif
|
||||
|
||||
/* from winternl.h */
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32__)
|
||||
#define __UNICODE_STRING_DEFINED
|
||||
#endif
|
||||
typedef struct _UNICODE_STRING {
|
||||
@@ -4444,6 +4444,10 @@ typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||
# define SystemProcessorPerformanceInformation 8
|
||||
#endif
|
||||
|
||||
#ifndef ProcessConsoleHostProcess
|
||||
# define ProcessConsoleHostProcess 49
|
||||
#endif
|
||||
|
||||
#ifndef FILE_DEVICE_FILE_SYSTEM
|
||||
# define FILE_DEVICE_FILE_SYSTEM 0x00000009
|
||||
#endif
|
||||
@@ -4586,6 +4590,13 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
|
||||
BOOLEAN RestartScan
|
||||
);
|
||||
|
||||
typedef NTSTATUS (NTAPI *sNtQueryInformationProcess)
|
||||
(HANDLE ProcessHandle,
|
||||
UINT ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
ULONG Length,
|
||||
PULONG ReturnLength);
|
||||
|
||||
/*
|
||||
* Kernel32 headers
|
||||
*/
|
||||
@@ -4727,6 +4738,7 @@ extern sNtSetInformationFile pNtSetInformationFile;
|
||||
extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
extern sNtQueryInformationProcess pNtQueryInformationProcess;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
|
||||
@@ -74,11 +74,6 @@ BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
|
||||
}
|
||||
|
||||
|
||||
static int error_means_no_support(DWORD error) {
|
||||
return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
|
||||
error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
|
||||
}
|
||||
|
||||
|
||||
void uv_winsock_init(void) {
|
||||
WSADATA wsa_data;
|
||||
@@ -105,50 +100,36 @@ void uv_winsock_init(void) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Detect non-IFS LSPs */
|
||||
/* Try to detect non-IFS LSPs */
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 1;
|
||||
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
if (dummy != INVALID_SOCKET) {
|
||||
opt_len = (int) sizeof protocol_info;
|
||||
if (getsockopt(dummy,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &protocol_info,
|
||||
&opt_len) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "getsockopt");
|
||||
|
||||
if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 1;
|
||||
|
||||
if (closesocket(dummy) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
|
||||
} else if (!error_means_no_support(WSAGetLastError())) {
|
||||
/* Any error other than "socket type not supported" is fatal. */
|
||||
uv_fatal_error(WSAGetLastError(), "socket");
|
||||
&opt_len) == 0) {
|
||||
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
||||
uv_tcp_non_ifs_lsp_ipv4 = 0;
|
||||
}
|
||||
closesocket(dummy);
|
||||
}
|
||||
|
||||
/* Detect IPV6 support and non-IFS LSPs */
|
||||
/* Try to detect IPV6 support and non-IFS LSPs */
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 1;
|
||||
dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
if (dummy != INVALID_SOCKET) {
|
||||
opt_len = (int) sizeof protocol_info;
|
||||
if (getsockopt(dummy,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &protocol_info,
|
||||
&opt_len) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "getsockopt");
|
||||
|
||||
if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 1;
|
||||
|
||||
if (closesocket(dummy) == SOCKET_ERROR)
|
||||
uv_fatal_error(WSAGetLastError(), "closesocket");
|
||||
|
||||
} else if (!error_means_no_support(WSAGetLastError())) {
|
||||
/* Any error other than "socket type not supported" is fatal. */
|
||||
uv_fatal_error(WSAGetLastError(), "socket");
|
||||
&opt_len) == 0) {
|
||||
if (protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES)
|
||||
uv_tcp_non_ifs_lsp_ipv6 = 0;
|
||||
}
|
||||
closesocket(dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,14 @@
|
||||
# define SIO_BASE_HANDLE 0x48000022
|
||||
#endif
|
||||
|
||||
#ifndef MCAST_JOIN_SOURCE_GROUP
|
||||
# define MCAST_JOIN_SOURCE_GROUP 45
|
||||
#endif
|
||||
|
||||
#ifndef MCAST_LEAVE_SOURCE_GROUP
|
||||
# define MCAST_LEAVE_SOURCE_GROUP 46
|
||||
#endif
|
||||
|
||||
/*
|
||||
* TDI defines that are only in the DDK.
|
||||
* We only need receive flags so far.
|
||||
|
||||
Reference in New Issue
Block a user