mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
Update libuv to 1.30.1 release
This commit is contained in:
@@ -195,6 +195,7 @@ typedef enum {
|
||||
/* Handle types. */
|
||||
typedef struct uv_loop_s uv_loop_t;
|
||||
typedef struct uv_handle_s uv_handle_t;
|
||||
typedef struct uv_dir_s uv_dir_t;
|
||||
typedef struct uv_stream_s uv_stream_t;
|
||||
typedef struct uv_tcp_s uv_tcp_t;
|
||||
typedef struct uv_udp_s uv_udp_t;
|
||||
@@ -227,6 +228,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
@@ -363,7 +365,10 @@ typedef enum {
|
||||
UV_EXTERN int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
UV_EXTERN const char* uv_strerror(int err);
|
||||
UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen);
|
||||
|
||||
UV_EXTERN const char* uv_err_name(int err);
|
||||
UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen);
|
||||
|
||||
|
||||
#define UV_REQ_FIELDS \
|
||||
@@ -619,7 +624,11 @@ UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
|
||||
UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int flags);
|
||||
UV_EXTERN int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr);
|
||||
|
||||
UV_EXTERN int uv_udp_getpeername(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
@@ -946,12 +955,23 @@ enum uv_process_flags {
|
||||
* the child's process handle.
|
||||
*/
|
||||
UV_PROCESS_DETACHED = (1 << 3),
|
||||
/*
|
||||
* Hide the subprocess window that would normally be created. This option is
|
||||
* only meaningful on Windows systems. On Unix it is silently ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE = (1 << 4),
|
||||
/*
|
||||
* Hide the subprocess console window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE = (1 << 4)
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5),
|
||||
/*
|
||||
* Hide the subprocess GUI window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1027,6 +1047,16 @@ struct uv_passwd_s {
|
||||
char* homedir;
|
||||
};
|
||||
|
||||
struct uv_utsname_s {
|
||||
char sysname[256];
|
||||
char release[256];
|
||||
char version[256];
|
||||
char machine[256];
|
||||
/* This struct does not contain the nodename and domainname fields present in
|
||||
the utsname type. domainname is a GNU extension. Both fields are referred
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@@ -1049,12 +1079,18 @@ UV_EXTERN int uv_set_process_title(const char* title);
|
||||
UV_EXTERN int uv_resident_set_memory(size_t* rss);
|
||||
UV_EXTERN int uv_uptime(double* uptime);
|
||||
UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
|
||||
UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd);
|
||||
|
||||
typedef struct {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
} uv_timeval_t;
|
||||
|
||||
typedef struct {
|
||||
int64_t tv_sec;
|
||||
int32_t tv_usec;
|
||||
} uv_timeval64_t;
|
||||
|
||||
typedef struct {
|
||||
uv_timeval_t ru_utime; /* user CPU time used */
|
||||
uv_timeval_t ru_stime; /* system CPU time used */
|
||||
@@ -1083,6 +1119,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
|
||||
UV_EXTERN uv_pid_t uv_os_getpid(void);
|
||||
UV_EXTERN uv_pid_t uv_os_getppid(void);
|
||||
|
||||
#define UV_PRIORITY_LOW 19
|
||||
#define UV_PRIORITY_BELOW_NORMAL 10
|
||||
#define UV_PRIORITY_NORMAL 0
|
||||
#define UV_PRIORITY_ABOVE_NORMAL -7
|
||||
#define UV_PRIORITY_HIGH -14
|
||||
#define UV_PRIORITY_HIGHEST -20
|
||||
|
||||
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
|
||||
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
|
||||
|
||||
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
|
||||
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
|
||||
|
||||
@@ -1095,8 +1141,21 @@ 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);
|
||||
|
||||
#ifdef MAXHOSTNAMELEN
|
||||
# define UV_MAXHOSTNAMESIZE (MAXHOSTNAMELEN + 1)
|
||||
#else
|
||||
/*
|
||||
Fallback for the maximum hostname size, including the null terminator. The
|
||||
Windows gethostname() documentation states that 256 bytes will always be
|
||||
large enough to hold the null-terminated hostname.
|
||||
*/
|
||||
# define UV_MAXHOSTNAMESIZE 256
|
||||
#endif
|
||||
|
||||
UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
|
||||
|
||||
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
|
||||
|
||||
|
||||
typedef enum {
|
||||
UV_FS_UNKNOWN = -1,
|
||||
@@ -1128,11 +1187,21 @@ typedef enum {
|
||||
UV_FS_READLINK,
|
||||
UV_FS_CHOWN,
|
||||
UV_FS_FCHOWN,
|
||||
UV_FS_LCHOWN,
|
||||
UV_FS_REALPATH,
|
||||
UV_FS_COPYFILE
|
||||
UV_FS_COPYFILE,
|
||||
UV_FS_LCHOWN,
|
||||
UV_FS_OPENDIR,
|
||||
UV_FS_READDIR,
|
||||
UV_FS_CLOSEDIR
|
||||
} uv_fs_type;
|
||||
|
||||
struct uv_dir_s {
|
||||
uv_dirent_t* dirents;
|
||||
size_t nentries;
|
||||
void* reserved[4];
|
||||
UV_DIR_PRIVATE_FIELDS
|
||||
};
|
||||
|
||||
/* uv_fs_t is a subclass of uv_req_t. */
|
||||
struct uv_fs_s {
|
||||
UV_REQ_FIELDS
|
||||
@@ -1225,6 +1294,18 @@ UV_EXTERN int uv_fs_scandir(uv_loop_t* loop,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req,
|
||||
uv_dirent_t* ent);
|
||||
UV_EXTERN int uv_fs_opendir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_readdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_closedir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_stat(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
@@ -1467,6 +1548,7 @@ UV_EXTERN int uv_chdir(const char* dir);
|
||||
|
||||
UV_EXTERN uint64_t uv_get_free_memory(void);
|
||||
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);
|
||||
|
||||
@@ -1520,9 +1602,29 @@ UV_EXTERN void uv_key_delete(uv_key_t* key);
|
||||
UV_EXTERN void* uv_key_get(uv_key_t* key);
|
||||
UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
|
||||
|
||||
UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv);
|
||||
|
||||
typedef void (*uv_thread_cb)(void* arg);
|
||||
|
||||
UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
|
||||
|
||||
typedef enum {
|
||||
UV_THREAD_NO_FLAGS = 0x00,
|
||||
UV_THREAD_HAS_STACK_SIZE = 0x01
|
||||
} uv_thread_create_flags;
|
||||
|
||||
struct uv_thread_options_s {
|
||||
unsigned int flags;
|
||||
size_t stack_size;
|
||||
/* More fields may be added at any time. */
|
||||
};
|
||||
|
||||
typedef struct uv_thread_options_s uv_thread_options_t;
|
||||
|
||||
UV_EXTERN int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
uv_thread_cb entry,
|
||||
void* arg);
|
||||
UV_EXTERN uv_thread_t uv_thread_self(void);
|
||||
UV_EXTERN int uv_thread_join(uv_thread_t *tid);
|
||||
UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _UV_PTHREAD_BARRIER_
|
||||
#define _UV_PTHREAD_BARRIER_
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#if !defined(__MVS__)
|
||||
#include <semaphore.h> /* sem_t */
|
||||
#endif
|
||||
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
|
||||
#define UV__PTHREAD_BARRIER_FALLBACK 1
|
||||
|
||||
/*
|
||||
* To maintain ABI compatibility with
|
||||
* libuv v1.x struct is padded according
|
||||
* to target platform
|
||||
*/
|
||||
#if defined(__ANDROID__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
sizeof(pthread_cond_t) + \
|
||||
sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#elif defined(__APPLE__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
2 * sizeof(sem_t) + \
|
||||
2 * sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#else
|
||||
# define UV_BARRIER_STRUCT_PADDING 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
unsigned threshold;
|
||||
unsigned in;
|
||||
unsigned out;
|
||||
} _uv_barrier;
|
||||
|
||||
typedef struct {
|
||||
_uv_barrier* b;
|
||||
char _pad[UV_BARRIER_STRUCT_PADDING];
|
||||
} pthread_barrier_t;
|
||||
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count);
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier);
|
||||
int pthread_barrier_destroy(pthread_barrier_t *barrier);
|
||||
|
||||
#endif /* _UV_PTHREAD_BARRIER_ */
|
||||
@@ -31,13 +31,14 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
|
||||
|
||||
#include <termios.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#if !defined(__MVS__)
|
||||
#include <semaphore.h>
|
||||
#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
@@ -46,8 +47,6 @@
|
||||
|
||||
#if defined(__linux__)
|
||||
# include "uv/linux.h"
|
||||
#elif defined(__PASE__)
|
||||
# include "uv/posix.h"
|
||||
#elif defined(__APPLE__)
|
||||
# include "uv/darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
@@ -56,12 +55,13 @@
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "uv/bsd.h"
|
||||
#elif defined(__CYGWIN__) || defined(__MSYS__)
|
||||
#elif defined(__PASE__) || \
|
||||
defined(__CYGWIN__) || \
|
||||
defined(__MSYS__) || \
|
||||
defined(__GNU__)
|
||||
# include "uv/posix.h"
|
||||
#elif defined(__HAIKU__)
|
||||
# include "uv/posix.h"
|
||||
#endif
|
||||
|
||||
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
|
||||
# include "uv/pthread-barrier.h"
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
@@ -130,8 +130,30 @@ typedef pthread_rwlock_t uv_rwlock_t;
|
||||
typedef UV_PLATFORM_SEM_T uv_sem_t;
|
||||
typedef pthread_cond_t uv_cond_t;
|
||||
typedef pthread_key_t uv_key_t;
|
||||
typedef pthread_barrier_t uv_barrier_t;
|
||||
|
||||
/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
|
||||
#if defined(_AIX) || \
|
||||
defined(__OpenBSD__) || \
|
||||
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */
|
||||
struct _uv_barrier {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
unsigned threshold;
|
||||
unsigned in;
|
||||
unsigned out;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct _uv_barrier* b;
|
||||
# if defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
/* TODO(bnoordhuis) Remove padding in v2. */
|
||||
char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)];
|
||||
# endif
|
||||
} uv_barrier_t;
|
||||
#else
|
||||
typedef pthread_barrier_t uv_barrier_t;
|
||||
#endif
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
typedef gid_t uv_gid_t;
|
||||
@@ -139,6 +161,9 @@ typedef uid_t uv_uid_t;
|
||||
|
||||
typedef struct dirent uv__dirent_t;
|
||||
|
||||
#define UV_DIR_PRIVATE_FIELDS \
|
||||
DIR* dir;
|
||||
|
||||
#if defined(DT_UNKNOWN)
|
||||
# define HAVE_DIRENT_TYPES
|
||||
# if defined(DT_REG)
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 21
|
||||
#define UV_VERSION_PATCH 0
|
||||
#define UV_VERSION_MINOR 30
|
||||
#define UV_VERSION_PATCH 1
|
||||
#define UV_VERSION_IS_RELEASE 1
|
||||
#define UV_VERSION_SUFFIX ""
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
# define SSIZE_MAX INTPTR_MAX
|
||||
# define _SSIZE_T_
|
||||
# define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
@@ -82,6 +83,14 @@ typedef struct pollfd {
|
||||
#define SIGKILL 9
|
||||
#define SIGWINCH 28
|
||||
|
||||
/* Redefine NSIG to take SIGWINCH into consideration */
|
||||
#if defined(NSIG) && NSIG <= SIGWINCH
|
||||
# undef NSIG
|
||||
#endif
|
||||
#ifndef NSIG
|
||||
# define NSIG SIGWINCH + 1
|
||||
#endif
|
||||
|
||||
/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like
|
||||
* platforms. However MinGW doesn't define it, so we do. */
|
||||
#ifndef SIGABRT_COMPAT
|
||||
@@ -293,6 +302,11 @@ typedef struct uv__dirent_s {
|
||||
char d_name[1];
|
||||
} uv__dirent_t;
|
||||
|
||||
#define UV_DIR_PRIVATE_FIELDS \
|
||||
HANDLE dir_handle; \
|
||||
WIN32_FIND_DATAW find_data; \
|
||||
BOOL need_find_call;
|
||||
|
||||
#define HAVE_DIRENT_TYPES
|
||||
#define UV__DT_DIR UV_DIRENT_DIR
|
||||
#define UV__DT_FILE UV_DIRENT_FILE
|
||||
@@ -309,8 +323,6 @@ typedef struct {
|
||||
char* errmsg;
|
||||
} uv_lib_t;
|
||||
|
||||
RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
|
||||
#define UV_LOOP_PRIVATE_FIELDS \
|
||||
/* The loop's I/O completion port */ \
|
||||
HANDLE iocp; \
|
||||
@@ -322,8 +334,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
uv_req_t* pending_reqs_tail; \
|
||||
/* Head of a single-linked list of closed handles */ \
|
||||
uv_handle_t* endgame_handles; \
|
||||
/* The head of the timers tree */ \
|
||||
struct uv_timer_tree_s timers; \
|
||||
/* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */ \
|
||||
void* timer_heap; \
|
||||
/* Lists of active loop (prepare / check / idle) watchers */ \
|
||||
uv_prepare_t* prepare_handles; \
|
||||
uv_check_t* check_handles; \
|
||||
@@ -530,8 +542,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
unsigned char events;
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
RB_ENTRY(uv_timer_s) tree_entry; \
|
||||
uint64_t due; \
|
||||
void* heap_node[3]; \
|
||||
int unused; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id; \
|
||||
uv_timer_cb timer_cb;
|
||||
|
||||
@@ -22,13 +22,21 @@
|
||||
#include "uv.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win/internal.h"
|
||||
#include "win/handle-inl.h"
|
||||
#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h))
|
||||
#else
|
||||
#include "unix/internal.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct poll_ctx {
|
||||
uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
|
||||
uv_fs_poll_t* parent_handle;
|
||||
int busy_polling;
|
||||
unsigned int interval;
|
||||
uint64_t start_time;
|
||||
@@ -37,6 +45,7 @@ struct poll_ctx {
|
||||
uv_timer_t timer_handle;
|
||||
uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
|
||||
uv_stat_t statbuf;
|
||||
struct poll_ctx* previous; /* context from previous start()..stop() period */
|
||||
char path[1]; /* variable length */
|
||||
};
|
||||
|
||||
@@ -50,6 +59,7 @@ static uv_stat_t zero_statbuf;
|
||||
|
||||
int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
|
||||
handle->poll_ctx = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -63,7 +73,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
if (uv_is_active((uv_handle_t*)handle))
|
||||
return 0;
|
||||
|
||||
loop = handle->loop;
|
||||
@@ -84,13 +94,15 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
|
||||
ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
|
||||
uv__handle_unref(&ctx->timer_handle);
|
||||
|
||||
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (handle->poll_ctx != NULL)
|
||||
ctx->previous = (struct poll_ctx*)handle->poll_ctx;
|
||||
handle->poll_ctx = ctx;
|
||||
uv__handle_start(handle);
|
||||
|
||||
@@ -105,19 +117,17 @@ error:
|
||||
int uv_fs_poll_stop(uv_fs_poll_t* handle) {
|
||||
struct poll_ctx* ctx;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
if (!uv_is_active((uv_handle_t*)handle))
|
||||
return 0;
|
||||
|
||||
ctx = (struct poll_ctx*)handle->poll_ctx;
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->parent_handle != NULL);
|
||||
ctx->parent_handle = NULL;
|
||||
handle->poll_ctx = NULL;
|
||||
assert(ctx->parent_handle == handle);
|
||||
|
||||
/* Close the timer if it's active. If it's inactive, there's a stat request
|
||||
* in progress and poll_cb will take care of the cleanup.
|
||||
*/
|
||||
if (uv__is_active(&ctx->timer_handle))
|
||||
if (uv_is_active((uv_handle_t*)&ctx->timer_handle))
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
|
||||
uv__handle_stop(handle);
|
||||
@@ -130,7 +140,7 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
|
||||
struct poll_ctx* ctx;
|
||||
size_t required_len;
|
||||
|
||||
if (!uv__is_active(handle)) {
|
||||
if (!uv_is_active((uv_handle_t*)handle)) {
|
||||
*size = 0;
|
||||
return UV_EINVAL;
|
||||
}
|
||||
@@ -154,6 +164,9 @@ int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
|
||||
|
||||
void uv__fs_poll_close(uv_fs_poll_t* handle) {
|
||||
uv_fs_poll_stop(handle);
|
||||
|
||||
if (handle->poll_ctx == NULL)
|
||||
uv__make_close_pending((uv_handle_t*)handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -174,14 +187,13 @@ static void poll_cb(uv_fs_t* req) {
|
||||
uv_stat_t* statbuf;
|
||||
struct poll_ctx* ctx;
|
||||
uint64_t interval;
|
||||
uv_fs_poll_t* handle;
|
||||
|
||||
ctx = container_of(req, struct poll_ctx, fs_req);
|
||||
handle = ctx->parent_handle;
|
||||
|
||||
if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
uv_fs_req_cleanup(req);
|
||||
return;
|
||||
}
|
||||
if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle))
|
||||
goto out;
|
||||
|
||||
if (req->result != 0) {
|
||||
if (ctx->busy_polling != req->result) {
|
||||
@@ -206,7 +218,7 @@ static void poll_cb(uv_fs_t* req) {
|
||||
out:
|
||||
uv_fs_req_cleanup(req);
|
||||
|
||||
if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */
|
||||
if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) {
|
||||
uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
|
||||
return;
|
||||
}
|
||||
@@ -220,8 +232,27 @@ out:
|
||||
}
|
||||
|
||||
|
||||
static void timer_close_cb(uv_handle_t* handle) {
|
||||
uv__free(container_of(handle, struct poll_ctx, timer_handle));
|
||||
static void timer_close_cb(uv_handle_t* timer) {
|
||||
struct poll_ctx* ctx;
|
||||
struct poll_ctx* it;
|
||||
struct poll_ctx* last;
|
||||
uv_fs_poll_t* handle;
|
||||
|
||||
ctx = container_of(timer, struct poll_ctx, timer_handle);
|
||||
handle = ctx->parent_handle;
|
||||
if (ctx == handle->poll_ctx) {
|
||||
handle->poll_ctx = ctx->previous;
|
||||
if (handle->poll_ctx == NULL && uv__is_closing(handle))
|
||||
uv__make_close_pending((uv_handle_t*)handle);
|
||||
} else {
|
||||
for (last = (struct poll_ctx*)handle->poll_ctx, it = last->previous;
|
||||
it != ctx;
|
||||
last = it, it = it->previous) {
|
||||
assert(last->previous != NULL);
|
||||
}
|
||||
last->previous = ctx->previous;
|
||||
}
|
||||
uv__free(ctx);
|
||||
}
|
||||
|
||||
|
||||
@@ -249,7 +280,7 @@ static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
|
||||
#include "win/handle-inl.h"
|
||||
|
||||
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
291
wpiutil/src/main/native/libuv/src/idna.cpp
Normal file
291
wpiutil/src/main/native/libuv/src/idna.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Derived from https://github.com/bnoordhuis/punycode
|
||||
* but updated to support IDNA 2008.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "idna.h"
|
||||
#include <string.h>
|
||||
|
||||
static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
const char* pe,
|
||||
unsigned a) {
|
||||
unsigned b;
|
||||
unsigned c;
|
||||
unsigned d;
|
||||
unsigned min;
|
||||
|
||||
if (a > 0xF7)
|
||||
return -1;
|
||||
|
||||
switch (*p - pe) {
|
||||
default:
|
||||
if (a > 0xEF) {
|
||||
min = 0x10000;
|
||||
a = a & 7;
|
||||
b = (unsigned char) *(*p)++;
|
||||
c = (unsigned char) *(*p)++;
|
||||
d = (unsigned char) *(*p)++;
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case 2:
|
||||
if (a > 0xDF) {
|
||||
min = 0x800;
|
||||
b = 0x80 | (a & 15);
|
||||
c = (unsigned char) *(*p)++;
|
||||
d = (unsigned char) *(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case 1:
|
||||
if (a > 0xBF) {
|
||||
min = 0x80;
|
||||
b = 0x80;
|
||||
c = 0x80 | (a & 31);
|
||||
d = (unsigned char) *(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
return -1; /* Invalid continuation byte. */
|
||||
}
|
||||
|
||||
if (0x80 != (0xC0 & (b ^ c ^ d)))
|
||||
return -1; /* Invalid sequence. */
|
||||
|
||||
b &= 63;
|
||||
c &= 63;
|
||||
d &= 63;
|
||||
a = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
|
||||
if (a < min)
|
||||
return -1; /* Overlong sequence. */
|
||||
|
||||
if (a > 0x10FFFF)
|
||||
return -1; /* Four-byte sequence > U+10FFFF. */
|
||||
|
||||
if (a >= 0xD800 && a <= 0xDFFF)
|
||||
return -1; /* Surrogate pair. */
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
unsigned a;
|
||||
|
||||
a = (unsigned char) *(*p)++;
|
||||
|
||||
if (a < 128)
|
||||
return a; /* ASCII, common case. */
|
||||
|
||||
return uv__utf8_decode1_slow(p, pe, a);
|
||||
}
|
||||
|
||||
#define foreach_codepoint(c, p, pe) \
|
||||
for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
|
||||
|
||||
static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
char** d, char* de) {
|
||||
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const char* ss;
|
||||
unsigned c = 0;
|
||||
unsigned h;
|
||||
unsigned k;
|
||||
unsigned n;
|
||||
unsigned m;
|
||||
unsigned q;
|
||||
unsigned t;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned bias;
|
||||
unsigned delta;
|
||||
unsigned todo;
|
||||
int first;
|
||||
|
||||
h = 0;
|
||||
ss = s;
|
||||
todo = 0;
|
||||
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c < 128)
|
||||
h++;
|
||||
else if (c == (unsigned) -1)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
todo++;
|
||||
}
|
||||
|
||||
if (todo > 0) {
|
||||
if (*d < de) *(*d)++ = 'x';
|
||||
if (*d < de) *(*d)++ = 'n';
|
||||
if (*d < de) *(*d)++ = '-';
|
||||
if (*d < de) *(*d)++ = '-';
|
||||
}
|
||||
|
||||
x = 0;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c > 127)
|
||||
continue;
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = c;
|
||||
|
||||
if (++x == h)
|
||||
break; /* Visited all ASCII characters. */
|
||||
}
|
||||
|
||||
if (todo == 0)
|
||||
return h;
|
||||
|
||||
/* Only write separator when we've written ASCII characters first. */
|
||||
if (h > 0)
|
||||
if (*d < de)
|
||||
*(*d)++ = '-';
|
||||
|
||||
n = 128;
|
||||
bias = 72;
|
||||
delta = 0;
|
||||
first = 1;
|
||||
|
||||
while (todo > 0) {
|
||||
m = -1;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se)
|
||||
if (c >= n)
|
||||
if (c < m)
|
||||
m = c;
|
||||
|
||||
x = m - n;
|
||||
y = h + 1;
|
||||
|
||||
if (x > ~delta / y)
|
||||
return UV_E2BIG; /* Overflow. */
|
||||
|
||||
delta += x * y;
|
||||
n = m;
|
||||
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c < n)
|
||||
if (++delta == 0)
|
||||
return UV_E2BIG; /* Overflow. */
|
||||
|
||||
if (c != n)
|
||||
continue;
|
||||
|
||||
for (k = 36, q = delta; /* empty */; k += 36) {
|
||||
t = 1;
|
||||
|
||||
if (k > bias)
|
||||
t = k - bias;
|
||||
|
||||
if (t > 26)
|
||||
t = 26;
|
||||
|
||||
if (q < t)
|
||||
break;
|
||||
|
||||
/* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore
|
||||
* 10 <= y <= 35, we can optimize the long division
|
||||
* into a table-based reciprocal multiplication.
|
||||
*/
|
||||
x = q - t;
|
||||
y = 36 - t; /* 10 <= y <= 35 since 1 <= t <= 26. */
|
||||
q = x / y;
|
||||
t = t + x % y; /* 1 <= t <= 35 because of y. */
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = alphabet[t];
|
||||
}
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = alphabet[q];
|
||||
|
||||
delta /= 2;
|
||||
|
||||
if (first) {
|
||||
delta /= 350;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
/* No overflow check is needed because |delta| was just
|
||||
* divided by 2 and |delta+delta >= delta + delta/h|.
|
||||
*/
|
||||
h++;
|
||||
delta += delta / h;
|
||||
|
||||
for (bias = 0; delta > 35 * 26 / 2; bias += 36)
|
||||
delta /= 35;
|
||||
|
||||
bias += 36 * delta / (delta + 38);
|
||||
delta = 0;
|
||||
todo--;
|
||||
}
|
||||
|
||||
delta++;
|
||||
n++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef foreach_codepoint
|
||||
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
const char* si;
|
||||
const char* st;
|
||||
unsigned c;
|
||||
char* ds;
|
||||
int rc;
|
||||
|
||||
ds = d;
|
||||
|
||||
for (si = s; si < se; /* empty */) {
|
||||
st = si;
|
||||
c = uv__utf8_decode1(&si, se);
|
||||
|
||||
if (c != '.')
|
||||
if (c != 0x3002) /* 。 */
|
||||
if (c != 0xFF0E) /* . */
|
||||
if (c != 0xFF61) /* 。 */
|
||||
continue;
|
||||
|
||||
rc = uv__idna_toascii_label(s, st, &d, de);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (d < de)
|
||||
*d++ = '.';
|
||||
|
||||
s = si;
|
||||
}
|
||||
|
||||
if (s < se) {
|
||||
rc = uv__idna_toascii_label(s, se, &d, de);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (d < de)
|
||||
*d++ = '\0';
|
||||
|
||||
return d - ds; /* Number of bytes written. */
|
||||
}
|
||||
31
wpiutil/src/main/native/libuv/src/idna.h
Normal file
31
wpiutil/src/main/native/libuv/src/idna.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SRC_IDNA_H_
|
||||
#define UV_SRC_IDNA_H_
|
||||
|
||||
/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error.
|
||||
* |p| is updated on success _and_ error, i.e., bad multi-byte sequences are
|
||||
* skipped in their entirety, not just the first bad byte.
|
||||
*/
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe);
|
||||
|
||||
/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0
|
||||
* is the number of bytes written to |d|, including the trailing nul byte.
|
||||
* A return value < 0 is a libuv error code. |s| and |d| can not overlap.
|
||||
*/
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
|
||||
|
||||
#endif /* UV_SRC_IDNA_H_ */
|
||||
@@ -63,8 +63,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
|
||||
if (l <= 0 || (size_t) l >= size) {
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strncpy(dst, tmp, size);
|
||||
dst[size - 1] = '\0';
|
||||
uv__strscpy(dst, tmp, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -146,14 +145,8 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
|
||||
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((size_t)(tp - tmp) > size) {
|
||||
if (UV_E2BIG == uv__strscpy(dst, tmp, size))
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strcpy(dst, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
17
wpiutil/src/main/native/libuv/src/strscpy.cpp
Normal file
17
wpiutil/src/main/native/libuv/src/strscpy.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "strscpy.h"
|
||||
#include <limits.h> /* SSIZE_MAX */
|
||||
|
||||
ssize_t uv__strscpy(char* d, const char* s, size_t n) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if ('\0' == (d[i] = s[i]))
|
||||
return i > SSIZE_MAX ? (ssize_t) UV_E2BIG : (ssize_t) i;
|
||||
|
||||
if (i == 0)
|
||||
return 0;
|
||||
|
||||
d[--i] = '\0';
|
||||
|
||||
return UV_E2BIG;
|
||||
}
|
||||
18
wpiutil/src/main/native/libuv/src/strscpy.h
Normal file
18
wpiutil/src/main/native/libuv/src/strscpy.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef UV_STRSCPY_H_
|
||||
#define UV_STRSCPY_H_
|
||||
|
||||
/* Include uv.h for its definitions of size_t and ssize_t.
|
||||
* size_t can be obtained directly from <stddef.h> but ssize_t requires
|
||||
* some hoop jumping on Windows that I didn't want to duplicate here.
|
||||
*/
|
||||
#include "uv.h"
|
||||
|
||||
/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
|
||||
* the result, except when |n==0|. Returns the number of bytes copied
|
||||
* or UV_E2BIG if |d| is too small.
|
||||
*
|
||||
* See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html
|
||||
*/
|
||||
ssize_t uv__strscpy(char* d, const char* s, size_t n);
|
||||
|
||||
#endif /* UV_STRSCPY_H_ */
|
||||
@@ -31,18 +31,24 @@
|
||||
#pragma warning(disable: 6001 6011)
|
||||
#endif
|
||||
|
||||
#define MAX_THREADPOOL_SIZE 128
|
||||
#define MAX_THREADPOOL_SIZE 1024
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uv_cond_t cond;
|
||||
static uv_mutex_t mutex;
|
||||
static unsigned int idle_threads;
|
||||
static unsigned int slow_io_work_running;
|
||||
static unsigned int nthreads;
|
||||
static uv_thread_t* threads;
|
||||
static uv_thread_t default_threads[4];
|
||||
static QUEUE exit_message;
|
||||
static QUEUE wq;
|
||||
static QUEUE run_slow_work_message;
|
||||
static QUEUE slow_io_pending_wq;
|
||||
|
||||
static unsigned int slow_work_thread_threshold(void) {
|
||||
return (nthreads + 1) / 2;
|
||||
}
|
||||
|
||||
static void uv__cancelled(struct uv__work* w) {
|
||||
abort();
|
||||
@@ -55,34 +61,67 @@ static void uv__cancelled(struct uv__work* w) {
|
||||
static void worker(void* arg) {
|
||||
struct uv__work* w;
|
||||
QUEUE* q;
|
||||
int is_slow_work;
|
||||
|
||||
uv_sem_post((uv_sem_t*) arg);
|
||||
arg = NULL;
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
for (;;) {
|
||||
uv_mutex_lock(&mutex);
|
||||
/* `mutex` should always be locked at this point. */
|
||||
|
||||
while (QUEUE_EMPTY(&wq)) {
|
||||
/* Keep waiting while either no work is present or only slow I/O
|
||||
and we're at the threshold for that. */
|
||||
while (QUEUE_EMPTY(&wq) ||
|
||||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
|
||||
QUEUE_NEXT(&run_slow_work_message) == &wq &&
|
||||
slow_io_work_running >= slow_work_thread_threshold())) {
|
||||
idle_threads += 1;
|
||||
uv_cond_wait(&cond, &mutex);
|
||||
idle_threads -= 1;
|
||||
}
|
||||
|
||||
q = QUEUE_HEAD(&wq);
|
||||
|
||||
if (q == &exit_message)
|
||||
if (q == &exit_message) {
|
||||
uv_cond_signal(&cond);
|
||||
else {
|
||||
uv_mutex_unlock(&mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
|
||||
|
||||
is_slow_work = 0;
|
||||
if (q == &run_slow_work_message) {
|
||||
/* If we're at the slow I/O threshold, re-schedule until after all
|
||||
other work in the queue is done. */
|
||||
if (slow_io_work_running >= slow_work_thread_threshold()) {
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we encountered a request to run slow I/O work but there is none
|
||||
to run, that means it's cancelled => Start over. */
|
||||
if (QUEUE_EMPTY(&slow_io_pending_wq))
|
||||
continue;
|
||||
|
||||
is_slow_work = 1;
|
||||
slow_io_work_running++;
|
||||
|
||||
q = QUEUE_HEAD(&slow_io_pending_wq);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
|
||||
executing. */
|
||||
QUEUE_INIT(q);
|
||||
|
||||
/* If there is more slow I/O work, schedule it to be run as well. */
|
||||
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
|
||||
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
}
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (q == &exit_message)
|
||||
break;
|
||||
|
||||
w = QUEUE_DATA(q, struct uv__work, wq);
|
||||
w->work(w);
|
||||
|
||||
@@ -92,12 +131,32 @@ static void worker(void* arg) {
|
||||
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
|
||||
uv_async_send(&w->loop->wq_async);
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
|
||||
/* Lock `mutex` since that is expected at the start of the next
|
||||
* iteration. */
|
||||
uv_mutex_lock(&mutex);
|
||||
if (is_slow_work) {
|
||||
/* `slow_io_work_running` is protected by `mutex`. */
|
||||
slow_io_work_running--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void post(QUEUE* q) {
|
||||
static void post(QUEUE* q, enum uv__work_kind kind) {
|
||||
uv_mutex_lock(&mutex);
|
||||
if (kind == UV__WORK_SLOW_IO) {
|
||||
/* Insert into a separate queue. */
|
||||
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
|
||||
if (!QUEUE_EMPTY(&run_slow_work_message)) {
|
||||
/* Running slow I/O tasks is already scheduled => Nothing to do here.
|
||||
The worker that runs said other task will schedule this one as well. */
|
||||
uv_mutex_unlock(&mutex);
|
||||
return;
|
||||
}
|
||||
q = &run_slow_work_message;
|
||||
}
|
||||
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
@@ -112,7 +171,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
|
||||
if (nthreads == 0)
|
||||
return;
|
||||
|
||||
post(&exit_message);
|
||||
post(&exit_message, UV__WORK_CPU);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
if (uv_thread_join(threads + i))
|
||||
@@ -160,6 +219,8 @@ static void init_threads(void) {
|
||||
abort();
|
||||
|
||||
QUEUE_INIT(&wq);
|
||||
QUEUE_INIT(&slow_io_pending_wq);
|
||||
QUEUE_INIT(&run_slow_work_message);
|
||||
|
||||
if (uv_sem_init(&sem, 0))
|
||||
abort();
|
||||
@@ -198,13 +259,14 @@ static void init_once(void) {
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work* w,
|
||||
enum uv__work_kind kind,
|
||||
void (*work)(struct uv__work* w),
|
||||
void (*done)(struct uv__work* w, int status)) {
|
||||
uv_once(&once, init_once);
|
||||
w->loop = loop;
|
||||
w->work = work;
|
||||
w->done = done;
|
||||
post(&w->wq);
|
||||
post(&w->wq, kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +350,11 @@ int uv_queue_work(uv_loop_t* loop,
|
||||
req->loop = loop;
|
||||
req->work_cb = work_cb;
|
||||
req->after_work_cb = after_work_cb;
|
||||
uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_CPU,
|
||||
uv__queue_work,
|
||||
uv__queue_done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,22 @@
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "uv-common.h"
|
||||
#include "heap-inl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
static struct heap *timer_heap(const uv_loop_t* loop) {
|
||||
#ifdef _WIN32
|
||||
return (struct heap*) loop->timer_heap;
|
||||
#else
|
||||
return (struct heap*) &loop->timer_heap;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int timer_less_than(const struct heap_node* ha,
|
||||
const struct heap_node* hb) {
|
||||
const uv_timer_t* a;
|
||||
@@ -81,7 +90,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
heap_insert((struct heap*) &handle->loop->timer_heap,
|
||||
heap_insert(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_start(handle);
|
||||
@@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
heap_remove((struct heap*) &handle->loop->timer_heap,
|
||||
heap_remove(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_stop(handle);
|
||||
@@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
const uv_timer_t* handle;
|
||||
uint64_t diff;
|
||||
|
||||
heap_node = heap_min((const struct heap*) &loop->timer_heap);
|
||||
heap_node = heap_min(timer_heap(loop));
|
||||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
@@ -143,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
if (diff > INT_MAX)
|
||||
diff = INT_MAX;
|
||||
|
||||
return diff;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +161,7 @@ void uv__run_timers(uv_loop_t* loop) {
|
||||
uv_timer_t* handle;
|
||||
|
||||
for (;;) {
|
||||
heap_node = heap_min((struct heap*) &loop->timer_heap);
|
||||
heap_node = heap_min(timer_heap(loop));
|
||||
if (heap_node == NULL)
|
||||
break;
|
||||
|
||||
@@ -61,14 +61,43 @@ int uv_async_send(uv_async_t* handle) {
|
||||
if (ACCESS_ONCE(int, handle->pending) != 0)
|
||||
return 0;
|
||||
|
||||
if (cmpxchgi(&handle->pending, 0, 1) == 0)
|
||||
uv__async_send(handle->loop);
|
||||
/* Tell the other thread we're busy with the handle. */
|
||||
if (cmpxchgi(&handle->pending, 0, 1) != 0)
|
||||
return 0;
|
||||
|
||||
/* Wake up the other thread's event loop. */
|
||||
uv__async_send(handle->loop);
|
||||
|
||||
/* Tell the other thread we're done. */
|
||||
if (cmpxchgi(&handle->pending, 1, 2) != 1)
|
||||
abort();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Only call this from the event loop thread. */
|
||||
static int uv__async_spin(uv_async_t* handle) {
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
/* rc=0 -- handle is not pending.
|
||||
* rc=1 -- handle is pending, other thread is still working with it.
|
||||
* rc=2 -- handle is pending, other thread is done.
|
||||
*/
|
||||
rc = cmpxchgi(&handle->pending, 2, 0);
|
||||
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
|
||||
/* Other thread is busy with this handle, spin until it's done. */
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__async_close(uv_async_t* handle) {
|
||||
uv__async_spin(handle);
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
@@ -109,8 +138,8 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
|
||||
if (cmpxchgi(&h->pending, 1, 0) == 0)
|
||||
continue;
|
||||
if (0 == uv__async_spin(h))
|
||||
continue; /* Not pending. */
|
||||
|
||||
if (h->async_cb == NULL)
|
||||
continue;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#endif
|
||||
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
|
||||
UV_UNUSED(static void cpu_relax(void));
|
||||
|
||||
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
|
||||
@@ -49,43 +48,7 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
else
|
||||
return op4;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_uint(ptr, oldval, newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
long out;
|
||||
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
||||
: "=a" (out), "+m" (*(volatile long*) ptr)
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && defined(__xlC__)
|
||||
const long out = (*(volatile int*) ptr);
|
||||
# if defined(__64BIT__)
|
||||
__compare_and_swaplp(ptr, &oldval, newval);
|
||||
# else
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
# endif /* if defined(__64BIT__) */
|
||||
return out;
|
||||
#elif defined (__MVS__)
|
||||
#ifdef _LP64
|
||||
unsigned long long op4;
|
||||
if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
|
||||
(unsigned long long*) ptr, *ptr, &op4))
|
||||
#else
|
||||
unsigned long op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
(unsigned int*) ptr, *ptr, &op4))
|
||||
#endif
|
||||
return oldval;
|
||||
else
|
||||
return op4;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_ulong(ptr, oldval, newval);
|
||||
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#define IFF_RUNNING IFF_LINK
|
||||
#endif
|
||||
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
@@ -45,20 +49,18 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (exclude_type == UV__EXCLUDE_IFPHYS)
|
||||
return (ent->ifa_addr->sa_family != AF_LINK);
|
||||
#endif
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \
|
||||
defined(__HAIKU__)
|
||||
/*
|
||||
* On BSD getifaddrs returns information related to the raw underlying
|
||||
* devices. We're not interested in this information.
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
return 1;
|
||||
#elif defined(__NetBSD__)
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
if (ent->ifa_addr->sa_family != PF_INET &&
|
||||
ent->ifa_addr->sa_family != PF_INET6)
|
||||
return 1;
|
||||
#elif defined(__OpenBSD__)
|
||||
if (ent->ifa_addr->sa_family != PF_INET)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -69,11 +71,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
@@ -81,8 +84,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
*addresses =
|
||||
(uv_interface_address_t*)uv__malloc(*count * sizeof(**addresses));
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure the memory is initiallized to zero using calloc() */
|
||||
*addresses = (uv_interface_address_t*)uv__calloc(*count, sizeof(**addresses));
|
||||
|
||||
if (*addresses == NULL) {
|
||||
freeifaddrs(addrs);
|
||||
@@ -114,6 +122,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address++;
|
||||
}
|
||||
|
||||
#if !(defined(__CYGWIN__) || defined(__MSYS__))
|
||||
/* Fill in physical addresses for each interface */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
|
||||
@@ -123,17 +132,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
#else
|
||||
struct sockaddr_dl* sa_addr;
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
#endif
|
||||
}
|
||||
address++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
|
||||
@@ -40,9 +40,10 @@
|
||||
#include <sys/uio.h> /* writev */
|
||||
#include <sys/resource.h> /* getrusage */
|
||||
#include <pwd.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef __sun
|
||||
# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
|
||||
# include <sys/filio.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/wait.h>
|
||||
@@ -87,13 +88,8 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__MVS__)
|
||||
#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
|
||||
#endif
|
||||
|
||||
/* Fallback for the maximum hostname length */
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
# define MAXHOSTNAMELEN 256
|
||||
#if defined(__linux__)
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
static int uv__run_pending(uv_loop_t* loop);
|
||||
@@ -116,7 +112,7 @@ uint64_t uv_hrtime(void) {
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
assert(!uv__is_closing(handle));
|
||||
|
||||
handle->flags |= UV_CLOSING;
|
||||
handle->flags |= UV_HANDLE_CLOSING;
|
||||
handle->close_cb = close_cb;
|
||||
|
||||
switch (handle->type) {
|
||||
@@ -170,7 +166,9 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
|
||||
case UV_FS_POLL:
|
||||
uv__fs_poll_close((uv_fs_poll_t*)handle);
|
||||
break;
|
||||
/* Poll handles use file system requests, and one of them may still be
|
||||
* running. The poll code will call uv__make_close_pending() for us. */
|
||||
return;
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv__signal_close((uv_signal_t*) handle);
|
||||
@@ -214,8 +212,8 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
|
||||
}
|
||||
|
||||
void uv__make_close_pending(uv_handle_t* handle) {
|
||||
assert(handle->flags & UV_CLOSING);
|
||||
assert(!(handle->flags & UV_CLOSED));
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->next_closing = handle->loop->closing_handles;
|
||||
handle->loop->closing_handles = handle;
|
||||
}
|
||||
@@ -241,15 +239,17 @@ int uv__getiovmax(void) {
|
||||
|
||||
|
||||
static void uv__finish_close(uv_handle_t* handle) {
|
||||
/* Note: while the handle is in the UV_CLOSING state now, it's still possible
|
||||
* for it to be active in the sense that uv__is_active() returns true.
|
||||
/* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
|
||||
* possible for it to be active in the sense that uv__is_active() returns
|
||||
* true.
|
||||
*
|
||||
* A good example is when the user calls uv_shutdown(), immediately followed
|
||||
* by uv_close(). The handle is considered active at this point because the
|
||||
* completion of the shutdown req is still pending.
|
||||
*/
|
||||
assert(handle->flags & UV_CLOSING);
|
||||
assert(!(handle->flags & UV_CLOSED));
|
||||
handle->flags |= UV_CLOSED;
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
switch (handle->type) {
|
||||
case UV_PREPARE:
|
||||
@@ -514,6 +514,43 @@ skip:
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__)
|
||||
extern "C" int close$NOCANCEL(int);
|
||||
#else
|
||||
extern "C" int close$NOCANCEL$UNIX2003(int);
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/* close() on macos has the "interesting" quirk that it fails with EINTR
|
||||
* without closing the file descriptor when a thread is in the cancel state.
|
||||
* That's why libuv calls close$NOCANCEL() instead.
|
||||
*
|
||||
* glibc on linux has a similar issue: close() is a cancellation point and
|
||||
* will unwind the thread when it's in the cancel state. Work around that
|
||||
* by making the system call directly. Musl libc is unaffected.
|
||||
*/
|
||||
int uv__close_nocancel(int fd) {
|
||||
#if defined(__APPLE__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
#if defined(__LP64__)
|
||||
return close$NOCANCEL(fd);
|
||||
#else
|
||||
return close$NOCANCEL$UNIX2003(fd);
|
||||
#endif
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__linux__)
|
||||
return syscall(SYS_close, fd);
|
||||
#else
|
||||
return close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__close_nocheckstdio(int fd) {
|
||||
int saved_errno;
|
||||
int rc;
|
||||
@@ -521,7 +558,7 @@ int uv__close_nocheckstdio(int fd) {
|
||||
assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
|
||||
|
||||
saved_errno = errno;
|
||||
rc = close(fd);
|
||||
rc = uv__close_nocancel(fd);
|
||||
if (rc == -1) {
|
||||
rc = UV__ERR(errno);
|
||||
if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS))
|
||||
@@ -556,7 +593,7 @@ int uv__nonblock_ioctl(int fd, int set) {
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__)
|
||||
#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
|
||||
int uv__cloexec_ioctl(int fd, int set) {
|
||||
int r;
|
||||
|
||||
@@ -634,27 +671,6 @@ int uv__cloexec_fcntl(int fd, int set) {
|
||||
}
|
||||
|
||||
|
||||
/* This function is not execve-safe, there is a race window
|
||||
* between the call to dup() and fcntl(FD_CLOEXEC).
|
||||
*/
|
||||
int uv__dup(int fd) {
|
||||
int err;
|
||||
|
||||
fd = dup(fd);
|
||||
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
struct cmsghdr* cmsg;
|
||||
ssize_t rc;
|
||||
@@ -694,16 +710,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;
|
||||
@@ -910,7 +948,8 @@ void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
|
||||
QUEUE_REMOVE(&w->pending_queue);
|
||||
|
||||
/* Remove stale events for this file descriptor */
|
||||
uv__platform_invalidate_fd(loop, w->fd);
|
||||
if (w->fd != -1)
|
||||
uv__platform_invalidate_fd(loop, w->fd);
|
||||
}
|
||||
|
||||
|
||||
@@ -944,7 +983,7 @@ int uv_getrusage(uv_rusage_t* rusage) {
|
||||
rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
|
||||
rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
|
||||
|
||||
#if !defined(__MVS__)
|
||||
#if !defined(__MVS__) && !defined(__HAIKU__)
|
||||
rusage->ru_maxrss = usage.ru_maxrss;
|
||||
rusage->ru_ixrss = usage.ru_ixrss;
|
||||
rusage->ru_idrss = usage.ru_idrss;
|
||||
@@ -1309,7 +1348,7 @@ int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
instead by creating a large enough buffer and comparing the hostname length
|
||||
to the size input.
|
||||
*/
|
||||
char buf[MAXHOSTNAMELEN + 1];
|
||||
char buf[UV_MAXHOSTNAMESIZE];
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
@@ -1336,6 +1375,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
int uv_open_osfhandle(uv_os_fd_t os_fd) {
|
||||
return os_fd;
|
||||
}
|
||||
|
||||
uv_pid_t uv_os_getpid(void) {
|
||||
return getpid();
|
||||
@@ -1345,3 +1387,123 @@ uv_pid_t uv_os_getpid(void) {
|
||||
uv_pid_t uv_os_getppid(void) {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getpriority(uv_pid_t pid, int* priority) {
|
||||
int r;
|
||||
|
||||
if (priority == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
errno = 0;
|
||||
r = getpriority(PRIO_PROCESS, (int) pid);
|
||||
|
||||
if (r == -1 && errno != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*priority = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
struct utsname buf;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uname(&buf) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#ifdef _AIX
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%s.%s",
|
||||
buf.version,
|
||||
buf.release);
|
||||
if (r >= sizeof(buffer->release)) {
|
||||
r = UV_E2BIG;
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#if defined(_AIX) || defined(__PASE__)
|
||||
r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
|
||||
#else
|
||||
r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
|
||||
#endif
|
||||
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
uv_os_fd_t fd;
|
||||
int r;
|
||||
|
||||
r = uv_fileno(handle, &fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (func(fd, name, &socklen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
struct timeval time;
|
||||
|
||||
if (tv == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (gettimeofday(&time, NULL) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
tv->tv_sec = (int64_t) time.tv_sec;
|
||||
tv->tv_usec = (int32_t) time.tv_usec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ int uv_uptime(double* uptime) {
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
/* FIXME: read /proc/meminfo? */
|
||||
*rss = 0;
|
||||
return UV_ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
@@ -52,3 +52,7 @@ 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. */
|
||||
}
|
||||
|
||||
@@ -33,61 +33,56 @@
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
int (*dynamic_pthread_setname_np)(const char* name);
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int err;
|
||||
|
||||
static int (*dynamic_pthread_setname_np)(const char* name);
|
||||
#if !TARGET_OS_IPHONE
|
||||
static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
static CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
static OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
static void* application_services_handle;
|
||||
static void* core_foundation_handle;
|
||||
static CFBundleRef launch_services_bundle;
|
||||
static CFStringRef* display_name_key;
|
||||
static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
static CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
static CFBundleRef hi_services_bundle;
|
||||
static OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
|
||||
if (core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
if (application_services_handle != NULL) {
|
||||
dlclose(application_services_handle);
|
||||
application_services_handle = NULL;
|
||||
}
|
||||
}
|
||||
#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");
|
||||
|
||||
if (dynamic_pthread_setname_np == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = dynamic_pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__set_process_title(const char* title) {
|
||||
#if TARGET_OS_IPHONE
|
||||
return uv__pthread_setname_np(title);
|
||||
#else
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
void* application_services_handle;
|
||||
void* core_foundation_handle;
|
||||
CFBundleRef launch_services_bundle;
|
||||
CFStringRef* display_name_key;
|
||||
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
CFBundleRef hi_services_bundle;
|
||||
OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
CFTypeRef asn;
|
||||
int err;
|
||||
|
||||
err = UV_ENOENT;
|
||||
#if !TARGET_OS_IPHONE
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
@@ -116,8 +111,6 @@ int uv__set_process_title(const char* title) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
@@ -149,13 +142,14 @@ int uv__set_process_title(const char* title) {
|
||||
"CFBundleGetInfoDictionary");
|
||||
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetMainBundle");
|
||||
|
||||
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
|
||||
goto out;
|
||||
|
||||
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
|
||||
hi_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
|
||||
err = UV_ENOENT;
|
||||
|
||||
if (hi_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -169,42 +163,37 @@ int uv__set_process_title(const char* title) {
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
|
||||
if (pSetApplicationIsDaemon == NULL ||
|
||||
pLSApplicationCheckIn == NULL ||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pSetApplicationIsDaemon(1) != noErr)
|
||||
goto out;
|
||||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
|
||||
/* Check into process manager?! */
|
||||
pLSApplicationCheckIn(-2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
|
||||
err = UV_EINVAL;
|
||||
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
|
||||
asn,
|
||||
*display_name_key,
|
||||
S(title),
|
||||
NULL) != noErr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
return;
|
||||
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
uv__set_process_title_platform_fini();
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
|
||||
@@ -47,15 +47,6 @@
|
||||
# define CP_INTR 4
|
||||
#endif
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
@@ -146,6 +137,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
struct loadavg info;
|
||||
size_t size = sizeof(info);
|
||||
@@ -159,76 +155,6 @@ void uv_loadavg(double avg[3]) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int oid[4];
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
|
||||
oid[0] = CTL_KERN;
|
||||
oid[1] = KERN_PROC;
|
||||
oid[2] = KERN_PROC_ARGS;
|
||||
oid[3] = getpid();
|
||||
|
||||
sysctl(oid,
|
||||
ARRAY_SIZE(oid),
|
||||
NULL,
|
||||
NULL,
|
||||
process_title,
|
||||
strlen(process_title) + 1);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size;
|
||||
|
||||
@@ -43,12 +43,11 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel_) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_PREADV 1
|
||||
@@ -61,12 +60,20 @@
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <copyfile.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__linux__) && !defined(FICLONE)
|
||||
# include <sys/ioctl.h>
|
||||
# define FICLONE _IOW(0x94, 9, int)
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && !defined(_AIX71)
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
|
||||
#define INIT(subtype) \
|
||||
do { \
|
||||
if (req == NULL) \
|
||||
@@ -120,7 +127,11 @@
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
uv__fs_work, \
|
||||
uv__fs_done); \
|
||||
return 0; \
|
||||
} \
|
||||
else { \
|
||||
@@ -131,19 +142,34 @@
|
||||
while (0)
|
||||
|
||||
|
||||
static int uv__fs_close(int fd) {
|
||||
int rc;
|
||||
|
||||
rc = uv__close_nocancel(fd);
|
||||
if (rc == -1)
|
||||
if (errno == EINTR || errno == EINPROGRESS)
|
||||
rc = 0; /* The close is in progress, not an error. */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_fsync(uv_fs_t* req) {
|
||||
#if defined(__APPLE__)
|
||||
/* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
|
||||
* to the drive platters. This is in contrast to Linux's fdatasync and fsync
|
||||
* which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
|
||||
* for flushing buffered data to permanent storage. If F_FULLFSYNC is not
|
||||
* supported by the file system we should fall back to fsync(). This is the
|
||||
* same approach taken by sqlite.
|
||||
* supported by the file system we fall back to F_BARRIERFSYNC or fsync().
|
||||
* This is the same approach taken by sqlite, except sqlite does not issue
|
||||
* an F_BARRIERFSYNC call.
|
||||
*/
|
||||
int r;
|
||||
|
||||
r = fcntl(req->file, F_FULLFSYNC);
|
||||
if (r != 0 && errno == ENOTTY)
|
||||
if (r != 0)
|
||||
r = fcntl(req->file, 85 /* F_BARRIERFSYNC */); /* fsync + barrier */
|
||||
if (r != 0)
|
||||
r = fsync(req->file);
|
||||
return r;
|
||||
#else
|
||||
@@ -165,59 +191,18 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
static int no_utimesat;
|
||||
struct timespec ts[2];
|
||||
struct timeval tv[2];
|
||||
char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
|
||||
int r;
|
||||
|
||||
if (no_utimesat)
|
||||
goto skip;
|
||||
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
|
||||
r = uv__utimesat(req->file, NULL, ts, 0);
|
||||
if (r == 0)
|
||||
return r;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return r;
|
||||
|
||||
no_utimesat = 1;
|
||||
|
||||
skip:
|
||||
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
|
||||
|
||||
r = utimes(path, tv);
|
||||
if (r == 0)
|
||||
return r;
|
||||
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
|
||||
break;
|
||||
/* Fall through. */
|
||||
|
||||
case EACCES:
|
||||
case ENOTDIR:
|
||||
errno = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
@@ -235,13 +220,6 @@ skip:
|
||||
# else
|
||||
return futimes(req->file, tv);
|
||||
# endif
|
||||
#elif defined(_AIX71)
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__MVS__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
@@ -300,21 +278,65 @@ static ssize_t uv__fs_open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static int no_preadv;
|
||||
#endif
|
||||
unsigned int iovmax;
|
||||
ssize_t result;
|
||||
|
||||
#if defined(_AIX)
|
||||
struct stat buf;
|
||||
if(fstat(req->file, &buf))
|
||||
return -1;
|
||||
if(S_ISDIR(buf.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
#endif /* defined(_AIX) */
|
||||
iovmax = uv__getiovmax();
|
||||
if (req->nbufs > iovmax)
|
||||
req->nbufs = iovmax;
|
||||
|
||||
if (req->off < 0) {
|
||||
if (req->nbufs == 1)
|
||||
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
|
||||
@@ -333,25 +355,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
if (no_preadv) retry:
|
||||
# endif
|
||||
{
|
||||
off_t nread;
|
||||
size_t index;
|
||||
|
||||
nread = 0;
|
||||
index = 0;
|
||||
result = 1;
|
||||
do {
|
||||
if (req->bufs[index].len > 0) {
|
||||
result = pread(req->file,
|
||||
req->bufs[index].base,
|
||||
req->bufs[index].len,
|
||||
req->off + nread);
|
||||
if (result > 0)
|
||||
nread += result;
|
||||
}
|
||||
index++;
|
||||
} while (index < req->nbufs && result > 0);
|
||||
if (nread > 0)
|
||||
result = nread;
|
||||
result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
@@ -369,6 +373,25 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
done:
|
||||
/* Early cleanup of bufs allocation, since we're done with it. */
|
||||
if (req->bufs != req->bufsml)
|
||||
uv__free(req->bufs);
|
||||
|
||||
req->bufs = NULL;
|
||||
req->nbufs = 0;
|
||||
|
||||
#ifdef __PASE__
|
||||
/* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */
|
||||
if (result == -1 && errno == EOPNOTSUPP) {
|
||||
struct stat buf;
|
||||
ssize_t rc;
|
||||
rc = fstat(req->file, &buf);
|
||||
if (rc == 0 && S_ISDIR(buf.st_mode)) {
|
||||
errno = EISDIR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -391,7 +414,7 @@ static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_scandir(uv_fs_t* req) {
|
||||
uv__dirent_t **dents;
|
||||
uv__dirent_t** dents;
|
||||
int n;
|
||||
|
||||
dents = NULL;
|
||||
@@ -415,29 +438,127 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) {
|
||||
return n;
|
||||
}
|
||||
|
||||
static int uv__fs_opendir(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
|
||||
dir = (uv_dir_t*)uv__malloc(sizeof(*dir));
|
||||
if (dir == NULL)
|
||||
goto error;
|
||||
|
||||
dir->dir = opendir(req->path);
|
||||
if (dir->dir == NULL)
|
||||
goto error;
|
||||
|
||||
req->ptr = dir;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv__free(dir);
|
||||
req->ptr = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uv__fs_readdir(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
uv_dirent_t* dirent;
|
||||
struct dirent* res;
|
||||
unsigned int dirent_idx;
|
||||
unsigned int i;
|
||||
|
||||
dir = (uv_dir_t*)req->ptr;
|
||||
dirent_idx = 0;
|
||||
|
||||
while (dirent_idx < dir->nentries) {
|
||||
/* readdir() returns NULL on end of directory, as well as on error. errno
|
||||
is used to differentiate between the two conditions. */
|
||||
errno = 0;
|
||||
res = readdir(dir->dir);
|
||||
|
||||
if (res == NULL) {
|
||||
if (errno != 0)
|
||||
goto error;
|
||||
break;
|
||||
}
|
||||
|
||||
if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0)
|
||||
continue;
|
||||
|
||||
dirent = &dir->dirents[dirent_idx];
|
||||
dirent->name = uv__strdup(res->d_name);
|
||||
|
||||
if (dirent->name == NULL)
|
||||
goto error;
|
||||
|
||||
dirent->type = uv__fs_get_dirent_type(res);
|
||||
++dirent_idx;
|
||||
}
|
||||
|
||||
return dirent_idx;
|
||||
|
||||
error:
|
||||
for (i = 0; i < dirent_idx; ++i) {
|
||||
uv__free((char*) dir->dirents[i].name);
|
||||
dir->dirents[i].name = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int uv__fs_closedir(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
|
||||
dir = (uv_dir_t*)req->ptr;
|
||||
|
||||
if (dir->dir != NULL) {
|
||||
closedir(dir->dir);
|
||||
dir->dir = NULL;
|
||||
}
|
||||
|
||||
uv__free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
ssize_t pathmax;
|
||||
|
||||
pathmax = pathconf(path, _PC_PATH_MAX);
|
||||
|
||||
if (pathmax == -1) {
|
||||
#if defined(PATH_MAX)
|
||||
return PATH_MAX;
|
||||
#else
|
||||
#error "PATH_MAX undefined in the current platform"
|
||||
#endif
|
||||
}
|
||||
if (pathmax == -1)
|
||||
pathmax = UV__PATH_MAX;
|
||||
|
||||
return pathmax;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
ssize_t maxlen;
|
||||
ssize_t len;
|
||||
char* buf;
|
||||
char* newbuf;
|
||||
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
buf = (char*)uv__malloc(len + 1);
|
||||
#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;
|
||||
ret = lstat(req->path, &st);
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
if (!S_ISLNK(st.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
maxlen = st.st_size;
|
||||
|
||||
/* According to readlink(2) lstat can report st_size == 0
|
||||
for some symlinks, such as those in /proc or /sys. */
|
||||
if (maxlen == 0)
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#endif
|
||||
|
||||
buf = (char*)uv__malloc(maxlen);
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
@@ -445,17 +566,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
#if defined(__MVS__)
|
||||
len = os390_readlink(req->path, buf, len);
|
||||
len = os390_readlink(req->path, buf, maxlen);
|
||||
#else
|
||||
len = readlink(req->path, buf, len);
|
||||
len = readlink(req->path, buf, maxlen);
|
||||
#endif
|
||||
|
||||
|
||||
if (len == -1) {
|
||||
uv__free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Uncommon case: resize to make room for the trailing nul byte. */
|
||||
if (len == maxlen) {
|
||||
newbuf = (char*)uv__realloc(buf, len + 1);
|
||||
|
||||
if (newbuf == NULL) {
|
||||
uv__free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = newbuf;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
req->ptr = buf;
|
||||
|
||||
@@ -463,9 +595,15 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_realpath(uv_fs_t* req) {
|
||||
ssize_t len;
|
||||
char* buf;
|
||||
|
||||
#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
|
||||
buf = realpath(req->path, NULL);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
#else
|
||||
ssize_t len;
|
||||
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
buf = (char*)uv__malloc(len + 1);
|
||||
|
||||
@@ -478,6 +616,7 @@ static ssize_t uv__fs_realpath(uv_fs_t* req) {
|
||||
uv__free(buf);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
req->ptr = buf;
|
||||
|
||||
@@ -698,10 +837,49 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__sun) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
return utimensat(AT_FDCWD, req->path, ts, 0);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__)
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
return utimes(req->path, tv);
|
||||
#elif defined(_AIX) \
|
||||
&& !defined(_AIX71)
|
||||
struct utimbuf buf;
|
||||
buf.actime = req->atime;
|
||||
buf.modtime = req->mtime;
|
||||
return utime(req->path, &buf); /* TODO use utimes() where available */
|
||||
return utime(req->path, &buf);
|
||||
#elif defined(__MVS__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
atr.att_mtimechg = 1;
|
||||
atr.att_atimechg = 1;
|
||||
atr.att_mtime = req->mtime;
|
||||
atr.att_atime = req->atime;
|
||||
return __lchattr((char*) req->path, &atr, sizeof(atr));
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -739,25 +917,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
|
||||
if (no_pwritev) retry:
|
||||
# endif
|
||||
{
|
||||
off_t written;
|
||||
size_t index;
|
||||
|
||||
written = 0;
|
||||
index = 0;
|
||||
r = 0;
|
||||
do {
|
||||
if (req->bufs[index].len > 0) {
|
||||
r = pwrite(req->file,
|
||||
req->bufs[index].base,
|
||||
req->bufs[index].len,
|
||||
req->off + written);
|
||||
if (r > 0)
|
||||
written += r;
|
||||
}
|
||||
index++;
|
||||
} while (index < req->nbufs && r >= 0);
|
||||
if (written > 0)
|
||||
r = written;
|
||||
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
@@ -784,34 +944,11 @@ done:
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
/* On macOS, use the native copyfile(3). */
|
||||
copyfile_flags_t flags;
|
||||
|
||||
flags = COPYFILE_ALL;
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_EXCL)
|
||||
flags |= COPYFILE_EXCL;
|
||||
|
||||
#ifdef COPYFILE_CLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE)
|
||||
flags |= COPYFILE_CLONE;
|
||||
#endif
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
#ifdef COPYFILE_CLONE_FORCE
|
||||
flags |= COPYFILE_CLONE_FORCE;
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
return copyfile(req->path, req->new_path, NULL, flags);
|
||||
#else
|
||||
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;
|
||||
@@ -829,7 +966,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;
|
||||
}
|
||||
@@ -844,7 +981,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);
|
||||
|
||||
@@ -853,7 +990,19 @@ 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);
|
||||
goto out;
|
||||
}
|
||||
@@ -883,7 +1032,7 @@ 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,
|
||||
@@ -934,7 +1083,6 @@ out:
|
||||
|
||||
errno = UV__ERR(result);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
||||
@@ -1014,10 +1162,84 @@ static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__fs_statx(int fd,
|
||||
const char* path,
|
||||
int is_fstat,
|
||||
int is_lstat,
|
||||
uv_stat_t* buf) {
|
||||
STATIC_ASSERT(UV_ENOSYS != -1);
|
||||
#ifdef __linux__
|
||||
static int no_statx;
|
||||
struct uv__statx statxbuf;
|
||||
int dirfd;
|
||||
int flags;
|
||||
int mode;
|
||||
int rc;
|
||||
|
||||
if (no_statx)
|
||||
return UV_ENOSYS;
|
||||
|
||||
dirfd = AT_FDCWD;
|
||||
flags = 0; /* AT_STATX_SYNC_AS_STAT */
|
||||
mode = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */
|
||||
|
||||
if (is_fstat) {
|
||||
dirfd = fd;
|
||||
flags |= 0x1000; /* AT_EMPTY_PATH */
|
||||
}
|
||||
|
||||
if (is_lstat)
|
||||
flags |= AT_SYMLINK_NOFOLLOW;
|
||||
|
||||
rc = uv__statx(dirfd, path, flags, mode, &statxbuf);
|
||||
|
||||
if (rc == -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;
|
||||
|
||||
no_statx = 1;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor;
|
||||
buf->st_mode = statxbuf.stx_mode;
|
||||
buf->st_nlink = statxbuf.stx_nlink;
|
||||
buf->st_uid = statxbuf.stx_uid;
|
||||
buf->st_gid = statxbuf.stx_gid;
|
||||
buf->st_rdev = statxbuf.stx_rdev_major;
|
||||
buf->st_ino = statxbuf.stx_ino;
|
||||
buf->st_size = statxbuf.stx_size;
|
||||
buf->st_blksize = statxbuf.stx_blksize;
|
||||
buf->st_blocks = statxbuf.stx_blocks;
|
||||
buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec;
|
||||
buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec;
|
||||
buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec;
|
||||
buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec;
|
||||
buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec;
|
||||
buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec;
|
||||
buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec;
|
||||
buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec;
|
||||
buf->st_flags = 0;
|
||||
buf->st_gen = 0;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
#endif /* __linux__ */
|
||||
}
|
||||
|
||||
|
||||
static int uv__fs_stat(const char *path, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 0, buf);
|
||||
if (ret != UV_ENOSYS)
|
||||
return ret;
|
||||
|
||||
ret = stat(path, &pbuf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
@@ -1030,6 +1252,10 @@ static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 1, buf);
|
||||
if (ret != UV_ENOSYS)
|
||||
return ret;
|
||||
|
||||
ret = lstat(path, &pbuf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
@@ -1042,6 +1268,10 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
|
||||
struct stat pbuf;
|
||||
int ret;
|
||||
|
||||
ret = uv__fs_statx(fd, "", /* is_fstat */ 1, /* is_lstat */ 0, buf);
|
||||
if (ret != UV_ENOSYS)
|
||||
return ret;
|
||||
|
||||
ret = fstat(fd, &pbuf);
|
||||
if (ret == 0)
|
||||
uv__to_stat(&pbuf, buf);
|
||||
@@ -1049,9 +1279,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
|
||||
size_t offset;
|
||||
/* Figure out which bufs are done */
|
||||
for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
|
||||
size -= bufs[offset].len;
|
||||
|
||||
typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
|
||||
static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
|
||||
/* Fix a partial read/write */
|
||||
if (size > 0) {
|
||||
bufs[offset].base += size;
|
||||
bufs[offset].len -= size;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_write_all(uv_fs_t* req) {
|
||||
unsigned int iovmax;
|
||||
unsigned int nbufs;
|
||||
uv_buf_t* bufs;
|
||||
@@ -1068,7 +1310,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
|
||||
if (req->nbufs > iovmax)
|
||||
req->nbufs = iovmax;
|
||||
|
||||
result = process(req);
|
||||
do
|
||||
result = uv__fs_write(req);
|
||||
while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result <= 0) {
|
||||
if (total == 0)
|
||||
total = result;
|
||||
@@ -1078,14 +1323,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
|
||||
if (req->off >= 0)
|
||||
req->off += result;
|
||||
|
||||
req->nbufs = uv__fs_buf_offset(req->bufs, result);
|
||||
req->bufs += req->nbufs;
|
||||
nbufs -= req->nbufs;
|
||||
total += result;
|
||||
}
|
||||
|
||||
if (errno == EINTR && total == -1)
|
||||
return total;
|
||||
|
||||
if (bufs != req->bufsml)
|
||||
uv__free(bufs);
|
||||
|
||||
@@ -1102,7 +1345,8 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
ssize_t r;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
|
||||
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
|
||||
req->fs_type == UV_FS_READ);
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
@@ -1116,7 +1360,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(ACCESS, access(req->path, req->flags));
|
||||
X(CHMOD, chmod(req->path, req->mode));
|
||||
X(CHOWN, chown(req->path, req->uid, req->gid));
|
||||
X(CLOSE, close(req->file));
|
||||
X(CLOSE, uv__fs_close(req->file));
|
||||
X(COPYFILE, uv__fs_copyfile(req));
|
||||
X(FCHMOD, fchmod(req->file, req->mode));
|
||||
X(FCHOWN, fchown(req->file, req->uid, req->gid));
|
||||
@@ -1131,8 +1375,11 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(MKDIR, mkdir(req->path, req->mode));
|
||||
X(MKDTEMP, uv__fs_mkdtemp(req));
|
||||
X(OPEN, uv__fs_open(req));
|
||||
X(READ, uv__fs_buf_iter(req, uv__fs_read));
|
||||
X(READ, uv__fs_read(req));
|
||||
X(SCANDIR, uv__fs_scandir(req));
|
||||
X(OPENDIR, uv__fs_opendir(req));
|
||||
X(READDIR, uv__fs_readdir(req));
|
||||
X(CLOSEDIR, uv__fs_closedir(req));
|
||||
X(READLINK, uv__fs_readlink(req));
|
||||
X(REALPATH, uv__fs_realpath(req));
|
||||
X(RENAME, rename(req->path, req->new_path));
|
||||
@@ -1142,7 +1389,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(SYMLINK, symlink(req->path, req->new_path));
|
||||
X(UNLINK, unlink(req->path));
|
||||
X(UTIME, uv__fs_utime(req));
|
||||
X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
|
||||
X(WRITE, uv__fs_write_all(req));
|
||||
default: abort();
|
||||
}
|
||||
#undef X
|
||||
@@ -1403,6 +1650,40 @@ int uv_fs_scandir(uv_loop_t* loop,
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_opendir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
INIT(OPENDIR);
|
||||
PATH;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_readdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
INIT(READDIR);
|
||||
|
||||
if (dir == NULL || dir->dir == NULL || dir->dirents == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
req->ptr = dir;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_closedir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
INIT(CLOSEDIR);
|
||||
|
||||
if (dir == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
req->ptr = dir;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_readlink(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
@@ -1543,6 +1824,9 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
req->path = NULL;
|
||||
req->new_path = NULL;
|
||||
|
||||
if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
|
||||
uv__fs_readdir_cleanup(req);
|
||||
|
||||
if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
|
||||
uv__fs_scandir_cleanup(req);
|
||||
|
||||
@@ -1550,7 +1834,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
uv__free(req->bufs);
|
||||
req->bufs = NULL;
|
||||
|
||||
if (req->ptr != &req->statbuf)
|
||||
if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf)
|
||||
uv__free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
|
||||
|
||||
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
|
||||
/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
@@ -255,42 +256,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
path = paths[i];
|
||||
len = strlen(path);
|
||||
|
||||
if (handle->realpath_len == 0)
|
||||
continue; /* This should be unreachable */
|
||||
|
||||
/* Filter out paths that are outside handle's request */
|
||||
if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
if (len < handle->realpath_len)
|
||||
continue;
|
||||
|
||||
if (handle->realpath_len > 1 || *handle->realpath != '/') {
|
||||
if (handle->realpath_len != len &&
|
||||
path[handle->realpath_len] != '/')
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* or that we matched the whole string */
|
||||
continue;
|
||||
|
||||
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
continue;
|
||||
|
||||
if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
|
||||
/* Remove common prefix, unless the watched folder is "/" */
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Skip forward slash */
|
||||
if (*path != '\0') {
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
|
||||
if (len == 0) {
|
||||
/* Since we're using fsevents to watch the file itself,
|
||||
* realpath == path, and we now need to get the basename of the file back
|
||||
* (for commonality with other codepaths and platforms). */
|
||||
while (len < handle->realpath_len && path[-1] != '/') {
|
||||
path--;
|
||||
len++;
|
||||
}
|
||||
/* Created and Removed seem to be always set, but don't make sense */
|
||||
flags &= ~kFSEventsRenamed;
|
||||
} else {
|
||||
/* Skip forward slash */
|
||||
path++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len == 0)
|
||||
continue;
|
||||
#else
|
||||
if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
/* Do not emit events from subdirectories (without option set) */
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
|
||||
pos = strchr(path + 1, '/');
|
||||
if (pos != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
path = "";
|
||||
len = 0;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
event = (uv__fsevents_event_t*)uv__malloc(sizeof(*event) + len);
|
||||
if (event == NULL)
|
||||
break;
|
||||
@@ -299,22 +313,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
memcpy(event->path, path, len + 1);
|
||||
event->events = UV_RENAME;
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
if (0 != (flags & kFSEventsModified) &&
|
||||
0 == (flags & kFSEventsRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
if (0 == (flags & kFSEventsRenamed)) {
|
||||
if (0 != (flags & kFSEventsModified) ||
|
||||
0 == (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
#else
|
||||
if (0 != (flags & kFSEventsModified) &&
|
||||
0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
|
||||
0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
|
||||
0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
QUEUE_INSERT_TAIL(&head, &event->member);
|
||||
}
|
||||
@@ -836,7 +839,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
|
||||
handle->cf_cb->data = handle;
|
||||
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
|
||||
handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
|
||||
handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
|
||||
uv_unref((uv_handle_t*) handle->cf_cb);
|
||||
|
||||
err = uv_mutex_init(&handle->cf_mutex);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "idna.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
@@ -91,7 +92,9 @@ int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
}
|
||||
assert(!"unknown EAI_* error code");
|
||||
abort();
|
||||
#ifndef __SUNPRO_C
|
||||
return 0; /* Pacify compiler. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -141,15 +144,34 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* hostname,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
size_t hostname_len;
|
||||
size_t service_len;
|
||||
size_t hints_len;
|
||||
size_t len;
|
||||
char* buf;
|
||||
long rc;
|
||||
|
||||
if (req == NULL || (hostname == NULL && service == NULL))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
|
||||
* probably because it uses EBCDIC rather than ASCII.
|
||||
*/
|
||||
#ifdef __MVS__
|
||||
(void) &hostname_ascii;
|
||||
#else
|
||||
if (hostname != NULL) {
|
||||
rc = uv__idna_toascii(hostname,
|
||||
hostname + strlen(hostname),
|
||||
hostname_ascii,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
hostname = hostname_ascii;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_len = hostname ? strlen(hostname) + 1 : 0;
|
||||
service_len = service ? strlen(service) + 1 : 0;
|
||||
hints_len = hints ? sizeof(*hints) : 0;
|
||||
@@ -186,6 +208,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
if (cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop,
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -55,24 +55,161 @@
|
||||
#include <strings.h>
|
||||
#include <sys/vnode.h>
|
||||
|
||||
#include <as400_protos.h>
|
||||
|
||||
|
||||
typedef struct {
|
||||
int bytes_available;
|
||||
int bytes_returned;
|
||||
char current_date_and_time[8];
|
||||
char system_name[8];
|
||||
char elapsed_time[6];
|
||||
char restricted_state_flag;
|
||||
char reserved;
|
||||
int percent_processing_unit_used;
|
||||
int jobs_in_system;
|
||||
int percent_permanent_addresses;
|
||||
int percent_temporary_addresses;
|
||||
int system_asp;
|
||||
int percent_system_asp_used;
|
||||
int total_auxiliary_storage;
|
||||
int current_unprotected_storage_used;
|
||||
int maximum_unprotected_storage_used;
|
||||
int percent_db_capability;
|
||||
int main_storage_size;
|
||||
int number_of_partitions;
|
||||
int partition_identifier;
|
||||
int reserved1;
|
||||
int current_processing_capacity;
|
||||
char processor_sharing_attribute;
|
||||
char reserved2[3];
|
||||
int number_of_processors;
|
||||
int active_jobs_in_system;
|
||||
int active_threads_in_system;
|
||||
int maximum_jobs_in_system;
|
||||
int percent_temporary_256mb_segments_used;
|
||||
int percent_temporary_4gb_segments_used;
|
||||
int percent_permanent_256mb_segments_used;
|
||||
int percent_permanent_4gb_segments_used;
|
||||
int percent_current_interactive_performance;
|
||||
int percent_uncapped_cpu_capacity_used;
|
||||
int percent_shared_processor_pool_used;
|
||||
long main_storage_size_long;
|
||||
} SSTS0200;
|
||||
|
||||
|
||||
static int get_ibmi_system_status(SSTS0200* rcvr) {
|
||||
/* rcvrlen is input parameter 2 to QWCRSSTS */
|
||||
unsigned int rcvrlen = sizeof(*rcvr);
|
||||
|
||||
/* 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
|
||||
};
|
||||
|
||||
/* errcode is input parameter 5 to QWCRSSTS */
|
||||
struct _errcode {
|
||||
int bytes_provided;
|
||||
int bytes_available;
|
||||
char msgid[7];
|
||||
} errcode;
|
||||
|
||||
/* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
|
||||
ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
|
||||
|
||||
/* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
|
||||
void* qwcrssts_argv[6];
|
||||
|
||||
/* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
|
||||
int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
/* initialize the QWCRSSTS returned info structure */
|
||||
memset(rcvr, 0, sizeof(*rcvr));
|
||||
|
||||
/* initialize the QWCRSSTS error code structure */
|
||||
memset(&errcode, 0, sizeof(errcode));
|
||||
errcode.bytes_provided = sizeof(errcode);
|
||||
|
||||
/* initialize the array of argument pointers for the QWCRSSTS API */
|
||||
qwcrssts_argv[0] = rcvr;
|
||||
qwcrssts_argv[1] = &rcvrlen;
|
||||
qwcrssts_argv[2] = &format;
|
||||
qwcrssts_argv[3] = &reset_status;
|
||||
qwcrssts_argv[4] = &errcode;
|
||||
qwcrssts_argv[5] = NULL;
|
||||
|
||||
/* Call the IBM i QWCRSSTS API from PASE */
|
||||
rc = _PGMCALL(&qwcrssts_pointer, (void**)&qwcrssts_argv, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
|
||||
SSTS0200 rcvr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
|
||||
SSTS0200 rcvr;
|
||||
|
||||
if (get_ibmi_system_status(&rcvr))
|
||||
return 0;
|
||||
|
||||
return (uint64_t)rcvr.main_storage_size * 1024ULL;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
SSTS0200 rcvr;
|
||||
|
||||
if (get_ibmi_system_status(&rcvr)) {
|
||||
avg[0] = avg[1] = avg[2] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The average (in tenths) of the elapsed time during which the processing
|
||||
* units were in use. For example, a value of 411 in binary would be 41.1%.
|
||||
* This percentage could be greater than 100% for an uncapped partition.
|
||||
*/
|
||||
double processing_unit_used_percent =
|
||||
rcvr.percent_processing_unit_used / 1000.0;
|
||||
|
||||
avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
return UV_ENOSYS;
|
||||
*rss = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#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 */
|
||||
@@ -60,6 +61,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(__ANDROID__)
|
||||
int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
# ifdef pthread_sigmask
|
||||
@@ -95,8 +104,7 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
*/
|
||||
#if defined(__clang__) || \
|
||||
defined(__GNUC__) || \
|
||||
defined(__INTEL_COMPILER) || \
|
||||
defined(__SUNPRO_C)
|
||||
defined(__INTEL_COMPILER)
|
||||
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
|
||||
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
|
||||
#else
|
||||
@@ -127,26 +135,6 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
|
||||
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
|
||||
/* handle flags */
|
||||
enum {
|
||||
UV_CLOSING = 0x01, /* uv_close() called but not finished. */
|
||||
UV_CLOSED = 0x02, /* close(2) finished. */
|
||||
UV_STREAM_READING = 0x04, /* uv_read_start() called. */
|
||||
UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
|
||||
UV_STREAM_SHUT = 0x10, /* Write side closed. */
|
||||
UV_STREAM_READABLE = 0x20, /* The stream is readable */
|
||||
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
|
||||
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
|
||||
UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
|
||||
UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
|
||||
UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
|
||||
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
|
||||
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
|
||||
UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
|
||||
UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */
|
||||
UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */
|
||||
};
|
||||
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 1
|
||||
@@ -208,8 +196,8 @@ int uv__nonblock_ioctl(int fd, int set);
|
||||
int uv__nonblock_fcntl(int fd, int set);
|
||||
int uv__close(int fd); /* preserves errno */
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__close_nocancel(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__dup(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
@@ -256,10 +244,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay);
|
||||
/* pipe */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
/* timer */
|
||||
void uv__run_timers(uv_loop_t* loop);
|
||||
int uv__next_timeout(const uv_loop_t* loop);
|
||||
|
||||
/* signal */
|
||||
void uv__signal_close(uv_signal_t* handle);
|
||||
void uv__signal_global_once_init(void);
|
||||
@@ -284,7 +268,6 @@ void uv__prepare_close(uv_prepare_t* handle);
|
||||
void uv__process_close(uv_process_t* handle);
|
||||
void uv__stream_close(uv_stream_t* handle);
|
||||
void uv__tcp_close(uv_tcp_t* handle);
|
||||
void uv__timer_close(uv_timer_t* handle);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
uv_handle_type uv__handle_type(int fd);
|
||||
@@ -314,24 +297,6 @@ int uv__fsevents_init(uv_fs_event_t* handle);
|
||||
int uv__fsevents_close(uv_fs_event_t* handle);
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop);
|
||||
|
||||
/* OSX < 10.7 has no file events, polyfill them */
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
|
||||
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
|
||||
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
|
||||
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
|
||||
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
|
||||
static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
|
||||
static const int kFSEventStreamEventFlagItemModified = 0x00001000;
|
||||
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
|
||||
static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
|
||||
static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
|
||||
static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
|
||||
static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
|
||||
static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
|
||||
|
||||
#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
@@ -354,4 +319,11 @@ UV_UNUSED(static const char* uv__basename_r(const char* path)) {
|
||||
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
|
||||
#endif
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
|
||||
@@ -59,7 +59,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
static int uv__has_forked_with_cfrunloop;
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (loop->cf_state != NULL) {
|
||||
/* We cannot start another CFRunloop and/or thread in the child
|
||||
process; CF aborts if you try or if you try to touch the thread
|
||||
@@ -86,7 +86,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
uv__free(loop->cf_state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -387,6 +387,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct kevent*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
@@ -452,49 +453,51 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
#if defined(__APPLE__)
|
||||
struct stat statbuf;
|
||||
#endif /* defined(__APPLE__) */
|
||||
int fd;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
handle->path = uv__strdup(path);
|
||||
handle->cb = cb;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (uv__has_forked_with_cfrunloop)
|
||||
goto fallback;
|
||||
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
handle->cf_flags = flags;
|
||||
|
||||
if (fstat(fd, &statbuf))
|
||||
goto fallback;
|
||||
/* FSEvents works only with directories */
|
||||
if (!(statbuf.st_mode & S_IFDIR))
|
||||
goto fallback;
|
||||
if (!uv__has_forked_with_cfrunloop) {
|
||||
int r;
|
||||
/* The fallback fd is not used */
|
||||
handle->event_watcher.fd = -1;
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->cb = cb;
|
||||
r = uv__fsevents_init(handle);
|
||||
if (r == 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close(fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return uv__fsevents_init(handle);
|
||||
|
||||
fallback:
|
||||
#endif /* defined(__APPLE__) */
|
||||
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);
|
||||
|
||||
return 0;
|
||||
@@ -502,29 +505,29 @@ fallback:
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
int r;
|
||||
r = 0;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle))
|
||||
#endif /* defined(__APPLE__) */
|
||||
{
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (!uv__has_forked_with_cfrunloop)
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
uv__io_close(handle->loop, &handle->event_watcher);
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
/* When FSEvents is used, we don't use the event_watcher's fd under certain
|
||||
* confitions. (see uv_fs_event_start) */
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
|
||||
* EPOLL* counterparts. We use the POLL* variants in this file because that
|
||||
* is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
|
||||
* is what libuv uses elsewhere.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -34,6 +35,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -82,19 +84,23 @@ static int read_times(FILE* statfile_fp,
|
||||
unsigned int numcpus,
|
||||
uv_cpu_info_t* ci);
|
||||
static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
|
||||
static unsigned long read_cpufreq(unsigned int cpunum);
|
||||
static uint64_t read_cpufreq(unsigned int cpunum);
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int fd;
|
||||
|
||||
fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
|
||||
/* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21,
|
||||
* a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
|
||||
* architectures, we just use that instead.
|
||||
*/
|
||||
fd = epoll_create1(O_CLOEXEC);
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the EPOLL_CLOEXEC flag.
|
||||
* or because it doesn't understand the O_CLOEXEC flag.
|
||||
*/
|
||||
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
|
||||
fd = uv__epoll_create(256);
|
||||
fd = epoll_create(256);
|
||||
|
||||
if (fd != -1)
|
||||
uv__cloexec(fd, 1);
|
||||
@@ -138,20 +144,21 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event* events;
|
||||
struct uv__epoll_event dummy;
|
||||
struct epoll_event* events;
|
||||
struct epoll_event dummy;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
|
||||
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events != NULL)
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].data == fd)
|
||||
events[i].data = -1;
|
||||
if (events[i].data.fd == fd)
|
||||
events[i].data.fd = -1;
|
||||
|
||||
/* Remove the file descriptor from the epoll.
|
||||
* This avoids a problem where the same file description remains open
|
||||
@@ -164,25 +171,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
|
||||
*/
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event e;
|
||||
struct epoll_event e;
|
||||
int rc;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
e.events = POLLIN;
|
||||
e.data = -1;
|
||||
e.data.fd = -1;
|
||||
|
||||
rc = 0;
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
|
||||
if (errno != EEXIST)
|
||||
rc = UV__ERR(errno);
|
||||
|
||||
if (rc == 0)
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
@@ -199,16 +207,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* that being the largest value I have seen in the wild (and only once.)
|
||||
*/
|
||||
static const int max_safe_timeout = 1789569;
|
||||
static int no_epoll_pwait;
|
||||
static int no_epoll_wait;
|
||||
struct uv__epoll_event events[1024];
|
||||
struct uv__epoll_event* pe;
|
||||
struct uv__epoll_event e;
|
||||
struct epoll_event events[1024];
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
uint64_t sigmask;
|
||||
sigset_t* psigset;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
@@ -223,6 +229,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
@@ -234,35 +242,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
e.events = w->pevents;
|
||||
e.data = w->fd;
|
||||
e.data.fd = w->fd;
|
||||
|
||||
if (w->events == 0)
|
||||
op = UV__EPOLL_CTL_ADD;
|
||||
op = EPOLL_CTL_ADD;
|
||||
else
|
||||
op = UV__EPOLL_CTL_MOD;
|
||||
op = EPOLL_CTL_MOD;
|
||||
|
||||
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
|
||||
* events, skip the syscall and squelch the events after epoll_wait().
|
||||
*/
|
||||
if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
|
||||
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
|
||||
if (errno != EEXIST)
|
||||
abort();
|
||||
|
||||
assert(op == UV__EPOLL_CTL_ADD);
|
||||
assert(op == EPOLL_CTL_ADD);
|
||||
|
||||
/* We've reactivated a file descriptor that's been watched before. */
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
sigmask = 0;
|
||||
psigset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
sigmask |= 1 << (SIGPROF - 1);
|
||||
psigset = &sigset;
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
@@ -277,30 +285,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||
abort();
|
||||
|
||||
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
|
||||
nfds = uv__epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
sigmask);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_pwait = 1;
|
||||
} else {
|
||||
nfds = uv__epoll_wait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_wait = 1;
|
||||
}
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
|
||||
abort();
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
psigset);
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||
@@ -321,12 +310,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
|
||||
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
@@ -348,7 +331,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data;
|
||||
fd = pe->data.fd;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
@@ -365,7 +348,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* Ignore all errors because we may be racing with another thread
|
||||
* when the file descriptor is closed.
|
||||
*/
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -745,20 +728,20 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
|
||||
static int read_times(FILE* statfile_fp,
|
||||
unsigned int numcpus,
|
||||
uv_cpu_info_t* ci) {
|
||||
unsigned long clock_ticks;
|
||||
struct uv_cpu_times_s ts;
|
||||
unsigned long user;
|
||||
unsigned long nice;
|
||||
unsigned long sys;
|
||||
unsigned long idle;
|
||||
unsigned long dummy;
|
||||
unsigned long irq;
|
||||
unsigned int num;
|
||||
unsigned int len;
|
||||
uint64_t clock_ticks;
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t sys;
|
||||
uint64_t idle;
|
||||
uint64_t dummy;
|
||||
uint64_t irq;
|
||||
uint64_t num;
|
||||
uint64_t len;
|
||||
char buf[1024];
|
||||
|
||||
clock_ticks = sysconf(_SC_CLK_TCK);
|
||||
assert(clock_ticks != (unsigned long) -1);
|
||||
assert(clock_ticks != (uint64_t) -1);
|
||||
assert(clock_ticks != 0);
|
||||
|
||||
rewind(statfile_fp);
|
||||
@@ -791,7 +774,8 @@ static int read_times(FILE* statfile_fp,
|
||||
* fields, they're not allowed in C89 mode.
|
||||
*/
|
||||
if (6 != sscanf(buf + len,
|
||||
"%lu %lu %lu %lu %lu %lu",
|
||||
"%" PRIu64 " %" PRIu64 " %" PRIu64
|
||||
"%" PRIu64 " %" PRIu64 " %" PRIu64,
|
||||
&user,
|
||||
&nice,
|
||||
&sys,
|
||||
@@ -813,8 +797,8 @@ static int read_times(FILE* statfile_fp,
|
||||
}
|
||||
|
||||
|
||||
static unsigned long read_cpufreq(unsigned int cpunum) {
|
||||
unsigned long val;
|
||||
static uint64_t read_cpufreq(unsigned int cpunum) {
|
||||
uint64_t val;
|
||||
char buf[1024];
|
||||
FILE* fp;
|
||||
|
||||
@@ -827,7 +811,7 @@ static unsigned long read_cpufreq(unsigned int cpunum) {
|
||||
if (fp == NULL)
|
||||
return 0;
|
||||
|
||||
if (fscanf(fp, "%lu", &val) != 1)
|
||||
if (fscanf(fp, "%" PRIu64, &val) != 1)
|
||||
val = 0;
|
||||
|
||||
fclose(fp);
|
||||
@@ -860,9 +844,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
return !exclude_type;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
#ifndef HAVE_IFADDRS_H
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
return UV_ENOSYS;
|
||||
#else
|
||||
struct ifaddrs *addrs, *ent;
|
||||
@@ -870,12 +855,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int i;
|
||||
struct sockaddr_ll *sll;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
@@ -884,11 +869,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0)
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses =
|
||||
(uv_interface_address_t*)uv__malloc(*count * sizeof(**addresses));
|
||||
/* Make sure the memory is initiallized to zero using calloc() */
|
||||
*addresses = (uv_interface_address_t*)uv__calloc(*count, sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
@@ -927,7 +914,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
size_t namelen = strlen(ent->ifa_name);
|
||||
/* Alias interface share the same physical address */
|
||||
if (strncmp(address->name, ent->ifa_name, namelen) == 0 &&
|
||||
(address->name[namelen] == 0 || address->name[namelen] == ':')) {
|
||||
sll = (struct sockaddr_ll*)ent->ifa_addr;
|
||||
memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
|
||||
}
|
||||
@@ -959,3 +949,114 @@ void uv__set_process_title(const char* title) {
|
||||
prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static uint64_t uv__read_proc_meminfo(const char* what) {
|
||||
uint64_t rc;
|
||||
ssize_t n;
|
||||
char* p;
|
||||
int fd;
|
||||
char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
|
||||
|
||||
rc = 0;
|
||||
fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
|
||||
|
||||
if (fd == -1)
|
||||
return 0;
|
||||
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
|
||||
if (n <= 0)
|
||||
goto out;
|
||||
|
||||
buf[n] = '\0';
|
||||
p = strstr(buf, what);
|
||||
|
||||
if (p == NULL)
|
||||
goto out;
|
||||
|
||||
p += strlen(what);
|
||||
|
||||
if (1 != sscanf(p, "%" PRIu64 " kB", &rc))
|
||||
goto out;
|
||||
|
||||
rc *= 1024;
|
||||
|
||||
out:
|
||||
|
||||
if (uv__close_nocheckstdio(fd))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct sysinfo info;
|
||||
uint64_t rc;
|
||||
|
||||
rc = uv__read_proc_meminfo("MemFree:");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (0 == sysinfo(&info))
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
struct sysinfo info;
|
||||
uint64_t rc;
|
||||
|
||||
rc = uv__read_proc_meminfo("MemTotal:");
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (0 == sysinfo(&info))
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
|
||||
char filename[256];
|
||||
uint64_t rc;
|
||||
int fd;
|
||||
ssize_t n;
|
||||
char buf[32]; /* Large enough to hold an encoded uint64_t. */
|
||||
|
||||
snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param);
|
||||
|
||||
rc = 0;
|
||||
fd = uv__open_cloexec(filename, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
n = read(fd, buf, sizeof(buf) - 1);
|
||||
|
||||
if (n > 0) {
|
||||
buf[n] = '\0';
|
||||
sscanf(buf, "%" PRIu64, &rc);
|
||||
}
|
||||
|
||||
if (uv__close_nocheckstdio(fd))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
/*
|
||||
* This might return 0 if there was a problem getting the memory limit from
|
||||
* cgroups. This is OK because a return value of 0 signifies that the memory
|
||||
* limit is unknown.
|
||||
*/
|
||||
return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
|
||||
}
|
||||
|
||||
@@ -278,6 +278,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
struct watcher_list* w;
|
||||
size_t len;
|
||||
int events;
|
||||
int err;
|
||||
int wd;
|
||||
@@ -306,12 +307,13 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
if (w)
|
||||
goto no_insert;
|
||||
|
||||
w = (watcher_list*)uv__malloc(sizeof(*w) + strlen(path) + 1);
|
||||
len = strlen(path) + 1;
|
||||
w = (watcher_list*)uv__malloc(sizeof(*w) + len);
|
||||
if (w == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
w->wd = wd;
|
||||
w->path = strcpy((char*)(w + 1), path);
|
||||
w->path = (char*)memcpy(w + 1, path, len);
|
||||
QUEUE_INIT(&w->watchers);
|
||||
w->iterating = 0;
|
||||
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
|
||||
|
||||
@@ -77,56 +77,6 @@
|
||||
# endif
|
||||
#endif /* __NR_eventfd2 */
|
||||
|
||||
#ifndef __NR_epoll_create
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create 213
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create 254
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create */
|
||||
|
||||
#ifndef __NR_epoll_create1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create1 291
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create1 329
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create1 */
|
||||
|
||||
#ifndef __NR_epoll_ctl
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_ctl 233 /* used to be 214 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_ctl 255
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
|
||||
# endif
|
||||
#endif /* __NR_epoll_ctl */
|
||||
|
||||
#ifndef __NR_epoll_wait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_wait 232 /* used to be 215 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_wait 256
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
|
||||
# endif
|
||||
#endif /* __NR_epoll_wait */
|
||||
|
||||
#ifndef __NR_epoll_pwait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_pwait 281
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_pwait 319
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
|
||||
# endif
|
||||
#endif /* __NR_epoll_pwait */
|
||||
|
||||
#ifndef __NR_inotify_init
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init 253
|
||||
@@ -237,6 +187,21 @@
|
||||
# endif
|
||||
#endif /* __NR_pwritev */
|
||||
|
||||
#ifndef __NR_statx
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_statx 332
|
||||
# elif defined(__i386__)
|
||||
# define __NR_statx 383
|
||||
# elif defined(__aarch64__)
|
||||
# define __NR_statx 397
|
||||
# elif defined(__arm__)
|
||||
# define __NR_statx (UV_SYSCALL_BASE + 397)
|
||||
# elif defined(__ppc__)
|
||||
# define __NR_statx 383
|
||||
# elif defined(__s390__)
|
||||
# define __NR_statx 379
|
||||
# endif
|
||||
#endif /* __NR_statx */
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
|
||||
#if defined(__i386__)
|
||||
@@ -285,76 +250,6 @@ int uv__eventfd2(unsigned int count, int flags) {
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create(int size) {
|
||||
#if defined(__NR_epoll_create)
|
||||
return syscall(__NR_epoll_create, size);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create1(int flags) {
|
||||
#if defined(__NR_epoll_create1)
|
||||
return syscall(__NR_epoll_create1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
|
||||
#if defined(__NR_epoll_ctl)
|
||||
return syscall(__NR_epoll_ctl, epfd, op, fd, events);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout) {
|
||||
#if defined(__NR_epoll_wait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask) {
|
||||
#if defined(__NR_epoll_pwait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_pwait,
|
||||
epfd,
|
||||
events,
|
||||
nevents,
|
||||
timeout,
|
||||
&sigmask,
|
||||
sizeof(sigmask));
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init(void) {
|
||||
#if defined(__NR_inotify_init)
|
||||
return syscall(__NR_inotify_init);
|
||||
@@ -431,19 +326,6 @@ int uv__recvmmsg(int fd,
|
||||
}
|
||||
|
||||
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags)
|
||||
{
|
||||
#if defined(__NR_utimensat)
|
||||
return syscall(__NR_utimensat, dirfd, path, times, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_preadv)
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
@@ -469,3 +351,19 @@ int uv__dup3(int oldfd, int newfd, int flags) {
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__statx(int dirfd,
|
||||
const char* path,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf) {
|
||||
/* __NR_statx make Android box killed by SIGSYS.
|
||||
* That looks like a seccomp2 sandbox filter rejecting the system call.
|
||||
*/
|
||||
#if defined(__NR_statx) && !defined(__ANDROID__)
|
||||
return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -66,12 +66,6 @@
|
||||
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/* epoll flags */
|
||||
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EPOLL_CTL_ADD 1
|
||||
#define UV__EPOLL_CTL_DEL 2
|
||||
#define UV__EPOLL_CTL_MOD 3
|
||||
|
||||
/* inotify flags */
|
||||
#define UV__IN_ACCESS 0x001
|
||||
#define UV__IN_MODIFY 0x002
|
||||
@@ -86,17 +80,35 @@
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
#if defined(__x86_64__)
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
struct uv__statx_timestamp {
|
||||
int64_t tv_sec;
|
||||
uint32_t tv_nsec;
|
||||
int32_t unused0;
|
||||
};
|
||||
|
||||
struct uv__statx {
|
||||
uint32_t stx_mask;
|
||||
uint32_t stx_blksize;
|
||||
uint64_t stx_attributes;
|
||||
uint32_t stx_nlink;
|
||||
uint32_t stx_uid;
|
||||
uint32_t stx_gid;
|
||||
uint16_t stx_mode;
|
||||
uint16_t unused0;
|
||||
uint64_t stx_ino;
|
||||
uint64_t stx_size;
|
||||
uint64_t stx_blocks;
|
||||
uint64_t stx_attributes_mask;
|
||||
struct uv__statx_timestamp stx_atime;
|
||||
struct uv__statx_timestamp stx_btime;
|
||||
struct uv__statx_timestamp stx_ctime;
|
||||
struct uv__statx_timestamp stx_mtime;
|
||||
uint32_t stx_rdev_major;
|
||||
uint32_t stx_rdev_minor;
|
||||
uint32_t stx_dev_major;
|
||||
uint32_t stx_dev_minor;
|
||||
uint64_t unused1[14];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
@@ -113,18 +125,6 @@ struct uv__mmsghdr {
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
|
||||
int uv__eventfd(unsigned int count);
|
||||
int uv__epoll_create(int size);
|
||||
int uv__epoll_create1(int flags);
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout);
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask);
|
||||
int uv__eventfd2(unsigned int count, int flags);
|
||||
int uv__inotify_init(void);
|
||||
int uv__inotify_init1(int flags);
|
||||
@@ -140,12 +140,13 @@ int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags);
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags);
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
int uv__dup3(int oldfd, int newfd, int flags);
|
||||
int uv__statx(int dirfd,
|
||||
const char* path,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf);
|
||||
|
||||
#endif /* UV_LINUX_SYSCALL_H_ */
|
||||
|
||||
@@ -74,7 +74,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_signal_init;
|
||||
|
||||
uv__handle_unref(&loop->child_watcher);
|
||||
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
|
||||
QUEUE_INIT(&loop->process_handles);
|
||||
|
||||
err = uv_rwlock_init(&loop->cloexec_lock);
|
||||
@@ -90,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -40,15 +40,6 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
@@ -96,7 +87,8 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
/* Copy string from the intermediate buffer to outer one with appropriate
|
||||
* length.
|
||||
*/
|
||||
strlcpy(buffer, int_buf, *size);
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(buffer, int_buf, *size);
|
||||
|
||||
/* Set new size. */
|
||||
*size = strlen(buffer);
|
||||
@@ -134,62 +126,8 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,16 +36,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
@@ -146,62 +136,8 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,8 +66,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||
@@ -132,11 +131,21 @@ void uv__pipe_close(uv_pipe_t* handle) {
|
||||
|
||||
|
||||
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
int flags;
|
||||
int mode;
|
||||
int err;
|
||||
flags = 0;
|
||||
|
||||
if (uv__fd_exists(handle->loop, fd))
|
||||
return UV_EEXIST;
|
||||
|
||||
do
|
||||
mode = fcntl(fd, F_GETFL);
|
||||
while (mode == -1 && errno == EINTR);
|
||||
|
||||
if (mode == -1)
|
||||
return UV__ERR(errno); /* according to docs, must be EBADF */
|
||||
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -147,9 +156,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
return err;
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
mode &= O_ACCMODE;
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle, fd, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,8 +185,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
do {
|
||||
@@ -199,11 +211,11 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
if (new_sock) {
|
||||
err = uv__stream_open((uv_stream_t*)handle,
|
||||
uv__stream_fd(handle),
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT);
|
||||
uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
||||
|
||||
out:
|
||||
handle->delayed_error = err;
|
||||
@@ -221,9 +233,6 @@ out:
|
||||
}
|
||||
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
|
||||
|
||||
static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
uv__peersockfunc func,
|
||||
char* buffer,
|
||||
@@ -234,10 +243,13 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
memset(&sa, 0, addrlen);
|
||||
err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
|
||||
err = uv__getsockpeername((const uv_handle_t*) handle,
|
||||
func,
|
||||
(struct sockaddr*) &sa,
|
||||
(int*) &addrlen);
|
||||
if (err < 0) {
|
||||
*size = 0;
|
||||
return UV__ERR(errno);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
@@ -298,6 +298,8 @@ update_timeout:
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
size_t i;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (loop->poll_fds_iterating) {
|
||||
/* uv__io_poll is currently iterating. Just invalidate fd. */
|
||||
for (i = 0; i < loop->poll_fds_used; i++)
|
||||
|
||||
@@ -239,9 +239,9 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
|
||||
|
||||
flags = 0;
|
||||
if (container->flags & UV_WRITABLE_PIPE)
|
||||
flags |= UV_STREAM_READABLE;
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (container->flags & UV_READABLE_PIPE)
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open(container->data.stream, pipefds[0], flags);
|
||||
}
|
||||
@@ -249,7 +249,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ static void uv__process_child_init(const uv_process_options_t* options,
|
||||
use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
|
||||
close_fd = use_fd;
|
||||
|
||||
if (use_fd == -1) {
|
||||
if (use_fd < 0) {
|
||||
uv__write_int(error_fd, UV__ERR(errno));
|
||||
_exit(127);
|
||||
}
|
||||
@@ -385,6 +385,11 @@ static void uv__process_child_init(const uv_process_options_t* options,
|
||||
if (n == SIGKILL || n == SIGSTOP)
|
||||
continue; /* Can't be changed. */
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
if (n == SIGKILLTHR)
|
||||
continue; /* Can't be changed. */
|
||||
#endif
|
||||
|
||||
if (SIG_ERR != signal(n, SIG_DFL))
|
||||
continue;
|
||||
|
||||
@@ -431,6 +436,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void uv__set_process_title_platform_init(void);
|
||||
extern void uv__set_process_title(const char* title);
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
@@ -38,6 +39,9 @@ static struct {
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
#ifdef __APPLE__
|
||||
uv__set_process_title_platform_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -375,7 +375,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) {
|
||||
@@ -396,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle,
|
||||
*/
|
||||
first_handle = uv__signal_first_handle(signum);
|
||||
if (first_handle == NULL ||
|
||||
(!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) {
|
||||
(!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
|
||||
err = uv__signal_register_handler(signum, oneshot);
|
||||
if (err) {
|
||||
/* Registering the signal handler failed. Must be an invalid signal. */
|
||||
@@ -407,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle,
|
||||
|
||||
handle->signum = signum;
|
||||
if (oneshot)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT;
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT;
|
||||
|
||||
RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
@@ -464,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop,
|
||||
handle = msg->handle;
|
||||
|
||||
if (msg->signum == handle->signum) {
|
||||
assert(!(handle->flags & UV_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
handle->signal_cb(handle, handle->signum);
|
||||
}
|
||||
|
||||
handle->dispatched_signals++;
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If uv_close was called while there were caught signals that were not
|
||||
* yet dispatched, the uv__finish_close was deferred. Make close pending
|
||||
* now if this has happened.
|
||||
*/
|
||||
if ((handle->flags & UV_CLOSING) &&
|
||||
if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
(handle->caught_signals == handle->dispatched_signals)) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
@@ -505,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first
|
||||
/* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
|
||||
* handler returned is a one-shot handler, the rest will be too.
|
||||
*/
|
||||
f1 = w1->flags & UV__SIGNAL_ONE_SHOT;
|
||||
f2 = w2->flags & UV__SIGNAL_ONE_SHOT;
|
||||
f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
|
||||
f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (f1 < f2) return -1;
|
||||
if (f1 > f2) return 1;
|
||||
|
||||
@@ -558,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) {
|
||||
if (first_handle == NULL) {
|
||||
uv__signal_unregister_handler(handle->signum);
|
||||
} else {
|
||||
rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT;
|
||||
first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT;
|
||||
rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (first_oneshot && !rem_oneshot) {
|
||||
ret = uv__signal_register_handler(handle->signum, 1);
|
||||
assert(ret == 0);
|
||||
|
||||
@@ -58,11 +58,19 @@ struct uv__stream_select_s {
|
||||
fd_set* swrite;
|
||||
size_t swrite_sz;
|
||||
};
|
||||
# define WRITE_RETRY_ON_ERROR(send_handle) \
|
||||
|
||||
/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
|
||||
(errno == EMSGSIZE && send_handle))
|
||||
(errno == EMSGSIZE && send_handle != NULL))
|
||||
#else
|
||||
# define WRITE_RETRY_ON_ERROR(send_handle) \
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
@@ -220,7 +228,7 @@ static void uv__stream_osx_select(void* arg) {
|
||||
uv_sem_wait(&s->async_sem);
|
||||
|
||||
/* Should be processed at this stage */
|
||||
assert((s->events == 0) || (stream->flags & UV_CLOSING));
|
||||
assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +256,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) {
|
||||
if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
|
||||
if (stream->flags & UV_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return;
|
||||
|
||||
/* NOTE: It is important to do it here, otherwise `select()` might be called
|
||||
@@ -342,7 +350,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
||||
if (err)
|
||||
goto failed_async_init;
|
||||
|
||||
s->async.flags |= UV__HANDLE_INTERNAL;
|
||||
s->async.flags |= UV_HANDLE_INTERNAL;
|
||||
uv__handle_unref(&s->async);
|
||||
|
||||
err = uv_sem_init(&s->close_sem, 0);
|
||||
@@ -407,12 +415,14 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
|
||||
stream->flags |= flags;
|
||||
|
||||
if (stream->type == UV_TCP) {
|
||||
if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
|
||||
if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* TODO Use delay the user passed in. */
|
||||
if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
|
||||
if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) &&
|
||||
uv__tcp_keepalive(fd, 1, 60)) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -447,7 +457,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
|
||||
|
||||
void uv__stream_destroy(uv_stream_t* stream) {
|
||||
assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
|
||||
assert(stream->flags & UV_CLOSED);
|
||||
assert(stream->flags & UV_HANDLE_CLOSED);
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__req_unregister(stream->loop, stream->connect_req);
|
||||
@@ -522,7 +532,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
stream = container_of(w, uv_stream_t, io_watcher);
|
||||
assert(events & POLLIN);
|
||||
assert(stream->accepted_fd == -1);
|
||||
assert(!(stream->flags & UV_CLOSING));
|
||||
assert(!(stream->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
|
||||
|
||||
@@ -565,7 +575,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
|
||||
if (stream->type == UV_TCP &&
|
||||
(stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
|
||||
/* Give other processes a chance to accept connections. */
|
||||
struct timespec timeout = { 0, 1 };
|
||||
nanosleep(&timeout, NULL);
|
||||
@@ -590,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||
case UV_TCP:
|
||||
err = uv__stream_open(client,
|
||||
server->accepted_fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
if (err) {
|
||||
/* TODO handle error */
|
||||
uv__close(server->accepted_fd);
|
||||
@@ -674,14 +685,14 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
|
||||
/* Shutdown? */
|
||||
if ((stream->flags & UV_STREAM_SHUTTING) &&
|
||||
!(stream->flags & UV_CLOSING) &&
|
||||
!(stream->flags & UV_STREAM_SHUT)) {
|
||||
if ((stream->flags & UV_HANDLE_SHUTTING) &&
|
||||
!(stream->flags & UV_HANDLE_CLOSING) &&
|
||||
!(stream->flags & UV_HANDLE_SHUT)) {
|
||||
assert(stream->shutdown_req);
|
||||
|
||||
req = stream->shutdown_req;
|
||||
stream->shutdown_req = NULL;
|
||||
stream->flags &= ~UV_STREAM_SHUTTING;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
|
||||
err = 0;
|
||||
@@ -689,7 +700,7 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
err = UV__ERR(errno);
|
||||
|
||||
if (err == 0)
|
||||
stream->flags |= UV_STREAM_SHUT;
|
||||
stream->flags |= UV_HANDLE_SHUT;
|
||||
|
||||
if (req->cb != NULL)
|
||||
req->cb(req, err);
|
||||
@@ -697,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) {
|
||||
if (n == 1)
|
||||
return write(fd, vec->iov_base, vec->iov_len);
|
||||
else
|
||||
return writev(fd, vec, n);
|
||||
}
|
||||
|
||||
|
||||
static size_t uv__write_req_size(uv_write_t* req) {
|
||||
size_t size;
|
||||
|
||||
@@ -709,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) {
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if all write request data has been written, or 0 if there is still
|
||||
* more data to write.
|
||||
*
|
||||
* Note: the return value only says something about the *current* request.
|
||||
* There may still be other write requests sitting in the queue.
|
||||
*/
|
||||
static int uv__write_req_update(uv_stream_t* stream,
|
||||
uv_write_t* req,
|
||||
size_t n) {
|
||||
uv_buf_t* buf;
|
||||
size_t len;
|
||||
|
||||
assert(n <= stream->write_queue_size);
|
||||
stream->write_queue_size -= n;
|
||||
|
||||
buf = req->bufs + req->write_index;
|
||||
|
||||
do {
|
||||
len = n < buf->len ? n : buf->len;
|
||||
buf->base += len;
|
||||
buf->len -= len;
|
||||
buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */
|
||||
n -= len;
|
||||
} while (n > 0);
|
||||
|
||||
req->write_index = buf - req->bufs;
|
||||
|
||||
return req->write_index == req->nbufs;
|
||||
}
|
||||
|
||||
|
||||
static void uv__write_req_finish(uv_write_t* req) {
|
||||
uv_stream_t* stream = req->handle;
|
||||
|
||||
@@ -829,102 +879,32 @@ start:
|
||||
*pi = fd_to_send;
|
||||
}
|
||||
|
||||
do {
|
||||
do
|
||||
n = sendmsg(uv__stream_fd(stream), &msg, 0);
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
/*
|
||||
* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
|
||||
#else
|
||||
while (n == -1 && errno == EINTR);
|
||||
#endif
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
|
||||
/* Ensure the handle isn't sent again in case this is a partial write. */
|
||||
if (n >= 0)
|
||||
req->send_handle = NULL;
|
||||
} else {
|
||||
do {
|
||||
if (iovcnt == 1) {
|
||||
n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
|
||||
} else {
|
||||
n = writev(uv__stream_fd(stream), iov, iovcnt);
|
||||
}
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
/*
|
||||
* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
|
||||
#else
|
||||
while (n == -1 && errno == EINTR);
|
||||
#endif
|
||||
do
|
||||
n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
if (!WRITE_RETRY_ON_ERROR(req->send_handle)) {
|
||||
err = UV__ERR(errno);
|
||||
goto error;
|
||||
} else if (stream->flags & UV_STREAM_BLOCKING) {
|
||||
/* If this is a blocking stream, try again. */
|
||||
goto start;
|
||||
}
|
||||
} else {
|
||||
/* Successful write */
|
||||
|
||||
while (n >= 0) {
|
||||
uv_buf_t* buf = &(req->bufs[req->write_index]);
|
||||
size_t len = buf->len;
|
||||
|
||||
assert(req->write_index < req->nbufs);
|
||||
|
||||
if ((size_t)n < len) {
|
||||
buf->base += n;
|
||||
buf->len -= n;
|
||||
stream->write_queue_size -= n;
|
||||
n = 0;
|
||||
|
||||
/* There is more to write. */
|
||||
if (stream->flags & UV_STREAM_BLOCKING) {
|
||||
/*
|
||||
* If we're blocking then we should not be enabling the write
|
||||
* watcher - instead we need to try again.
|
||||
*/
|
||||
goto start;
|
||||
} else {
|
||||
/* Break loop and ensure the watcher is pending. */
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Finished writing the buf at index req->write_index. */
|
||||
req->write_index++;
|
||||
|
||||
assert((size_t)n >= len);
|
||||
n -= len;
|
||||
|
||||
assert(stream->write_queue_size >= len);
|
||||
stream->write_queue_size -= len;
|
||||
|
||||
if (req->write_index == req->nbufs) {
|
||||
/* Then we're done! */
|
||||
assert(n == 0);
|
||||
uv__write_req_finish(req);
|
||||
/* TODO: start trying to write the next request. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
|
||||
err = UV__ERR(errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Either we've counted n down to zero or we've got EAGAIN. */
|
||||
assert(n == 0 || n == -1);
|
||||
if (n >= 0 && uv__write_req_update(stream, req, n)) {
|
||||
uv__write_req_finish(req);
|
||||
return; /* TODO(bnoordhuis) Start trying to write the next request. */
|
||||
}
|
||||
|
||||
/* Only non-blocking streams should use the write_watcher. */
|
||||
assert(!(stream->flags & UV_STREAM_BLOCKING));
|
||||
/* If this is a blocking stream, try again. */
|
||||
if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
|
||||
goto start;
|
||||
|
||||
/* We're not done. */
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
@@ -947,10 +927,16 @@ error:
|
||||
static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
uv_write_t* req;
|
||||
QUEUE* q;
|
||||
QUEUE pq;
|
||||
|
||||
while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
|
||||
if (QUEUE_EMPTY(&stream->write_completed_queue))
|
||||
return;
|
||||
|
||||
QUEUE_MOVE(&stream->write_completed_queue, &pq);
|
||||
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
/* Pop a req off write_completed_queue. */
|
||||
q = QUEUE_HEAD(&stream->write_completed_queue);
|
||||
q = QUEUE_HEAD(&pq);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
QUEUE_REMOVE(q);
|
||||
uv__req_unregister(stream->loop, req);
|
||||
@@ -966,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
if (req->cb)
|
||||
req->cb(req, req->error);
|
||||
}
|
||||
|
||||
assert(QUEUE_EMPTY(&stream->write_completed_queue));
|
||||
}
|
||||
|
||||
|
||||
@@ -1015,13 +999,13 @@ uv_handle_type uv__handle_type(int fd) {
|
||||
|
||||
|
||||
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
|
||||
stream->flags |= UV_STREAM_READ_EOF;
|
||||
stream->flags |= UV_HANDLE_READ_EOF;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
stream->read_cb(stream, UV_EOF, buf);
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
}
|
||||
|
||||
|
||||
@@ -1134,7 +1118,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
int err;
|
||||
int is_ipc;
|
||||
|
||||
stream->flags &= ~UV_STREAM_READ_PARTIAL;
|
||||
stream->flags &= ~UV_HANDLE_READ_PARTIAL;
|
||||
|
||||
/* Prevent loop starvation when the data comes in as fast as (or faster than)
|
||||
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
|
||||
@@ -1143,11 +1127,11 @@ static void uv__read(uv_stream_t* stream) {
|
||||
|
||||
is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
|
||||
|
||||
/* XXX: Maybe instead of having UV_STREAM_READING we just test if
|
||||
/* XXX: Maybe instead of having UV_HANDLE_READING we just test if
|
||||
* tcp->read_cb is NULL or not?
|
||||
*/
|
||||
while (stream->read_cb
|
||||
&& (stream->flags & UV_STREAM_READING)
|
||||
&& (stream->flags & UV_HANDLE_READING)
|
||||
&& (count-- > 0)) {
|
||||
assert(stream->alloc_cb != NULL);
|
||||
|
||||
@@ -1188,7 +1172,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
/* Error */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
/* Wait for the next one. */
|
||||
if (stream->flags & UV_STREAM_READING) {
|
||||
if (stream->flags & UV_HANDLE_READING) {
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
@@ -1201,8 +1185,8 @@ static void uv__read(uv_stream_t* stream) {
|
||||
} else {
|
||||
/* Error. User should call uv_close(). */
|
||||
stream->read_cb(stream, UV__ERR(errno), &buf);
|
||||
if (stream->flags & UV_STREAM_READING) {
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
if (stream->flags & UV_HANDLE_READING) {
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
@@ -1252,7 +1236,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
|
||||
/* Return if we didn't fill the buffer, there is no more data to read. */
|
||||
if (nread < buflen) {
|
||||
stream->flags |= UV_STREAM_READ_PARTIAL;
|
||||
stream->flags |= UV_HANDLE_READ_PARTIAL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1273,9 +1257,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
stream->type == UV_TTY ||
|
||||
stream->type == UV_NAMED_PIPE);
|
||||
|
||||
if (!(stream->flags & UV_STREAM_WRITABLE) ||
|
||||
stream->flags & UV_STREAM_SHUT ||
|
||||
stream->flags & UV_STREAM_SHUTTING ||
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE) ||
|
||||
stream->flags & UV_HANDLE_SHUT ||
|
||||
stream->flags & UV_HANDLE_SHUTTING ||
|
||||
uv__is_closing(stream)) {
|
||||
return UV_ENOTCONN;
|
||||
}
|
||||
@@ -1287,7 +1271,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
req->handle = stream;
|
||||
req->cb = cb;
|
||||
stream->shutdown_req = req;
|
||||
stream->flags |= UV_STREAM_SHUTTING;
|
||||
stream->flags |= UV_HANDLE_SHUTTING;
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
@@ -1304,7 +1288,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
assert(stream->type == UV_TCP ||
|
||||
stream->type == UV_NAMED_PIPE ||
|
||||
stream->type == UV_TTY);
|
||||
assert(!(stream->flags & UV_CLOSING));
|
||||
assert(!(stream->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__stream_connect(stream);
|
||||
@@ -1327,9 +1311,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
* report the EOF yet because there is still data to read.
|
||||
*/
|
||||
if ((events & POLLHUP) &&
|
||||
(stream->flags & UV_STREAM_READING) &&
|
||||
(stream->flags & UV_STREAM_READ_PARTIAL) &&
|
||||
!(stream->flags & UV_STREAM_READ_EOF)) {
|
||||
(stream->flags & UV_HANDLE_READING) &&
|
||||
(stream->flags & UV_HANDLE_READ_PARTIAL) &&
|
||||
!(stream->flags & UV_HANDLE_READ_EOF)) {
|
||||
uv_buf_t buf = { NULL, 0 };
|
||||
uv__stream_eof(stream, &buf);
|
||||
}
|
||||
@@ -1419,7 +1403,7 @@ int uv_write2(uv_write_t* req,
|
||||
if (uv__stream_fd(stream) < 0)
|
||||
return UV_EBADF;
|
||||
|
||||
if (!(stream->flags & UV_STREAM_WRITABLE))
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return -EPIPE;
|
||||
|
||||
if (send_handle) {
|
||||
@@ -1489,7 +1473,7 @@ int uv_write2(uv_write_t* req,
|
||||
* if this assert fires then somehow the blocking stream isn't being
|
||||
* sufficiently flushed in uv__write.
|
||||
*/
|
||||
assert(!(stream->flags & UV_STREAM_BLOCKING));
|
||||
assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES));
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
@@ -1558,7 +1542,7 @@ int uv_try_write(uv_stream_t* stream,
|
||||
}
|
||||
|
||||
if (written == 0 && req_size != 0)
|
||||
return UV_EAGAIN;
|
||||
return req.error < 0 ? req.error : UV_EAGAIN;
|
||||
else
|
||||
return written;
|
||||
}
|
||||
@@ -1570,16 +1554,16 @@ int uv_read_start(uv_stream_t* stream,
|
||||
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
|
||||
stream->type == UV_TTY);
|
||||
|
||||
if (stream->flags & UV_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!(stream->flags & UV_STREAM_READABLE))
|
||||
if (!(stream->flags & UV_HANDLE_READABLE))
|
||||
return -ENOTCONN;
|
||||
|
||||
/* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
|
||||
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
|
||||
* expresses the desired state of the user.
|
||||
*/
|
||||
stream->flags |= UV_STREAM_READING;
|
||||
stream->flags |= UV_HANDLE_READING;
|
||||
|
||||
/* TODO: try to do the read inline? */
|
||||
/* TODO: keep track of tcp state. If we've gotten a EOF then we should
|
||||
@@ -1600,10 +1584,10 @@ int uv_read_start(uv_stream_t* stream,
|
||||
|
||||
|
||||
int uv_read_stop(uv_stream_t* stream) {
|
||||
if (!(stream->flags & UV_STREAM_READING))
|
||||
if (!(stream->flags & UV_HANDLE_READING))
|
||||
return 0;
|
||||
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
@@ -1616,12 +1600,12 @@ int uv_read_stop(uv_stream_t* stream) {
|
||||
|
||||
|
||||
int uv_is_readable(const uv_stream_t* stream) {
|
||||
return !!(stream->flags & UV_STREAM_READABLE);
|
||||
return !!(stream->flags & UV_HANDLE_READABLE);
|
||||
}
|
||||
|
||||
|
||||
int uv_is_writable(const uv_stream_t* stream) {
|
||||
return !!(stream->flags & UV_STREAM_WRITABLE);
|
||||
return !!(stream->flags & UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1670,6 +1654,7 @@ void uv__stream_close(uv_stream_t* handle) {
|
||||
uv__io_close(handle->loop, &handle->io_watcher);
|
||||
uv_read_stop(handle);
|
||||
uv__handle_stop(handle);
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
|
||||
if (handle->io_watcher.fd != -1) {
|
||||
/* Don't close stdio file descriptors. Nothing good comes from it. */
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.freeram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
struct sysinfo info;
|
||||
|
||||
if (sysinfo(&info) == 0)
|
||||
return (uint64_t) info.totalram * info.mem_unit;
|
||||
return 0;
|
||||
}
|
||||
@@ -82,7 +82,7 @@ static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
|
||||
handle->flags |= flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Query to see if tcp socket is bound. */
|
||||
slen = sizeof(saddr);
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
@@ -216,7 +216,7 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
|
||||
err = maybe_new_socket(handle,
|
||||
addr->sa_family,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -235,12 +235,16 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
if (r == -1 && errno != 0) {
|
||||
if (errno == EINPROGRESS)
|
||||
; /* not an error */
|
||||
else if (errno == ECONNREFUSED)
|
||||
/* If we get a ECONNREFUSED wait until the next tick to report the
|
||||
* error. Solaris wants to report immediately--other unixes want to
|
||||
* wait.
|
||||
else if (errno == ECONNREFUSED
|
||||
#if defined(__OpenBSD__)
|
||||
|| errno == EINVAL
|
||||
#endif
|
||||
)
|
||||
/* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
|
||||
* next tick to report the error. Solaris and OpenBSD wants to report
|
||||
* immediately -- other unixes want to wait.
|
||||
*/
|
||||
handle->delayed_error = UV__ERR(errno);
|
||||
handle->delayed_error = UV__ERR(ECONNREFUSED);
|
||||
else
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@@ -272,51 +276,35 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
sock,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
if (uv__stream_fd(handle) < 0)
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getsockname(uv__stream_fd(handle), name, &socklen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->delayed_error)
|
||||
return handle->delayed_error;
|
||||
|
||||
if (uv__stream_fd(handle) < 0)
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getpeername(uv__stream_fd(handle), name, &socklen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +322,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
}
|
||||
|
||||
if (single_accept)
|
||||
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
|
||||
flags = 0;
|
||||
#if defined(__MVS__)
|
||||
@@ -401,9 +389,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_NODELAY;
|
||||
handle->flags |= UV_HANDLE_TCP_NODELAY;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_NODELAY;
|
||||
handle->flags &= ~UV_HANDLE_TCP_NODELAY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -419,9 +407,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_KEEPALIVE;
|
||||
handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_KEEPALIVE;
|
||||
handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
|
||||
|
||||
/* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
|
||||
* uv_tcp_t with an int that's almost never used...
|
||||
@@ -433,9 +421,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
|
||||
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
if (enable)
|
||||
handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
|
||||
handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
else
|
||||
handle->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,115 +37,127 @@
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#if defined(__GLIBC__) && !defined(__UCLIBC__)
|
||||
#include <gnu/libc-version.h> /* gnu_get_libc_version() */
|
||||
#endif
|
||||
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
|
||||
#endif
|
||||
|
||||
#if defined(UV__PTHREAD_BARRIER_FALLBACK)
|
||||
/* TODO: support barrier_attr */
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count) {
|
||||
/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
|
||||
#if defined(_AIX) || \
|
||||
defined(__OpenBSD__) || \
|
||||
!defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
struct _uv_barrier* b;
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || count == 0)
|
||||
return EINVAL;
|
||||
|
||||
if (barrier_attr != NULL)
|
||||
return ENOTSUP;
|
||||
return UV_EINVAL;
|
||||
|
||||
b = (_uv_barrier*)uv__malloc(sizeof(*b));
|
||||
if (b == NULL)
|
||||
return ENOMEM;
|
||||
return UV_ENOMEM;
|
||||
|
||||
b->in = 0;
|
||||
b->out = 0;
|
||||
b->threshold = count;
|
||||
|
||||
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
|
||||
rc = uv_mutex_init(&b->mutex);
|
||||
if (rc != 0)
|
||||
goto error2;
|
||||
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
|
||||
|
||||
rc = uv_cond_init(&b->cond);
|
||||
if (rc != 0)
|
||||
goto error;
|
||||
|
||||
barrier->b = b;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
error2:
|
||||
uv__free(b);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
int last;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
return UV_EINVAL;
|
||||
|
||||
b = barrier->b;
|
||||
/* Lock the mutex*/
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
/* Increment the count. If this is the first thread to reach the threshold,
|
||||
wake up waiters, unlock the mutex, then return
|
||||
PTHREAD_BARRIER_SERIAL_THREAD. */
|
||||
if (++b->in == b->threshold) {
|
||||
b->in = 0;
|
||||
b->out = b->threshold - 1;
|
||||
rc = pthread_cond_signal(&b->cond);
|
||||
assert(rc == 0);
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
b->out = b->threshold;
|
||||
uv_cond_signal(&b->cond);
|
||||
} else {
|
||||
do
|
||||
uv_cond_wait(&b->cond, &b->mutex);
|
||||
while (b->in != 0);
|
||||
}
|
||||
/* Otherwise, wait for other threads until in is set to 0,
|
||||
then return 0 to indicate this is not the first thread. */
|
||||
do {
|
||||
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
|
||||
break;
|
||||
} while (b->in != 0);
|
||||
|
||||
/* mark thread exit */
|
||||
b->out--;
|
||||
pthread_cond_signal(&b->cond);
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return rc;
|
||||
last = (--b->out == 0);
|
||||
if (!last)
|
||||
uv_cond_signal(&b->cond); /* Not needed for last thread. */
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
return last;
|
||||
}
|
||||
|
||||
int pthread_barrier_destroy(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
|
||||
b = barrier->b;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
assert(b->in == 0);
|
||||
assert(b->out == 0);
|
||||
|
||||
if (b->in > 0 || b->out > 0)
|
||||
rc = EBUSY;
|
||||
if (b->in != 0 || b->out != 0)
|
||||
abort();
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
uv_cond_destroy(&b->cond);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pthread_cond_destroy(&b->cond);
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
uv__free(barrier->b);
|
||||
barrier->b = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int rc;
|
||||
|
||||
rc = pthread_barrier_wait(barrier);
|
||||
if (rc != 0)
|
||||
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
|
||||
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -165,8 +177,21 @@ static size_t thread_stack_size(void) {
|
||||
if (lim.rlim_cur != RLIM_INFINITY) {
|
||||
/* pthread_attr_setstacksize() expects page-aligned values. */
|
||||
lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
|
||||
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
|
||||
return lim.rlim_cur;
|
||||
|
||||
/* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
|
||||
* too small to safely receive signals on.
|
||||
*
|
||||
* Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
|
||||
* the largest MINSIGSTKSZ of the architectures that musl supports) so
|
||||
* let's use that as a lower bound.
|
||||
*
|
||||
* We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
|
||||
* is between 28 and 133 KB when compiling against glibc, depending
|
||||
* on the architecture.
|
||||
*/
|
||||
if (lim.rlim_cur >= 8192)
|
||||
if (lim.rlim_cur >= PTHREAD_STACK_MIN)
|
||||
return lim.rlim_cur;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -181,13 +206,36 @@ static size_t thread_stack_size(void) {
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
uv_thread_options_t params;
|
||||
params.flags = UV_THREAD_NO_FLAGS;
|
||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||
}
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
void *arg) {
|
||||
int err;
|
||||
size_t stack_size;
|
||||
pthread_attr_t* attr;
|
||||
pthread_attr_t attr_storage;
|
||||
size_t pagesize;
|
||||
size_t stack_size;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
attr = NULL;
|
||||
stack_size = thread_stack_size();
|
||||
if (stack_size == 0) {
|
||||
stack_size = thread_stack_size();
|
||||
} else {
|
||||
pagesize = (size_t)getpagesize();
|
||||
/* Round up to the nearest page boundary. */
|
||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||
#ifdef PTHREAD_STACK_MIN
|
||||
if (stack_size < PTHREAD_STACK_MIN)
|
||||
stack_size = PTHREAD_STACK_MIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (stack_size > 0) {
|
||||
attr = &attr_storage;
|
||||
@@ -425,7 +473,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
|
||||
@@ -461,7 +509,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
|
||||
|
||||
@@ -590,7 +639,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
|
||||
|
||||
@@ -767,26 +816,9 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
return UV_ETIMEDOUT;
|
||||
|
||||
abort();
|
||||
#ifndef __SUNPRO_C
|
||||
return UV_EINVAL; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int r = pthread_barrier_wait(barrier);
|
||||
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
return r == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
uv_handle_type type;
|
||||
int flags;
|
||||
int newfd;
|
||||
int r;
|
||||
int saved_flags;
|
||||
int mode;
|
||||
char path[256];
|
||||
(void)unused; /* deprecated parameter is no longer needed */
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
* That restriction also applies to character devices like /dev/random
|
||||
@@ -111,6 +113,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
flags = 0;
|
||||
newfd = -1;
|
||||
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1)
|
||||
return UV__ERR(errno);
|
||||
mode = saved_flags & O_ACCMODE;
|
||||
|
||||
/* Reopen the file descriptor when it refers to a tty. This lets us put the
|
||||
* tty in non-blocking mode without affecting other processes that share it
|
||||
* with us.
|
||||
@@ -128,14 +139,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, O_RDWR);
|
||||
r = uv__open_cloexec(path, mode);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
if (r < 0) {
|
||||
/* fallback to using blocking writes */
|
||||
if (!readable)
|
||||
flags |= UV_STREAM_BLOCKING;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_BLOCKING_WRITES;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
@@ -154,22 +165,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pacify the compiler. */
|
||||
(void) &saved_flags;
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
@@ -177,7 +172,7 @@ skip:
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
if (!(flags & UV_HANDLE_BLOCKING_WRITES))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -194,10 +189,10 @@ skip:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (readable)
|
||||
flags |= UV_STREAM_READABLE;
|
||||
else
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#if defined(__MVS__)
|
||||
#include <xti.h>
|
||||
#endif
|
||||
#include <sys/un.h>
|
||||
|
||||
#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
|
||||
# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
@@ -92,8 +93,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
|
||||
assert(!(handle->flags & UV_UDP_PROCESSING));
|
||||
handle->flags |= UV_UDP_PROCESSING;
|
||||
assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
|
||||
handle->flags |= UV_HANDLE_UDP_PROCESSING;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_completed_queue);
|
||||
@@ -128,7 +129,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~UV_UDP_PROCESSING;
|
||||
handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
|
||||
}
|
||||
|
||||
|
||||
@@ -227,9 +228,22 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
assert(req != NULL);
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
h.msg_name = &req->addr;
|
||||
h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
|
||||
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
|
||||
if (req->addr.ss_family == AF_UNSPEC) {
|
||||
h.msg_name = NULL;
|
||||
h.msg_namelen = 0;
|
||||
} else {
|
||||
h.msg_name = &req->addr;
|
||||
if (req->addr.ss_family == AF_INET6)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in6);
|
||||
else if (req->addr.ss_family == AF_INET)
|
||||
h.msg_namelen = sizeof(struct sockaddr_in);
|
||||
else if (req->addr.ss_family == AF_UNIX)
|
||||
h.msg_namelen = sizeof(struct sockaddr_un);
|
||||
else {
|
||||
assert(0 && "unsupported address family");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
h.msg_iov = (struct iovec*) req->bufs;
|
||||
h.msg_iovlen = req->nbufs;
|
||||
|
||||
@@ -263,16 +277,30 @@ static void uv__udp_sendmsg(uv_udp_t* handle) {
|
||||
* are different from the BSDs: it _shares_ the port rather than steal it
|
||||
* from the current listener. While useful, it's not something we can emulate
|
||||
* on other platforms so we don't enable it.
|
||||
*
|
||||
* zOS does not support getsockname with SO_REUSEPORT option when using
|
||||
* AF_UNIX.
|
||||
*/
|
||||
static int uv__set_reuse(int fd) {
|
||||
int yes;
|
||||
|
||||
#if defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
yes = 1;
|
||||
|
||||
#if defined(SO_REUSEPORT) && defined(__MVS__)
|
||||
struct sockaddr_in sockfd;
|
||||
unsigned int sockfd_len = sizeof(sockfd);
|
||||
if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1)
|
||||
return UV__ERR(errno);
|
||||
if (sockfd.sin_family == AF_UNIX) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
} else {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#elif defined(SO_REUSEPORT) && !defined(__linux__)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
#else
|
||||
yes = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
|
||||
return UV__ERR(errno);
|
||||
#endif
|
||||
@@ -383,6 +411,50 @@ static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_connect(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen) {
|
||||
int err;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
err = connect(handle->io_watcher.fd, addr, addrlen);
|
||||
} while (err == -1 && errno == EINTR);
|
||||
|
||||
if (err)
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
int r;
|
||||
struct sockaddr addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
addr.sa_family = AF_UNSPEC;
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
r = connect(handle->io_watcher.fd, &addr, sizeof(addr));
|
||||
} while (r == -1 && errno == EINTR);
|
||||
|
||||
if (r == -1 && errno != EAFNOSUPPORT)
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
@@ -395,9 +467,11 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
if (addr) {
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* It's legal for send_queue_count > 0 even when the write_queue is empty;
|
||||
* it means there are error-state requests in the write_completed_queue that
|
||||
@@ -407,7 +481,10 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
|
||||
uv__req_init(handle->loop, req, UV_UDP_SEND);
|
||||
assert(addrlen <= sizeof(req->addr));
|
||||
memcpy(&req->addr, addr, addrlen);
|
||||
if (addr == NULL)
|
||||
req->addr.ss_family = AF_UNSPEC;
|
||||
else
|
||||
memcpy(&req->addr, addr, addrlen);
|
||||
req->send_cb = send_cb;
|
||||
req->handle = handle;
|
||||
req->nbufs = nbufs;
|
||||
@@ -427,7 +504,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
|
||||
if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
|
||||
uv__udp_sendmsg(handle);
|
||||
|
||||
/* `uv__udp_sendmsg` may not be able to do non-blocking write straight
|
||||
@@ -459,9 +536,13 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
if (handle->send_queue_count != 0)
|
||||
return UV_EAGAIN;
|
||||
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
if (addr) {
|
||||
err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
|
||||
}
|
||||
|
||||
memset(&h, 0, sizeof h);
|
||||
h.msg_name = (struct sockaddr*) addr;
|
||||
@@ -608,6 +689,7 @@ int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
|
||||
uv__io_init(&handle->io_watcher, uv__udp_io, fd);
|
||||
QUEUE_INIT(&handle->write_queue);
|
||||
QUEUE_INIT(&handle->write_completed_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -636,6 +718,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
return err;
|
||||
|
||||
handle->io_watcher.fd = sock;
|
||||
if (uv__udp_is_connected(handle))
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -743,13 +828,17 @@ int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
|
||||
IPV6_UNICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__)) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_TTL,
|
||||
IPV6_UNICAST_HOPS,
|
||||
ttl);
|
||||
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
}
|
||||
|
||||
|
||||
@@ -760,14 +849,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
* IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
@@ -783,14 +874,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
* IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
@@ -847,23 +940,24 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_udp_getpeername(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->io_watcher.fd == -1)
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getsockname(handle->io_watcher.fd, name, &socklen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
# include <malloc.h> /* malloc */
|
||||
#else
|
||||
# include <net/if.h> /* if_nametoindex */
|
||||
# include <sys/un.h> /* AF_UNIX, sockaddr_un */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -72,7 +73,9 @@ char* uv__strndup(const char* s, size_t n) {
|
||||
}
|
||||
|
||||
void* uv__malloc(size_t size) {
|
||||
return uv__allocator.local_malloc(size);
|
||||
if (size > 0)
|
||||
return uv__allocator.local_malloc(size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uv__free(void* ptr) {
|
||||
@@ -91,7 +94,10 @@ void* uv__calloc(size_t count, size_t size) {
|
||||
}
|
||||
|
||||
void* uv__realloc(void* ptr, size_t size) {
|
||||
return uv__allocator.local_realloc(ptr, size);
|
||||
if (size > 0)
|
||||
return uv__allocator.local_realloc(ptr, size);
|
||||
uv__free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
@@ -155,6 +161,18 @@ static const char* uv__unknown_err_code(int err) {
|
||||
return copy != NULL ? copy : "Unknown system error";
|
||||
}
|
||||
|
||||
#define UV_ERR_NAME_GEN_R(name, _) \
|
||||
case UV_## name: \
|
||||
uv__strscpy(buf, #name, buflen); break;
|
||||
char* uv_err_name_r(int err, char* buf, size_t buflen) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
|
||||
default: snprintf(buf, buflen, "Unknown system error %d", err);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#undef UV_ERR_NAME_GEN_R
|
||||
|
||||
|
||||
#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
|
||||
const char* uv_err_name(int err) {
|
||||
@@ -166,6 +184,19 @@ const char* uv_err_name(int err) {
|
||||
#undef UV_ERR_NAME_GEN
|
||||
|
||||
|
||||
#define UV_STRERROR_GEN_R(name, msg) \
|
||||
case UV_ ## name: \
|
||||
snprintf(buf, buflen, "%s", msg); break;
|
||||
char* uv_strerror_r(int err, char* buf, size_t buflen) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_STRERROR_GEN_R)
|
||||
default: snprintf(buf, buflen, "Unknown system error %d", err);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#undef UV_STRERROR_GEN_R
|
||||
|
||||
|
||||
#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
|
||||
const char* uv_strerror(int err) {
|
||||
switch (err) {
|
||||
@@ -192,6 +223,9 @@ int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
addr->sin6_family = AF_INET6;
|
||||
addr->sin6_port = htons(port);
|
||||
#ifdef SIN6_LEN
|
||||
addr->sin6_len = sizeof(*addr);
|
||||
#endif
|
||||
|
||||
zone_index = strchr(ip, '%');
|
||||
if (zone_index != NULL) {
|
||||
@@ -284,17 +318,20 @@ int uv_tcp_connect(uv_connect_t* req,
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
uv_udp_send_cb send_cb) {
|
||||
int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Disconnect the handle */
|
||||
if (addr == NULL) {
|
||||
if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
|
||||
return UV_ENOTCONN;
|
||||
|
||||
return uv__udp_disconnect(handle);
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
@@ -302,6 +339,70 @@ int uv_udp_send(uv_udp_send_t* req,
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
if (handle->flags & UV_HANDLE_UDP_CONNECTED)
|
||||
return UV_EISCONN;
|
||||
|
||||
return uv__udp_connect(handle, addr, addrlen);
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_is_connected(uv_udp_t* handle) {
|
||||
struct sockaddr_storage addr;
|
||||
int addrlen;
|
||||
if (handle->type != UV_UDP)
|
||||
return 0;
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
|
||||
return 0;
|
||||
|
||||
return addrlen > 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
|
||||
unsigned int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
|
||||
return UV_EISCONN;
|
||||
|
||||
if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
|
||||
return UV_EDESTADDRREQ;
|
||||
|
||||
if (addr != NULL) {
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
#if defined(AF_UNIX) && !defined(_WIN32)
|
||||
else if (addr->sa_family == AF_UNIX)
|
||||
addrlen = sizeof(struct sockaddr_un);
|
||||
#endif
|
||||
else
|
||||
return UV_EINVAL;
|
||||
} else {
|
||||
addrlen = 0;
|
||||
}
|
||||
|
||||
return addrlen;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr,
|
||||
uv_udp_send_cb send_cb) {
|
||||
int addrlen;
|
||||
|
||||
addrlen = uv__udp_check_before_send(handle, addr);
|
||||
if (addrlen < 0)
|
||||
return addrlen;
|
||||
|
||||
return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
|
||||
}
|
||||
|
||||
@@ -310,17 +411,11 @@ int uv_udp_try_send(uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
const struct sockaddr* addr) {
|
||||
unsigned int addrlen;
|
||||
int addrlen;
|
||||
|
||||
if (handle->type != UV_UDP)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (addr->sa_family == AF_INET)
|
||||
addrlen = sizeof(struct sockaddr_in);
|
||||
else if (addr->sa_family == AF_INET6)
|
||||
addrlen = sizeof(struct sockaddr_in6);
|
||||
else
|
||||
return UV_EINVAL;
|
||||
addrlen = uv__udp_check_before_send(handle, addr);
|
||||
if (addrlen < 0)
|
||||
return addrlen;
|
||||
|
||||
return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
|
||||
}
|
||||
@@ -357,7 +452,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
|
||||
|
||||
if (h->flags & UV__HANDLE_INTERNAL) continue;
|
||||
if (h->flags & UV_HANDLE_INTERNAL) continue;
|
||||
walk_cb(h, arg);
|
||||
}
|
||||
}
|
||||
@@ -386,9 +481,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
|
||||
|
||||
fprintf(stream,
|
||||
"[%c%c%c] %-8s %p\n",
|
||||
"R-"[!(h->flags & UV__HANDLE_REF)],
|
||||
"A-"[!(h->flags & UV__HANDLE_ACTIVE)],
|
||||
"I-"[!(h->flags & UV__HANDLE_INTERNAL)],
|
||||
"R-"[!(h->flags & UV_HANDLE_REF)],
|
||||
"A-"[!(h->flags & UV_HANDLE_ACTIVE)],
|
||||
"I-"[!(h->flags & UV_HANDLE_INTERNAL)],
|
||||
type,
|
||||
(void*)h);
|
||||
}
|
||||
@@ -541,37 +636,66 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
|
||||
dent = dents[(*nbufs)++];
|
||||
|
||||
ent->name = dent->d_name;
|
||||
ent->type = uv__fs_get_dirent_type(dent);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
|
||||
uv_dirent_type_t type;
|
||||
|
||||
#ifdef HAVE_DIRENT_TYPES
|
||||
switch (dent->d_type) {
|
||||
case UV__DT_DIR:
|
||||
ent->type = UV_DIRENT_DIR;
|
||||
type = UV_DIRENT_DIR;
|
||||
break;
|
||||
case UV__DT_FILE:
|
||||
ent->type = UV_DIRENT_FILE;
|
||||
type = UV_DIRENT_FILE;
|
||||
break;
|
||||
case UV__DT_LINK:
|
||||
ent->type = UV_DIRENT_LINK;
|
||||
type = UV_DIRENT_LINK;
|
||||
break;
|
||||
case UV__DT_FIFO:
|
||||
ent->type = UV_DIRENT_FIFO;
|
||||
type = UV_DIRENT_FIFO;
|
||||
break;
|
||||
case UV__DT_SOCKET:
|
||||
ent->type = UV_DIRENT_SOCKET;
|
||||
type = UV_DIRENT_SOCKET;
|
||||
break;
|
||||
case UV__DT_CHAR:
|
||||
ent->type = UV_DIRENT_CHAR;
|
||||
type = UV_DIRENT_CHAR;
|
||||
break;
|
||||
case UV__DT_BLOCK:
|
||||
ent->type = UV_DIRENT_BLOCK;
|
||||
type = UV_DIRENT_BLOCK;
|
||||
break;
|
||||
default:
|
||||
ent->type = UV_DIRENT_UNKNOWN;
|
||||
type = UV_DIRENT_UNKNOWN;
|
||||
}
|
||||
#else
|
||||
ent->type = UV_DIRENT_UNKNOWN;
|
||||
type = UV_DIRENT_UNKNOWN;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return type;
|
||||
}
|
||||
|
||||
void uv__fs_readdir_cleanup(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
uv_dirent_t* dirents;
|
||||
int i;
|
||||
|
||||
if (req->ptr == NULL)
|
||||
return;
|
||||
|
||||
dir = (uv_dir_t*)req->ptr;
|
||||
dirents = dir->dirents;
|
||||
req->ptr = NULL;
|
||||
|
||||
if (dirents == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; i < req->result; ++i) {
|
||||
uv__free((char*) dirents[i].name);
|
||||
dirents[i].name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -641,7 +765,7 @@ int uv_loop_close(uv_loop_t* loop) {
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
if (!(h->flags & UV__HANDLE_INTERNAL))
|
||||
if (!(h->flags & UV_HANDLE_INTERNAL))
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "uv.h"
|
||||
#include "uv/tree.h"
|
||||
#include "queue.h"
|
||||
#include "strscpy.h"
|
||||
|
||||
#if EDOM > 0
|
||||
# define UV__ERR(x) (-(x))
|
||||
@@ -59,22 +60,68 @@ extern int snprintf(char*, size_t, const char*, ...);
|
||||
#define STATIC_ASSERT(expr) \
|
||||
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Handle flags. Some flags are specific to Windows or UNIX. */
|
||||
enum {
|
||||
UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */
|
||||
UV__HANDLE_INTERNAL = 0x8000,
|
||||
UV__HANDLE_ACTIVE = 0x4000,
|
||||
UV__HANDLE_REF = 0x2000,
|
||||
UV__HANDLE_CLOSING = 0 /* no-op on unix */
|
||||
/* Used by all handles. */
|
||||
UV_HANDLE_CLOSING = 0x00000001,
|
||||
UV_HANDLE_CLOSED = 0x00000002,
|
||||
UV_HANDLE_ACTIVE = 0x00000004,
|
||||
UV_HANDLE_REF = 0x00000008,
|
||||
UV_HANDLE_INTERNAL = 0x00000010,
|
||||
UV_HANDLE_ENDGAME_QUEUED = 0x00000020,
|
||||
|
||||
/* Used by streams. */
|
||||
UV_HANDLE_LISTENING = 0x00000040,
|
||||
UV_HANDLE_CONNECTION = 0x00000080,
|
||||
UV_HANDLE_SHUTTING = 0x00000100,
|
||||
UV_HANDLE_SHUT = 0x00000200,
|
||||
UV_HANDLE_READ_PARTIAL = 0x00000400,
|
||||
UV_HANDLE_READ_EOF = 0x00000800,
|
||||
|
||||
/* Used by streams and UDP handles. */
|
||||
UV_HANDLE_READING = 0x00001000,
|
||||
UV_HANDLE_BOUND = 0x00002000,
|
||||
UV_HANDLE_READABLE = 0x00004000,
|
||||
UV_HANDLE_WRITABLE = 0x00008000,
|
||||
UV_HANDLE_READ_PENDING = 0x00010000,
|
||||
UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000,
|
||||
UV_HANDLE_ZERO_READ = 0x00040000,
|
||||
UV_HANDLE_EMULATE_IOCP = 0x00080000,
|
||||
UV_HANDLE_BLOCKING_WRITES = 0x00100000,
|
||||
UV_HANDLE_CANCELLATION_PENDING = 0x00200000,
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
UV_HANDLE_IPV6 = 0x00400000,
|
||||
|
||||
/* Only used by uv_tcp_t handles. */
|
||||
UV_HANDLE_TCP_NODELAY = 0x01000000,
|
||||
UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
|
||||
UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
|
||||
UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
|
||||
UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000,
|
||||
UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
|
||||
|
||||
/* Only used by uv_udp_t handles. */
|
||||
UV_HANDLE_UDP_PROCESSING = 0x01000000,
|
||||
UV_HANDLE_UDP_CONNECTED = 0x02000000,
|
||||
|
||||
/* Only used by uv_pipe_t handles. */
|
||||
UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,
|
||||
UV_HANDLE_PIPESERVER = 0x02000000,
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
UV_HANDLE_TTY_READABLE = 0x01000000,
|
||||
UV_HANDLE_TTY_RAW = 0x02000000,
|
||||
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
|
||||
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
|
||||
|
||||
/* Only used by uv_signal_t handles. */
|
||||
UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000,
|
||||
UV_SIGNAL_ONE_SHOT = 0x02000000,
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
UV_HANDLE_POLL_SLOW = 0x01000000
|
||||
};
|
||||
#else
|
||||
# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200
|
||||
# define UV__SIGNAL_ONE_SHOT 0x100
|
||||
# define UV__HANDLE_INTERNAL 0x80
|
||||
# define UV__HANDLE_ACTIVE 0x40
|
||||
# define UV__HANDLE_REF 0x20
|
||||
# define UV__HANDLE_CLOSING 0x01
|
||||
#endif
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|
||||
|
||||
@@ -96,6 +143,14 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
unsigned int addrlen,
|
||||
unsigned int flags);
|
||||
|
||||
int uv__udp_connect(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen);
|
||||
|
||||
int uv__udp_disconnect(uv_udp_t* handle);
|
||||
|
||||
int uv__udp_is_connected(uv_udp_t* handle);
|
||||
|
||||
int uv__udp_send(uv_udp_send_t* req,
|
||||
uv_udp_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
@@ -119,8 +174,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
|
||||
|
||||
enum uv__work_kind {
|
||||
UV__WORK_CPU,
|
||||
UV__WORK_FAST_IO,
|
||||
UV__WORK_SLOW_IO
|
||||
};
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work *w,
|
||||
enum uv__work_kind kind,
|
||||
void (*work)(struct uv__work *w),
|
||||
void (*done)(struct uv__work *w, int status));
|
||||
|
||||
@@ -131,6 +193,12 @@ size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
|
||||
int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
|
||||
|
||||
void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
void uv__fs_readdir_cleanup(uv_fs_t* req);
|
||||
uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent);
|
||||
|
||||
int uv__next_timeout(const uv_loop_t* loop);
|
||||
void uv__run_timers(uv_loop_t* loop);
|
||||
void uv__timer_close(uv_timer_t* handle);
|
||||
|
||||
#define uv__has_active_reqs(loop) \
|
||||
((loop)->active_reqs.count > 0)
|
||||
@@ -164,49 +232,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
while (0)
|
||||
|
||||
#define uv__is_active(h) \
|
||||
(((h)->flags & UV__HANDLE_ACTIVE) != 0)
|
||||
(((h)->flags & UV_HANDLE_ACTIVE) != 0)
|
||||
|
||||
#define uv__is_closing(h) \
|
||||
(((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
|
||||
(((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
|
||||
|
||||
#define uv__handle_start(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \
|
||||
(h)->flags |= UV_HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_stop(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \
|
||||
(h)->flags &= ~UV_HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_ref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) break; \
|
||||
(h)->flags |= UV_HANDLE_REF; \
|
||||
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_unref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
|
||||
if (((h)->flags & UV_HANDLE_REF) == 0) break; \
|
||||
(h)->flags &= ~UV_HANDLE_REF; \
|
||||
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__has_ref(h) \
|
||||
(((h)->flags & UV__HANDLE_REF) != 0)
|
||||
(((h)->flags & UV_HANDLE_REF) != 0)
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define uv__handle_platform_init(h) ((h)->u.fd = -1)
|
||||
@@ -218,7 +284,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
do { \
|
||||
(h)->loop = (loop_); \
|
||||
(h)->type = (type_); \
|
||||
(h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
|
||||
(h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
|
||||
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
|
||||
uv__handle_platform_init(h); \
|
||||
} \
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
const char* uv_handle_type_name(uv_handle_type type) {
|
||||
switch (type) {
|
||||
#define XX(uc,lc) case UV_##uc: return #lc;
|
||||
UV_HANDLE_TYPE_MAP(XX)
|
||||
UV_HANDLE_TYPE_MAP(XX)
|
||||
#undef XX
|
||||
case UV_FILE: return "file";
|
||||
case UV_HANDLE_TYPE_MAX:
|
||||
case UV_UNKNOWN_HANDLE: return NULL;
|
||||
case UV_FILE: return "file";
|
||||
case UV_HANDLE_TYPE_MAX:
|
||||
case UV_UNKNOWN_HANDLE: return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -31,10 +31,12 @@ void uv_handle_set_data(uv_handle_t* handle, void* data) {
|
||||
const char* uv_req_type_name(uv_req_type type) {
|
||||
switch (type) {
|
||||
#define XX(uc,lc) case UV_##uc: return #lc;
|
||||
UV_REQ_TYPE_MAP(XX)
|
||||
UV_REQ_TYPE_MAP(XX)
|
||||
#undef XX
|
||||
case UV_REQ_TYPE_MAX:
|
||||
case UV_UNKNOWN_REQ: return NULL;
|
||||
case UV_REQ_TYPE_MAX:
|
||||
case UV_UNKNOWN_REQ:
|
||||
default: /* UV_REQ_TYPE_PRIVATE */
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
!handle->async_sent) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
@@ -73,7 +73,7 @@ int uv_async_send(uv_async_t* handle) {
|
||||
|
||||
/* The user should make sure never to call uv_async_send to a closing or
|
||||
* closed handle. */
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
if (!uv__atomic_exchange_set(&handle->async_sent)) {
|
||||
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
|
||||
@@ -90,7 +90,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
|
||||
|
||||
handle->async_sent = 0;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (handle->async_cb != NULL) {
|
||||
handle->async_cb(handle);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "heap-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
/* uv_once initialization guards */
|
||||
@@ -223,6 +224,7 @@ static void uv_init(void) {
|
||||
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
struct heap* timer_heap;
|
||||
int err;
|
||||
|
||||
/* Initialize libuv itself first */
|
||||
@@ -248,7 +250,13 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
|
||||
loop->endgame_handles = NULL;
|
||||
|
||||
RB_INIT(&loop->timers);
|
||||
loop->timer_heap = timer_heap = (heap*)uv__malloc(sizeof(*timer_heap));
|
||||
if (timer_heap == NULL) {
|
||||
err = UV_ENOMEM;
|
||||
goto fail_timers_alloc;
|
||||
}
|
||||
|
||||
heap_init(timer_heap);
|
||||
|
||||
loop->check_handles = NULL;
|
||||
loop->prepare_handles = NULL;
|
||||
@@ -275,7 +283,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
@@ -287,6 +295,10 @@ fail_async_init:
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv__free(timer_heap);
|
||||
loop->timer_heap = NULL;
|
||||
|
||||
fail_timers_alloc:
|
||||
CloseHandle(loop->iocp);
|
||||
loop->iocp = INVALID_HANDLE_VALUE;
|
||||
|
||||
@@ -294,6 +306,13 @@ fail_mutex_init:
|
||||
}
|
||||
|
||||
|
||||
void uv_update_time(uv_loop_t* loop) {
|
||||
uint64_t new_time = uv__hrtime(1000);
|
||||
assert(new_time >= loop->time);
|
||||
loop->time = new_time;
|
||||
}
|
||||
|
||||
|
||||
void uv__once_init(void) {
|
||||
uv_once(&uv_init_guard_, uv_init);
|
||||
}
|
||||
@@ -322,6 +341,9 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
uv__free(loop->timer_heap);
|
||||
loop->timer_heap = NULL;
|
||||
|
||||
CloseHandle(loop->iocp);
|
||||
}
|
||||
|
||||
@@ -361,6 +383,57 @@ int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
DWORD bytes;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* overlapped;
|
||||
uv_req_t* req;
|
||||
int repeat;
|
||||
uint64_t timeout_time;
|
||||
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
GetQueuedCompletionStatus(loop->iocp,
|
||||
&bytes,
|
||||
&key,
|
||||
&overlapped,
|
||||
timeout);
|
||||
|
||||
if (overlapped) {
|
||||
/* Package was dequeued */
|
||||
req = uv_overlapped_to_req(overlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
* so update the loop time here.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
} else if (GetLastError() != WAIT_TIMEOUT) {
|
||||
/* Serious error */
|
||||
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
|
||||
} else if (timeout > 0) {
|
||||
/* GetQueuedCompletionStatus can occasionally return a little early.
|
||||
* Make sure that the desired timeout target time is reached.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
if (timeout_time > loop->time) {
|
||||
timeout = (DWORD)(timeout_time - loop->time);
|
||||
/* The first call to GetQueuedCompletionStatus should return very
|
||||
* close to the target time and the second should reach it, but
|
||||
* this is not stated in the documentation. To make sure a busy
|
||||
* loop cannot happen, the timeout is increased exponentially
|
||||
* starting on the third round.
|
||||
*/
|
||||
timeout += repeat ? (1 << (repeat - 1)) : 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
BOOL success;
|
||||
uv_req_t* req;
|
||||
@@ -443,7 +516,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
uv_update_time(loop);
|
||||
uv_process_timers(loop);
|
||||
uv__run_timers(loop);
|
||||
|
||||
ran_pending = uv_process_reqs(loop);
|
||||
uv_idle_invoke(loop);
|
||||
@@ -453,7 +526,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
|
||||
uv__poll(loop, timeout);
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
uv__poll(loop, timeout);
|
||||
else
|
||||
uv__poll_wine(loop, timeout);
|
||||
|
||||
|
||||
uv_check_invoke(loop);
|
||||
uv_process_endgames(loop);
|
||||
@@ -467,7 +544,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
|
||||
* the check.
|
||||
*/
|
||||
uv_process_timers(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
@@ -548,3 +625,30 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_cpumask_size(void) {
|
||||
return (int)(sizeof(DWORD_PTR) * 8);
|
||||
}
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen,
|
||||
int delayed_error) {
|
||||
|
||||
int result;
|
||||
uv_os_fd_t fd;
|
||||
|
||||
result = uv_fileno(handle, &fd);
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
if (delayed_error)
|
||||
return uv_translate_sys_error(delayed_error);
|
||||
|
||||
result = func((SOCKET) fd, name, namelen);
|
||||
if (result != 0)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ void uv_dlclose(uv_lib_t* lib) {
|
||||
|
||||
|
||||
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
|
||||
*ptr = (void*) GetProcAddress(lib->handle, name);
|
||||
/* Cast though integer to suppress pedantic warning about forbidden cast. */
|
||||
*ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
|
||||
return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
|
||||
}
|
||||
|
||||
@@ -75,8 +76,9 @@ const char* uv_dlerror(const uv_lib_t* lib) {
|
||||
|
||||
|
||||
static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
|
||||
DWORD_PTR args[1] = { (DWORD_PTR) errorno };
|
||||
LPCSTR fallback_error = "error: %1!d!";
|
||||
static const CHAR fallback_error[] = "error: %1!d!";
|
||||
DWORD_PTR args[1];
|
||||
args[0] = (DWORD_PTR) errorno;
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||||
@@ -107,7 +109,8 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
(LPSTR) &lib->errmsg, 0, NULL);
|
||||
|
||||
if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
|
||||
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
|
||||
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
|
||||
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
||||
|
||||
@@ -85,7 +85,7 @@ static void uv_relative_path(const WCHAR* filename,
|
||||
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
WCHAR** file) {
|
||||
size_t len, i;
|
||||
|
||||
|
||||
if (filename == NULL) {
|
||||
if (dir != NULL)
|
||||
*dir = NULL;
|
||||
@@ -217,11 +217,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv__free(long_path);
|
||||
long_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (long_path) {
|
||||
uv__free(pathw);
|
||||
pathw = long_path;
|
||||
if (long_path) {
|
||||
uv__free(pathw);
|
||||
pathw = long_path;
|
||||
}
|
||||
}
|
||||
|
||||
dir_to_watch = pathw;
|
||||
@@ -232,8 +232,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
*/
|
||||
|
||||
/* Convert to short path. */
|
||||
short_path = short_path_buffer;
|
||||
if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
|
||||
if (GetShortPathNameW(pathw,
|
||||
short_path_buffer,
|
||||
ARRAY_SIZE(short_path_buffer))) {
|
||||
short_path = short_path_buffer;
|
||||
} else {
|
||||
short_path = NULL;
|
||||
}
|
||||
|
||||
@@ -421,7 +424,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
* - We are not active, just ignore the callback
|
||||
*/
|
||||
if (!uv__is_active(handle)) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
return;
|
||||
@@ -545,7 +548,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
|
||||
offset = file_info->NextEntryOffset;
|
||||
} while (offset && !(handle->flags & UV__HANDLE_CLOSING));
|
||||
} while (offset && !(handle->flags & UV_HANDLE_CLOSING));
|
||||
} else {
|
||||
handle->cb(handle, NULL, UV_CHANGE, 0);
|
||||
}
|
||||
@@ -554,7 +557,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_fs_event_queue_readdirchanges(loop, handle);
|
||||
} else {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
@@ -575,7 +578,7 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
|
||||
|
||||
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
|
||||
if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
if (handle->buffer) {
|
||||
|
||||
@@ -58,7 +58,11 @@
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
uv__fs_work, \
|
||||
uv__fs_done); \
|
||||
return 0; \
|
||||
} else { \
|
||||
uv__fs_work(&req->work_req); \
|
||||
@@ -95,14 +99,17 @@
|
||||
return; \
|
||||
}
|
||||
|
||||
#define MILLIONu (1000U * 1000U)
|
||||
#define BILLIONu (1000U * 1000U * 1000U)
|
||||
|
||||
#define FILETIME_TO_UINT(filetime) \
|
||||
(*((uint64_t*) &(filetime)) - 116444736000000000ULL)
|
||||
(*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
|
||||
|
||||
#define FILETIME_TO_TIME_T(filetime) \
|
||||
(FILETIME_TO_UINT(filetime) / 10000000ULL)
|
||||
(FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
|
||||
|
||||
#define FILETIME_TO_TIME_NS(filetime, secs) \
|
||||
((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
|
||||
((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
|
||||
|
||||
#define FILETIME_TO_TIMESPEC(ts, filetime) \
|
||||
do { \
|
||||
@@ -112,8 +119,8 @@
|
||||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
|
||||
116444736000000000ULL; \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
|
||||
(uint64_t) 116444736 * BILLIONu; \
|
||||
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
|
||||
} while(0)
|
||||
@@ -504,6 +511,33 @@ void fs__open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_DIRECT) {
|
||||
/*
|
||||
* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive.
|
||||
* Windows returns 87, ERROR_INVALID_PARAMETER if these are combined.
|
||||
*
|
||||
* FILE_APPEND_DATA is included in FILE_GENERIC_WRITE:
|
||||
*
|
||||
* FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
* FILE_WRITE_DATA |
|
||||
* FILE_WRITE_ATTRIBUTES |
|
||||
* FILE_WRITE_EA |
|
||||
* FILE_APPEND_DATA |
|
||||
* SYNCHRONIZE
|
||||
*
|
||||
* Note: Appends are also permitted by FILE_WRITE_DATA.
|
||||
*
|
||||
* In order for direct writes and direct appends to succeed, we therefore
|
||||
* exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise
|
||||
* fail if the user's sole permission is a direct append, since this
|
||||
* particular combination is invalid.
|
||||
*/
|
||||
if (access & FILE_APPEND_DATA) {
|
||||
if (access & FILE_WRITE_DATA) {
|
||||
access &= ~FILE_APPEND_DATA;
|
||||
} else {
|
||||
goto einval;
|
||||
}
|
||||
}
|
||||
attributes |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
|
||||
@@ -785,9 +819,8 @@ void fs__unlink(uv_fs_t* req) {
|
||||
/* Remove read-only attribute */
|
||||
FILE_BASIC_INFORMATION basic = { 0 };
|
||||
|
||||
basic.FileAttributes = info.dwFileAttributes
|
||||
& ~(FILE_ATTRIBUTE_READONLY)
|
||||
| FILE_ATTRIBUTE_ARCHIVE;
|
||||
basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
@@ -1095,6 +1128,137 @@ cleanup:
|
||||
uv__free(dirents);
|
||||
}
|
||||
|
||||
void fs__opendir(uv_fs_t* req) {
|
||||
WCHAR* pathw;
|
||||
size_t len;
|
||||
const WCHAR* fmt;
|
||||
WCHAR* find_path;
|
||||
uv_dir_t* dir;
|
||||
|
||||
pathw = req->file.pathw;
|
||||
dir = NULL;
|
||||
find_path = NULL;
|
||||
|
||||
/* Figure out whether path is a file or a directory. */
|
||||
if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dir = (uv_dir_t*)uv__malloc(sizeof(*dir));
|
||||
if (dir == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
goto error;
|
||||
}
|
||||
|
||||
len = wcslen(pathw);
|
||||
|
||||
if (len == 0)
|
||||
fmt = L"./*";
|
||||
else if (IS_SLASH(pathw[len - 1]))
|
||||
fmt = L"%s*";
|
||||
else
|
||||
fmt = L"%s\\*";
|
||||
|
||||
find_path = (WCHAR*)uv__malloc(sizeof(WCHAR) * (len + 4));
|
||||
if (find_path == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
goto error;
|
||||
}
|
||||
|
||||
_snwprintf(find_path, len + 3, fmt, pathw);
|
||||
dir->dir_handle = FindFirstFileW(find_path, &dir->find_data);
|
||||
uv__free(find_path);
|
||||
find_path = NULL;
|
||||
if (dir->dir_handle == INVALID_HANDLE_VALUE &&
|
||||
GetLastError() != ERROR_FILE_NOT_FOUND) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
goto error;
|
||||
}
|
||||
|
||||
dir->need_find_call = FALSE;
|
||||
req->ptr = dir;
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
|
||||
error:
|
||||
uv__free(dir);
|
||||
uv__free(find_path);
|
||||
req->ptr = NULL;
|
||||
}
|
||||
|
||||
void fs__readdir(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
uv_dirent_t* dirents;
|
||||
uv__dirent_t dent;
|
||||
unsigned int dirent_idx;
|
||||
PWIN32_FIND_DATAW find_data;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
req->flags |= UV_FS_FREE_PTR;
|
||||
dir = (uv_dir_t*)req->ptr;
|
||||
dirents = dir->dirents;
|
||||
memset(dirents, 0, dir->nentries * sizeof(*dir->dirents));
|
||||
find_data = &dir->find_data;
|
||||
dirent_idx = 0;
|
||||
|
||||
while (dirent_idx < dir->nentries) {
|
||||
if (dir->need_find_call && FindNextFileW(dir->dir_handle, find_data) == 0) {
|
||||
if (GetLastError() == ERROR_NO_MORE_FILES)
|
||||
break;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Skip "." and ".." entries. */
|
||||
if (find_data->cFileName[0] == L'.' &&
|
||||
(find_data->cFileName[1] == L'\0' ||
|
||||
(find_data->cFileName[1] == L'.' &&
|
||||
find_data->cFileName[2] == L'\0'))) {
|
||||
dir->need_find_call = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
r = uv__convert_utf16_to_utf8((const WCHAR*) &find_data->cFileName,
|
||||
-1,
|
||||
(char**) &dirents[dirent_idx].name);
|
||||
if (r != 0)
|
||||
goto error;
|
||||
|
||||
/* Copy file type. */
|
||||
if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
dent.d_type = UV__DT_DIR;
|
||||
else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
|
||||
dent.d_type = UV__DT_LINK;
|
||||
else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
|
||||
dent.d_type = UV__DT_CHAR;
|
||||
else
|
||||
dent.d_type = UV__DT_FILE;
|
||||
|
||||
dirents[dirent_idx].type = uv__fs_get_dirent_type(&dent);
|
||||
dir->need_find_call = TRUE;
|
||||
++dirent_idx;
|
||||
}
|
||||
|
||||
SET_REQ_RESULT(req, dirent_idx);
|
||||
return;
|
||||
|
||||
error:
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
for (i = 0; i < dirent_idx; ++i) {
|
||||
uv__free((char*) dirents[i].name);
|
||||
dirents[i].name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void fs__closedir(uv_fs_t* req) {
|
||||
uv_dir_t* dir;
|
||||
|
||||
dir = (uv_dir_t*)req->ptr;
|
||||
FindClose(dir->dir_handle);
|
||||
uv__free(req->ptr);
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
|
||||
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
int do_lstat) {
|
||||
@@ -1198,7 +1362,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
|
||||
/* st_blocks contains the on-disk allocation size in 512-byte units. */
|
||||
statbuf->st_blocks =
|
||||
file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
|
||||
(uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
|
||||
|
||||
statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
|
||||
|
||||
@@ -1248,47 +1412,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1392,6 +1566,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;
|
||||
|
||||
@@ -1402,12 +1578,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1516,10 +1705,10 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
|
||||
|
||||
/* Test if the Archive attribute is cleared */
|
||||
if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
|
||||
/* Set Archive flag, otherwise setting or clearing the read-only
|
||||
/* Set Archive flag, otherwise setting or clearing the read-only
|
||||
flag will not work */
|
||||
file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
nt_status = pNtSetInformationFile(handle,
|
||||
@@ -1889,7 +2078,7 @@ static void fs__readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
int r;
|
||||
DWORD w_realpath_len;
|
||||
WCHAR* w_realpath_ptr = NULL;
|
||||
@@ -2009,6 +2198,9 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(MKDTEMP, mkdtemp)
|
||||
XX(RENAME, rename)
|
||||
XX(SCANDIR, scandir)
|
||||
XX(READDIR, readdir)
|
||||
XX(OPENDIR, opendir)
|
||||
XX(CLOSEDIR, closedir)
|
||||
XX(LINK, link)
|
||||
XX(SYMLINK, symlink)
|
||||
XX(READLINK, readlink)
|
||||
@@ -2050,6 +2242,8 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
if (req->flags & UV_FS_FREE_PTR) {
|
||||
if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
|
||||
uv__fs_scandir_cleanup(req);
|
||||
else if (req->fs_type == UV_FS_READDIR)
|
||||
uv__fs_readdir_cleanup(req);
|
||||
else
|
||||
uv__free(req->ptr);
|
||||
}
|
||||
@@ -2217,6 +2411,45 @@ int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_opendir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_OPENDIR);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_readdir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
INIT(UV_FS_READDIR);
|
||||
|
||||
if (dir == NULL ||
|
||||
dir->dirents == NULL ||
|
||||
dir->dir_handle == INVALID_HANDLE_VALUE) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
req->ptr = dir;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_closedir(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
uv_dir_t* dir,
|
||||
uv_fs_cb cb) {
|
||||
INIT(UV_FS_CLOSEDIR);
|
||||
if (dir == NULL)
|
||||
return UV_EINVAL;
|
||||
req->ptr = dir;
|
||||
POST;
|
||||
}
|
||||
|
||||
int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
|
||||
const char* new_path, uv_fs_cb cb) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
#include "idna.h"
|
||||
|
||||
/* EAI_* constants. */
|
||||
#include <winsock2.h>
|
||||
@@ -259,11 +260,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* node,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
int nodesize = 0;
|
||||
int servicesize = 0;
|
||||
int hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
int err;
|
||||
long rc;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
return UV_EINVAL;
|
||||
@@ -277,12 +280,19 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
|
||||
/* calculate required memory size for all input values */
|
||||
if (node != NULL) {
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
|
||||
sizeof(WCHAR));
|
||||
rc = uv__idna_toascii(node,
|
||||
node + strlen(node),
|
||||
hostname_ascii,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
|
||||
-1, NULL, 0) * sizeof(WCHAR));
|
||||
if (nodesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
node = hostname_ascii;
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
@@ -368,6 +378,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
if (getaddrinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
uv_getnameinfo_t* req;
|
||||
WCHAR host[NI_MAXHOST];
|
||||
WCHAR service[NI_MAXSERV];
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
if (GetNameInfoW((struct sockaddr*)&req->storage,
|
||||
@@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
ARRAY_SIZE(service),
|
||||
req->flags)) {
|
||||
ret = WSAGetLastError();
|
||||
req->retcode = uv__getaddrinfo_translate_error(ret);
|
||||
return;
|
||||
}
|
||||
req->retcode = uv__getaddrinfo_translate_error(ret);
|
||||
|
||||
/* convert results to UTF-8 */
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
host,
|
||||
-1,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
NULL,
|
||||
NULL);
|
||||
ret = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
host,
|
||||
-1,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
NULL,
|
||||
NULL);
|
||||
if (ret == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
NULL,
|
||||
NULL);
|
||||
ret = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
NULL,
|
||||
NULL);
|
||||
if (ret == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +145,7 @@ int uv_getnameinfo(uv_loop_t* loop,
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define DECREASE_ACTIVE_COUNT(loop, handle) \
|
||||
do { \
|
||||
if (--(handle)->activecnt == 0 && \
|
||||
!((handle)->flags & UV__HANDLE_CLOSING)) { \
|
||||
!((handle)->flags & UV_HANDLE_CLOSING)) { \
|
||||
uv__handle_stop((handle)); \
|
||||
} \
|
||||
assert((handle)->activecnt >= 0); \
|
||||
@@ -53,7 +53,7 @@
|
||||
assert(handle->reqs_pending > 0); \
|
||||
handle->reqs_pending--; \
|
||||
\
|
||||
if (handle->flags & UV__HANDLE_CLOSING && \
|
||||
if (handle->flags & UV_HANDLE_CLOSING && \
|
||||
handle->reqs_pending == 0) { \
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle); \
|
||||
} \
|
||||
@@ -62,14 +62,14 @@
|
||||
|
||||
#define uv__handle_closing(handle) \
|
||||
do { \
|
||||
assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
|
||||
assert(!((handle)->flags & UV_HANDLE_CLOSING)); \
|
||||
\
|
||||
if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
|
||||
((handle)->flags & UV__HANDLE_REF))) \
|
||||
if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \
|
||||
((handle)->flags & UV_HANDLE_REF))) \
|
||||
uv__active_handle_add((uv_handle_t*) (handle)); \
|
||||
\
|
||||
(handle)->flags |= UV__HANDLE_CLOSING; \
|
||||
(handle)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
(handle)->flags |= UV_HANDLE_CLOSING; \
|
||||
(handle)->flags &= ~UV_HANDLE_ACTIVE; \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
break;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_endgame(loop, (uv_timer_t*) handle);
|
||||
uv__timer_close((uv_timer_t*) handle);
|
||||
uv__handle_close(handle);
|
||||
break;
|
||||
|
||||
case UV_PREPARE:
|
||||
|
||||
@@ -59,15 +59,15 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
|
||||
|
||||
int uv_is_active(const uv_handle_t* handle) {
|
||||
return (handle->flags & UV__HANDLE_ACTIVE) &&
|
||||
!(handle->flags & UV__HANDLE_CLOSING);
|
||||
return (handle->flags & UV_HANDLE_ACTIVE) &&
|
||||
!(handle->flags & UV_HANDLE_CLOSING);
|
||||
}
|
||||
|
||||
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
@@ -139,7 +139,6 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
case UV_FS_POLL:
|
||||
uv__fs_poll_close((uv_fs_poll_t*) handle);
|
||||
uv__handle_closing(handle);
|
||||
uv_want_endgame(loop, handle);
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -150,10 +149,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
|
||||
|
||||
int uv_is_closing(const uv_handle_t* handle) {
|
||||
return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
|
||||
return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
|
||||
}
|
||||
|
||||
|
||||
uv_os_fd_t uv_get_osfhandle(int fd) {
|
||||
return uv__get_osfhandle(fd);
|
||||
}
|
||||
|
||||
int uv_open_osfhandle(uv_os_fd_t os_fd) {
|
||||
return _open_osfhandle((intptr_t) os_fd, 0);
|
||||
}
|
||||
|
||||
@@ -57,77 +57,19 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
|
||||
#define UV_END_DISABLE_CRT_ASSERT()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handles
|
||||
* (also see handle-inl.h)
|
||||
*/
|
||||
|
||||
/* Used by all handles. */
|
||||
#define UV_HANDLE_CLOSED 0x00000002
|
||||
#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
|
||||
|
||||
/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
|
||||
/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
|
||||
/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
|
||||
/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
|
||||
|
||||
/* Used by streams and UDP handles. */
|
||||
#define UV_HANDLE_READING 0x00000100
|
||||
#define UV_HANDLE_BOUND 0x00000200
|
||||
#define UV_HANDLE_LISTENING 0x00000800
|
||||
#define UV_HANDLE_CONNECTION 0x00001000
|
||||
#define UV_HANDLE_READABLE 0x00008000
|
||||
#define UV_HANDLE_WRITABLE 0x00010000
|
||||
#define UV_HANDLE_READ_PENDING 0x00020000
|
||||
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
|
||||
#define UV_HANDLE_ZERO_READ 0x00080000
|
||||
#define UV_HANDLE_EMULATE_IOCP 0x00100000
|
||||
#define UV_HANDLE_BLOCKING_WRITES 0x00200000
|
||||
#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
#define UV_HANDLE_IPV6 0x01000000
|
||||
|
||||
/* Only used by uv_tcp_t handles. */
|
||||
#define UV_HANDLE_TCP_NODELAY 0x02000000
|
||||
#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
|
||||
#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
|
||||
#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
|
||||
#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
|
||||
#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
|
||||
|
||||
/* Only used by uv_pipe_t handles. */
|
||||
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
|
||||
#define UV_HANDLE_PIPESERVER 0x02000000
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
#define UV_HANDLE_TTY_READABLE 0x01000000
|
||||
#define UV_HANDLE_TTY_RAW 0x02000000
|
||||
#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
|
||||
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
#define UV_HANDLE_POLL_SLOW 0x02000000
|
||||
|
||||
|
||||
/*
|
||||
* Requests: see req-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Streams: see stream-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TCP
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
UV__IPC_SOCKET_XFER_NONE = 0,
|
||||
UV__IPC_SOCKET_XFER_TCP_CONNECTION,
|
||||
UV__IPC_SOCKET_XFER_TCP_SERVER
|
||||
} uv__ipc_socket_xfer_type_t;
|
||||
|
||||
typedef struct {
|
||||
WSAPROTOCOL_INFOW socket_info;
|
||||
uint32_t delayed_error;
|
||||
uint32_t flags; /* Either zero or UV_HANDLE_CONNECTION. */
|
||||
} uv__ipc_socket_xfer_info_t;
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
|
||||
@@ -152,8 +94,11 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
|
||||
|
||||
int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
int pid,
|
||||
uv__ipc_socket_xfer_type_t* xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
|
||||
|
||||
/*
|
||||
@@ -246,15 +191,6 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*/
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
|
||||
|
||||
DWORD uv__next_timeout(const uv_loop_t* loop);
|
||||
void uv_process_timers(uv_loop_t* loop);
|
||||
|
||||
|
||||
/*
|
||||
* Loop watchers
|
||||
*/
|
||||
@@ -336,6 +272,14 @@ int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
|
||||
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
|
||||
|
||||
typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*);
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen,
|
||||
int delayed_error);
|
||||
|
||||
|
||||
/*
|
||||
* Process stdio handles.
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_close(handle);
|
||||
|
||||
@@ -23,16 +23,16 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <io.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "stream-inl.h"
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
#include "stream-inl.h"
|
||||
#include "uv-common.h"
|
||||
#include "uv.h"
|
||||
|
||||
#include <aclapi.h>
|
||||
#include <accctrl.h>
|
||||
@@ -55,19 +55,36 @@ static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
|
||||
|
||||
/* IPC incoming xfer queue item. */
|
||||
typedef struct {
|
||||
uv__ipc_socket_xfer_type_t xfer_type;
|
||||
uv__ipc_socket_xfer_info_t xfer_info;
|
||||
QUEUE member;
|
||||
} uv__ipc_xfer_queue_item_t;
|
||||
|
||||
/* IPC frame types. */
|
||||
enum { UV__IPC_DATA_FRAME = 0, UV__IPC_XFER_FRAME = 1 };
|
||||
/* IPC frame header flags. */
|
||||
/* clang-format off */
|
||||
enum {
|
||||
UV__IPC_FRAME_HAS_DATA = 0x01,
|
||||
UV__IPC_FRAME_HAS_SOCKET_XFER = 0x02,
|
||||
UV__IPC_FRAME_XFER_IS_TCP_CONNECTION = 0x04,
|
||||
/* These are combinations of the flags above. */
|
||||
UV__IPC_FRAME_XFER_FLAGS = 0x06,
|
||||
UV__IPC_FRAME_VALID_FLAGS = 0x07
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
/* IPC frame header. */
|
||||
typedef struct {
|
||||
uint32_t type;
|
||||
uint32_t payload_length;
|
||||
uint32_t flags;
|
||||
uint32_t reserved1; /* Ignored. */
|
||||
uint32_t data_length; /* Must be zero if there is no data. */
|
||||
uint32_t reserved2; /* Must be zero. */
|
||||
} uv__ipc_frame_header_t;
|
||||
|
||||
/* To implement the IPC protocol correctly, these structures must have exactly
|
||||
* the right size. */
|
||||
STATIC_ASSERT(sizeof(uv__ipc_frame_header_t) == 16);
|
||||
STATIC_ASSERT(sizeof(uv__ipc_socket_xfer_info_t) == 632);
|
||||
|
||||
/* Coalesced write request. */
|
||||
typedef struct {
|
||||
uv_write_t req; /* Internal heap-allocated write request. */
|
||||
@@ -349,7 +366,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
/* Clear the shutdown_req field so we don't go here again. */
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
/* Already closing. Cancel the shutdown. */
|
||||
@@ -410,7 +427,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
}
|
||||
}
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
@@ -881,7 +898,8 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
server->pipe.conn.ipc_xfer_queue_length--;
|
||||
item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
|
||||
|
||||
err = uv__tcp_xfer_import((uv_tcp_t*) client, &item->xfer_info);
|
||||
err = uv__tcp_xfer_import(
|
||||
(uv_tcp_t*) client, item->xfer_type, &item->xfer_info);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
@@ -909,7 +927,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (!(server->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, server, req, FALSE);
|
||||
}
|
||||
}
|
||||
@@ -1294,9 +1312,8 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
size_t nbufs,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb,
|
||||
bool copy_always) {
|
||||
int copy_always) {
|
||||
int err;
|
||||
int result;
|
||||
uv_buf_t write_buf;
|
||||
@@ -1305,7 +1322,7 @@ static int uv__pipe_write_data(uv_loop_t* loop,
|
||||
|
||||
UV_REQ_INIT(req, UV_WRITE);
|
||||
req->handle = (uv_stream_t*) handle;
|
||||
req->send_handle = send_handle;
|
||||
req->send_handle = NULL;
|
||||
req->cb = cb;
|
||||
/* Private fields. */
|
||||
req->coalesced = 0;
|
||||
@@ -1461,10 +1478,10 @@ int uv__pipe_write_ipc(uv_loop_t* loop,
|
||||
uv_buf_t stack_bufs[6];
|
||||
uv_buf_t* bufs;
|
||||
size_t buf_count, buf_index;
|
||||
uv__ipc_frame_header_t xfer_frame_header;
|
||||
uv__ipc_frame_header_t frame_header;
|
||||
uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE;
|
||||
uv__ipc_socket_xfer_info_t xfer_info;
|
||||
uv__ipc_frame_header_t data_frame_header;
|
||||
size_t data_length;
|
||||
uint64_t data_length;
|
||||
size_t i;
|
||||
int err;
|
||||
|
||||
@@ -1475,8 +1492,8 @@ int uv__pipe_write_ipc(uv_loop_t* loop,
|
||||
if (data_length > UINT32_MAX)
|
||||
return WSAENOBUFS; /* Maps to UV_ENOBUFS. */
|
||||
|
||||
/* Prepare xfer frame payload. */
|
||||
if (send_handle) {
|
||||
/* Prepare the frame's socket xfer payload. */
|
||||
if (send_handle != NULL) {
|
||||
uv_tcp_t* send_tcp_handle = (uv_tcp_t*) send_handle;
|
||||
|
||||
/* Verify that `send_handle` it is indeed a tcp handle. */
|
||||
@@ -1484,20 +1501,18 @@ int uv__pipe_write_ipc(uv_loop_t* loop,
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
|
||||
/* Export the tcp handle. */
|
||||
err = uv__tcp_xfer_export(
|
||||
send_tcp_handle, uv__pipe_get_ipc_remote_pid(handle), &xfer_info);
|
||||
err = uv__tcp_xfer_export(send_tcp_handle,
|
||||
uv__pipe_get_ipc_remote_pid(handle),
|
||||
&xfer_type,
|
||||
&xfer_info);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Compute the number of uv_buf_t's required. */
|
||||
buf_count = 0;
|
||||
if (send_handle != NULL) {
|
||||
buf_count += 2; /* One for the frame header, one for the payload. */
|
||||
}
|
||||
if (data_buf_count > 0) {
|
||||
buf_count += 1 + data_buf_count; /* One extra for the frame header. */
|
||||
}
|
||||
buf_count = 1 + data_buf_count; /* Frame header and data buffers. */
|
||||
if (send_handle != NULL)
|
||||
buf_count += 1; /* One extra for the socket xfer information. */
|
||||
|
||||
/* Use the on-stack buffer array if it is big enough; otherwise allocate
|
||||
* space for it on the heap. */
|
||||
@@ -1512,33 +1527,39 @@ int uv__pipe_write_ipc(uv_loop_t* loop,
|
||||
}
|
||||
buf_index = 0;
|
||||
|
||||
if (send_handle != NULL) {
|
||||
/* Add xfer frame header. */
|
||||
xfer_frame_header.type = UV__IPC_XFER_FRAME;
|
||||
xfer_frame_header.payload_length = sizeof xfer_info;
|
||||
bufs[buf_index++] =
|
||||
uv_buf_init((char*) &xfer_frame_header, sizeof xfer_frame_header);
|
||||
/* Initialize frame header and add it to the buffers list. */
|
||||
memset(&frame_header, 0, sizeof frame_header);
|
||||
bufs[buf_index++] = uv_buf_init((char*) &frame_header, sizeof frame_header);
|
||||
|
||||
/* Add xfer frame payload. */
|
||||
if (send_handle != NULL) {
|
||||
/* Add frame header flags. */
|
||||
switch (xfer_type) {
|
||||
case UV__IPC_SOCKET_XFER_TCP_CONNECTION:
|
||||
frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER |
|
||||
UV__IPC_FRAME_XFER_IS_TCP_CONNECTION;
|
||||
break;
|
||||
case UV__IPC_SOCKET_XFER_TCP_SERVER:
|
||||
frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER;
|
||||
break;
|
||||
default:
|
||||
assert(0); /* Unreachable. */
|
||||
}
|
||||
/* Add xfer info buffer. */
|
||||
bufs[buf_index++] = uv_buf_init((char*) &xfer_info, sizeof xfer_info);
|
||||
}
|
||||
|
||||
if (data_length > 0) {
|
||||
/* Add data frame header. */
|
||||
data_frame_header.type = UV__IPC_DATA_FRAME;
|
||||
data_frame_header.payload_length = (uint32_t) data_length;
|
||||
bufs[buf_index++] =
|
||||
uv_buf_init((char*) &data_frame_header, sizeof data_frame_header);
|
||||
|
||||
/* Add data buffers. */
|
||||
/* Update frame header. */
|
||||
frame_header.flags |= UV__IPC_FRAME_HAS_DATA;
|
||||
frame_header.data_length = (uint32_t) data_length;
|
||||
/* Add data buffers to buffers list. */
|
||||
for (i = 0; i < data_buf_count; i++)
|
||||
bufs[buf_index++] = data_bufs[i];
|
||||
}
|
||||
|
||||
/* Write buffers. We set the `always_copy` flag, so it is not a problem that
|
||||
* some of the written data lives on the stack. */
|
||||
err = uv__pipe_write_data(
|
||||
loop, req, handle, bufs, buf_count, send_handle, cb, true);
|
||||
err = uv__pipe_write_data(loop, req, handle, bufs, buf_count, cb, 1);
|
||||
|
||||
/* If we had to heap-allocate the bufs array, free it now. */
|
||||
if (bufs != stack_bufs) {
|
||||
@@ -1562,8 +1583,7 @@ int uv__pipe_write(uv_loop_t* loop,
|
||||
} else {
|
||||
/* Non-IPC pipe write: put data on the wire directly. */
|
||||
assert(send_handle == NULL);
|
||||
return uv__pipe_write_data(
|
||||
loop, req, handle, bufs, nbufs, NULL, cb, false);
|
||||
return uv__pipe_write_data(loop, req, handle, bufs, nbufs, cb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1604,14 +1624,18 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
|
||||
|
||||
static void uv__pipe_queue_ipc_xfer_info(
|
||||
uv_pipe_t* handle, uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
uv_pipe_t* handle,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
uv__ipc_xfer_queue_item_t* item;
|
||||
|
||||
item = (uv__ipc_xfer_queue_item_t*) uv__malloc(sizeof(*item));
|
||||
if (item == NULL)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
|
||||
memcpy(&item->xfer_info, xfer_info, sizeof(item->xfer_info));
|
||||
item->xfer_type = xfer_type;
|
||||
item->xfer_info = *xfer_info;
|
||||
|
||||
QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member);
|
||||
handle->pipe.conn.ipc_xfer_queue_length++;
|
||||
}
|
||||
@@ -1677,12 +1701,11 @@ static DWORD uv__pipe_read_data(uv_loop_t* loop,
|
||||
|
||||
|
||||
static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
DWORD* data_remaining =
|
||||
(DWORD*)&handle->pipe.conn.ipc_data_frame.payload_remaining;
|
||||
uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining;
|
||||
int err;
|
||||
|
||||
if (*data_remaining > 0) {
|
||||
/* Read data frame payload. */
|
||||
/* Read frame data payload. */
|
||||
DWORD bytes_read =
|
||||
uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining);
|
||||
*data_remaining -= bytes_read;
|
||||
@@ -1691,6 +1714,8 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
} else {
|
||||
/* Start of a new IPC frame. */
|
||||
uv__ipc_frame_header_t frame_header;
|
||||
uint32_t xfer_flags;
|
||||
uv__ipc_socket_xfer_type_t xfer_type;
|
||||
uv__ipc_socket_xfer_info_t xfer_info;
|
||||
|
||||
/* Read the IPC frame header. */
|
||||
@@ -1699,33 +1724,57 @@ static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
if (frame_header.type == UV__IPC_DATA_FRAME) {
|
||||
/* Data frame: capture payload length. Actual data will be read in
|
||||
* subsequent call to uv__pipe_read_ipc(). */
|
||||
*data_remaining = frame_header.payload_length;
|
||||
/* Validate that flags are valid. */
|
||||
if ((frame_header.flags & ~UV__IPC_FRAME_VALID_FLAGS) != 0)
|
||||
goto invalid;
|
||||
/* Validate that reserved2 is zero. */
|
||||
if (frame_header.reserved2 != 0)
|
||||
goto invalid;
|
||||
|
||||
/* Return number of bytes read. */
|
||||
return sizeof frame_header;
|
||||
|
||||
} else if (frame_header.type == UV__IPC_XFER_FRAME) {
|
||||
/* Xfer frame: read the payload. */
|
||||
assert(frame_header.payload_length == sizeof xfer_info);
|
||||
err =
|
||||
uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Store the pending socket info. */
|
||||
uv__pipe_queue_ipc_xfer_info(handle, &xfer_info);
|
||||
|
||||
/* Return number of bytes read. */
|
||||
return sizeof frame_header + sizeof xfer_info;
|
||||
/* Parse xfer flags. */
|
||||
xfer_flags = frame_header.flags & UV__IPC_FRAME_XFER_FLAGS;
|
||||
if (xfer_flags & UV__IPC_FRAME_HAS_SOCKET_XFER) {
|
||||
/* Socket coming -- determine the type. */
|
||||
xfer_type = xfer_flags & UV__IPC_FRAME_XFER_IS_TCP_CONNECTION
|
||||
? UV__IPC_SOCKET_XFER_TCP_CONNECTION
|
||||
: UV__IPC_SOCKET_XFER_TCP_SERVER;
|
||||
} else if (xfer_flags == 0) {
|
||||
/* No socket. */
|
||||
xfer_type = UV__IPC_SOCKET_XFER_NONE;
|
||||
} else {
|
||||
/* Invalid flags. */
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* Invalid frame. */
|
||||
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
|
||||
/* Parse data frame information. */
|
||||
if (frame_header.flags & UV__IPC_FRAME_HAS_DATA) {
|
||||
*data_remaining = frame_header.data_length;
|
||||
} else if (frame_header.data_length != 0) {
|
||||
/* Data length greater than zero but data flag not set -- invalid. */
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* If no socket xfer info follows, return here. Data will be read in a
|
||||
* subsequent invocation of uv__pipe_read_ipc(). */
|
||||
if (xfer_type == UV__IPC_SOCKET_XFER_NONE)
|
||||
return sizeof frame_header; /* Number of bytes read. */
|
||||
|
||||
/* Read transferred socket information. */
|
||||
err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
/* Store the pending socket info. */
|
||||
uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info);
|
||||
|
||||
/* Return number of bytes read. */
|
||||
return sizeof frame_header + sizeof xfer_info;
|
||||
}
|
||||
|
||||
invalid:
|
||||
/* Invalid frame. */
|
||||
err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
|
||||
|
||||
error:
|
||||
uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
|
||||
return 0; /* Break out of read loop. */
|
||||
@@ -1859,7 +1908,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
|
||||
assert(handle->type == UV_NAMED_PIPE);
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
|
||||
assert(req->pipeHandle == INVALID_HANDLE_VALUE);
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
@@ -1879,7 +1928,7 @@ void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
CloseHandle(req->pipeHandle);
|
||||
req->pipeHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
if (!(handle->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_pipe_queue_accept(loop, handle, req, FALSE);
|
||||
}
|
||||
}
|
||||
@@ -2091,7 +2140,7 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
||||
if (pipe->ipc) {
|
||||
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
|
||||
assert(pipe->pipe.conn.ipc_remote_pid != -1);
|
||||
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2262,7 +2311,7 @@ uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
|
||||
}
|
||||
|
||||
int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
SID_IDENTIFIER_AUTHORITY sid_world = SECURITY_WORLD_SID_AUTHORITY;
|
||||
SID_IDENTIFIER_AUTHORITY sid_world = { SECURITY_WORLD_SID_AUTHORITY };
|
||||
PACL old_dacl, new_dacl;
|
||||
PSECURITY_DESCRIPTOR sd;
|
||||
EXPLICIT_ACCESS ea;
|
||||
@@ -2297,7 +2346,7 @@ int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
|
||||
error = GetLastError();
|
||||
goto clean_sid;
|
||||
}
|
||||
|
||||
|
||||
memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
|
||||
if (mode & UV_READABLE)
|
||||
ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
||||
|
||||
@@ -75,7 +75,7 @@ static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
|
||||
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
uv_req_t* req;
|
||||
AFD_POLL_INFO* afd_poll_info;
|
||||
DWORD result;
|
||||
int result;
|
||||
|
||||
/* Find a yet unsubmitted req to submit. */
|
||||
if (handle->submitted_events_1 == 0) {
|
||||
@@ -136,7 +136,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
|
||||
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
DWORD result;
|
||||
int result;
|
||||
|
||||
afd_poll_info.Exclusive = TRUE;
|
||||
afd_poll_info.NumberOfHandles = 1;
|
||||
@@ -218,7 +218,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -228,7 +228,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
|
||||
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
@@ -461,7 +461,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -471,7 +471,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
|
||||
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
@@ -633,7 +633,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
|
||||
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->submitted_events_1 == 0);
|
||||
|
||||
@@ -103,6 +103,7 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
DWORD client_access = 0;
|
||||
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
||||
int err;
|
||||
BOOL overlap;
|
||||
|
||||
if (flags & UV_READABLE_PIPE) {
|
||||
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
|
||||
@@ -116,8 +117,6 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
}
|
||||
|
||||
BOOL overlap;
|
||||
|
||||
/* Create server pipe handle. */
|
||||
err = uv_stdio_pipe_server(loop,
|
||||
server_pipe,
|
||||
|
||||
@@ -741,7 +741,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
}
|
||||
*ptr_copy = NULL;
|
||||
assert(env_len == ptr - dst_copy);
|
||||
assert(env_len == (size_t) (ptr - dst_copy));
|
||||
|
||||
/* sort our (UTF-16) copy */
|
||||
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
|
||||
@@ -801,7 +801,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
var_size = GetEnvironmentVariableW(required_vars[i].wide,
|
||||
ptr,
|
||||
(int) (env_len - (ptr - dst)));
|
||||
if (var_size != len-1) { /* race condition? */
|
||||
if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
|
||||
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
|
||||
}
|
||||
}
|
||||
@@ -817,7 +817,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
|
||||
/* Terminate with an extra NULL. */
|
||||
assert(env_len == (ptr - dst));
|
||||
assert(env_len == (size_t) (ptr - dst));
|
||||
*ptr = L'\0';
|
||||
|
||||
uv__free(dst_copy);
|
||||
@@ -874,7 +874,7 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
|
||||
/* If we're closing, don't call the exit callback. Just schedule a close
|
||||
* callback now. */
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return;
|
||||
}
|
||||
@@ -926,7 +926,7 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
|
||||
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
assert(!handle->exit_cb_pending);
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
/* Clean-up the process handle. */
|
||||
@@ -966,6 +966,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
err = uv_utf8_to_utf16_alloc(options->file, &application);
|
||||
@@ -1067,7 +1069,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
process_flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
|
||||
if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
|
||||
if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
|
||||
(options->flags & UV_PROCESS_WINDOWS_HIDE)) {
|
||||
/* Avoid creating console window if stdio is not inherited. */
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
if (options->stdio[i].flags & UV_INHERIT_FD)
|
||||
@@ -1075,7 +1078,9 @@ int uv_spawn(uv_loop_t* loop,
|
||||
if (i == options->stdio_count - 1)
|
||||
process_flags |= CREATE_NO_WINDOW;
|
||||
}
|
||||
|
||||
}
|
||||
if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
|
||||
(options->flags & UV_PROCESS_WINDOWS_HIDE)) {
|
||||
/* Use SW_HIDE to avoid any potential process window. */
|
||||
startup.wShowWindow = SW_HIDE;
|
||||
} else {
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
@@ -90,7 +90,7 @@ int uv__signal_dispatch(int signum) {
|
||||
unsigned long previous = InterlockedExchange(
|
||||
(volatile LONG*) &handle->pending_signum, signum);
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
|
||||
continue;
|
||||
|
||||
if (!previous) {
|
||||
@@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) {
|
||||
}
|
||||
|
||||
dispatched = 1;
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED;
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
@@ -190,7 +190,7 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
int signum,
|
||||
int oneshot) {
|
||||
/* Test for invalid signal values. */
|
||||
if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
|
||||
if (signum <= 0 || signum >= NSIG)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Short circuit: if the signal watcher is already watching {signum} don't go
|
||||
@@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
|
||||
handle->signum = signum;
|
||||
if (oneshot)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT;
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT;
|
||||
|
||||
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
@@ -243,10 +243,10 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
|
||||
if (dispatched_signum == handle->signum)
|
||||
handle->signal_cb(handle, dispatched_signum);
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv_signal_stop(handle);
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* When it is closing, it must be stopped at this point. */
|
||||
assert(handle->signum == 0);
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -265,7 +265,7 @@ void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
|
||||
|
||||
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->signum == 0);
|
||||
|
||||
@@ -176,7 +176,7 @@ int uv_write2(uv_write_t* req,
|
||||
int uv_try_write(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs) {
|
||||
if (stream->flags & UV__HANDLE_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EBADF;
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return UV_EPIPE;
|
||||
|
||||
@@ -217,7 +217,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
|
||||
|
||||
err = 0;
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
} else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
|
||||
err = WSAGetLastError();
|
||||
@@ -233,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
@@ -680,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->accept_socket = INVALID_SOCKET;
|
||||
|
||||
if (!(server->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
/* Check if we're in a middle of changing the number of pending accepts. */
|
||||
if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
|
||||
uv_tcp_queue_accept(server, req);
|
||||
@@ -809,44 +809,24 @@ static int uv_tcp_try_connect(uv_connect_t* req,
|
||||
int uv_tcp_getsockname(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
int result;
|
||||
|
||||
if (handle->socket == INVALID_SOCKET) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (handle->delayed_error) {
|
||||
return uv_translate_sys_error(handle->delayed_error);
|
||||
}
|
||||
|
||||
result = getsockname(handle->socket, name, namelen);
|
||||
if (result != 0) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen,
|
||||
handle->delayed_error);
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_getpeername(const uv_tcp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
int result;
|
||||
|
||||
if (handle->socket == INVALID_SOCKET) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (handle->delayed_error) {
|
||||
return uv_translate_sys_error(handle->delayed_error);
|
||||
}
|
||||
|
||||
result = getpeername(handle->socket, name, namelen);
|
||||
if (result != 0) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen,
|
||||
handle->delayed_error);
|
||||
}
|
||||
|
||||
|
||||
@@ -945,6 +925,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* req) {
|
||||
DWORD bytes, flags, err;
|
||||
uv_buf_t buf;
|
||||
int count;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
@@ -999,7 +980,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
count = 32;
|
||||
while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
@@ -1166,7 +1148,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* use UV_ECANCELED for consistency with Unix */
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
} else if (setsockopt(handle->socket,
|
||||
@@ -1191,8 +1173,12 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
int target_pid,
|
||||
uv__ipc_socket_xfer_type_t* xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
*xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION;
|
||||
} else {
|
||||
*xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER;
|
||||
/* We're about to share the socket with another process. Because this is a
|
||||
* listening socket, we assume that the other process will be accepting
|
||||
* connections on it. Thus, before sharing the socket with another process,
|
||||
@@ -1208,12 +1194,9 @@ int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
if (WSADuplicateSocketW(
|
||||
handle->socket, target_pid, &xfer_info->socket_info)) {
|
||||
if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info))
|
||||
return WSAGetLastError();
|
||||
}
|
||||
xfer_info->delayed_error = handle->delayed_error;
|
||||
xfer_info->flags = handle->flags & UV_HANDLE_CONNECTION;
|
||||
|
||||
/* Mark the local copy of the handle as 'shared' so we behave in a way that's
|
||||
* friendly to the process(es) that we share the socket with. */
|
||||
@@ -1223,14 +1206,21 @@ int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
int err;
|
||||
SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&xfer_info->socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
SOCKET socket;
|
||||
|
||||
assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER ||
|
||||
xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION);
|
||||
|
||||
socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&xfer_info->socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
|
||||
if (socket == INVALID_SOCKET) {
|
||||
return WSAGetLastError();
|
||||
@@ -1246,7 +1236,7 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp, uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
tcp->delayed_error = xfer_info->delayed_error;
|
||||
tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
if (xfer_info->flags & UV_HANDLE_CONNECTION) {
|
||||
if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
|
||||
uv_connection_init((uv_stream_t*)tcp);
|
||||
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
|
||||
@@ -23,18 +23,15 @@
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__MINGW64_VERSION_MAJOR)
|
||||
/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
|
||||
* require this header in some versions of mingw64. */
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
static int uv_cond_condvar_init(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_destroy(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_signal(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_broadcast(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
|
||||
static int uv_cond_condvar_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex, uint64_t timeout);
|
||||
|
||||
|
||||
static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
|
||||
DWORD result;
|
||||
HANDLE existing_event, created_event;
|
||||
@@ -115,9 +112,34 @@ static UINT __stdcall uv__thread_start(void* arg) {
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
uv_thread_options_t params;
|
||||
params.flags = UV_THREAD_NO_FLAGS;
|
||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||
}
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
void *arg) {
|
||||
struct thread_ctx* ctx;
|
||||
int err;
|
||||
HANDLE thread;
|
||||
SYSTEM_INFO sysinfo;
|
||||
size_t stack_size;
|
||||
size_t pagesize;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
if (stack_size != 0) {
|
||||
GetNativeSystemInfo(&sysinfo);
|
||||
pagesize = (size_t)sysinfo.dwPageSize;
|
||||
/* Round up to the nearest page boundary. */
|
||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||
|
||||
if ((unsigned)stack_size != stack_size)
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
ctx = (struct thread_ctx*)uv__malloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
@@ -127,9 +149,9 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
ctx->arg = arg;
|
||||
|
||||
/* Create the thread in suspended state so we have a chance to pass
|
||||
* its own creation handle to it */
|
||||
* its own creation handle to it */
|
||||
thread = (HANDLE) _beginthreadex(NULL,
|
||||
0,
|
||||
(unsigned)stack_size,
|
||||
uv__thread_start,
|
||||
ctx,
|
||||
CREATE_SUSPENDED,
|
||||
@@ -374,7 +396,7 @@ int uv_cond_init(uv_cond_t* cond) {
|
||||
|
||||
void uv_cond_destroy(uv_cond_t* cond) {
|
||||
/* nothing to do */
|
||||
UV__UNUSED(cond);
|
||||
(void) &cond;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "uv/tree.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
/* The number of milliseconds in one second. */
|
||||
#define UV__MILLISEC 1000
|
||||
|
||||
|
||||
void uv_update_time(uv_loop_t* loop) {
|
||||
uint64_t new_time = uv__hrtime(UV__MILLISEC);
|
||||
assert(new_time >= loop->time);
|
||||
loop->time = new_time;
|
||||
}
|
||||
|
||||
|
||||
static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
|
||||
if (a->due < b->due)
|
||||
return -1;
|
||||
if (a->due > b->due)
|
||||
return 1;
|
||||
/*
|
||||
* compare start_id when both has the same due. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return -1;
|
||||
if (a->start_id > b->start_id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare)
|
||||
|
||||
|
||||
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
|
||||
handle->timer_cb = NULL;
|
||||
handle->repeat = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
|
||||
uint64_t clamped_timeout;
|
||||
|
||||
clamped_timeout = loop_time + timeout;
|
||||
if (clamped_timeout < timeout)
|
||||
clamped_timeout = (uint64_t) -1;
|
||||
|
||||
return clamped_timeout;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
|
||||
uint64_t repeat) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
uv_timer_t* old;
|
||||
|
||||
if (timer_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
uv_timer_stop(handle);
|
||||
|
||||
handle->timer_cb = timer_cb;
|
||||
handle->due = get_clamped_due_time(loop->time, timeout);
|
||||
handle->repeat = repeat;
|
||||
uv__handle_start(handle);
|
||||
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
|
||||
assert(old == NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_stop(uv_timer_t* handle) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_again(uv_timer_t* handle) {
|
||||
/* If timer_cb is NULL that means that the timer was never started. */
|
||||
if (!handle->timer_cb) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (handle->repeat) {
|
||||
uv_timer_stop(handle);
|
||||
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
handle->repeat = repeat;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
|
||||
DWORD uv__next_timeout(const uv_loop_t* loop) {
|
||||
uv_timer_t* timer;
|
||||
int64_t delta;
|
||||
|
||||
/* Check if there are any running timers
|
||||
* Need to cast away const first, since RB_MIN doesn't know what we are
|
||||
* going to do with this return value, it can't be marked const
|
||||
*/
|
||||
timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
|
||||
if (timer) {
|
||||
delta = timer->due - loop->time;
|
||||
if (delta >= UINT_MAX - 1) {
|
||||
/* A timeout value of UINT_MAX means infinite, so that's no good. */
|
||||
return UINT_MAX - 1;
|
||||
} else if (delta < 0) {
|
||||
/* Negative timeout values are not allowed */
|
||||
return 0;
|
||||
} else {
|
||||
return (DWORD)delta;
|
||||
}
|
||||
} else {
|
||||
/* No timers */
|
||||
return INFINITE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_timers(uv_loop_t* loop) {
|
||||
uv_timer_t* timer;
|
||||
|
||||
/* Call timer callbacks */
|
||||
for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
|
||||
timer != NULL && timer->due <= loop->time;
|
||||
timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
|
||||
|
||||
uv_timer_stop(timer);
|
||||
uv_timer_again(timer);
|
||||
timer->timer_cb((uv_timer_t*) timer);
|
||||
}
|
||||
}
|
||||
@@ -168,7 +168,7 @@ void uv_console_init(void) {
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
0);
|
||||
if (uv__tty_console_handle != NULL) {
|
||||
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
||||
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
@@ -176,9 +176,12 @@ void uv_console_init(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
BOOL readable;
|
||||
DWORD NumberOfEvents;
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
(void)unused;
|
||||
|
||||
uv__once_init();
|
||||
handle = (HANDLE) uv__get_osfhandle(fd);
|
||||
@@ -203,6 +206,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
|
||||
if (!readable) {
|
||||
/* Obtain the screen buffer info with the output handle. */
|
||||
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
|
||||
@@ -360,6 +364,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
} else {
|
||||
was_reading = 0;
|
||||
alloc_cb = NULL;
|
||||
read_cb = NULL;
|
||||
}
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
@@ -386,12 +392,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
|
||||
|
||||
int uv_is_tty(uv_file file) {
|
||||
DWORD result;
|
||||
return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
|
||||
@@ -739,8 +739,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
/* Ignore keyup events, unless the left alt key was held and a valid
|
||||
* unicode character was emitted. */
|
||||
if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
|
||||
KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
|
||||
if (!KEV.bKeyDown &&
|
||||
(KEV.wVirtualKeyCode != VK_MENU ||
|
||||
KEV.uChar.UnicodeChar == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -797,8 +798,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
if (KEV.uChar.UnicodeChar >= 0xDC00 &&
|
||||
KEV.uChar.UnicodeChar < 0xE000) {
|
||||
/* UTF-16 surrogate pair */
|
||||
WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
|
||||
KEV.uChar.UnicodeChar};
|
||||
WCHAR utf16_buffer[2];
|
||||
utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
|
||||
utf16_buffer[1] = KEV.uChar.UnicodeChar;
|
||||
char_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
utf16_buffer,
|
||||
@@ -947,20 +949,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
handle->read_cb((uv_stream_t*) handle,
|
||||
uv_translate_sys_error(GET_REQ_ERROR(req)),
|
||||
&buf);
|
||||
} else {
|
||||
/* The read was cancelled, or whatever we don't care */
|
||||
handle->read_cb((uv_stream_t*) handle, 0, &buf);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
|
||||
req->u.io.overlapped.InternalHigh != 0) {
|
||||
/* Read successful. TODO: read unicode, convert to utf-8 */
|
||||
DWORD bytes = req->u.io.overlapped.InternalHigh;
|
||||
handle->read_cb((uv_stream_t*) handle, bytes, &buf);
|
||||
} else {
|
||||
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
|
||||
handle->read_cb((uv_stream_t*) handle, 0, &buf);
|
||||
}
|
||||
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
|
||||
}
|
||||
|
||||
/* Wait for more input events. */
|
||||
@@ -1039,6 +1036,7 @@ int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
/* Cancel raw read. Write some bullshit event to force the console wait to
|
||||
* return. */
|
||||
memset(&record, 0, sizeof record);
|
||||
record.EventType = FOCUS_EVENT;
|
||||
if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
|
||||
return GetLastError();
|
||||
}
|
||||
@@ -2185,14 +2183,14 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
void uv_tty_close(uv_tty_t* handle) {
|
||||
assert(handle->u.fd == -1 || handle->u.fd > 2);
|
||||
if (handle->flags & UV_HANDLE_READING)
|
||||
uv_tty_read_stop(handle);
|
||||
|
||||
if (handle->u.fd == -1)
|
||||
CloseHandle(handle->handle);
|
||||
else
|
||||
close(handle->u.fd);
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING)
|
||||
uv_tty_read_stop(handle);
|
||||
|
||||
handle->u.fd = -1;
|
||||
handle->handle = INVALID_HANDLE_VALUE;
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
@@ -2212,7 +2210,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
if (handle->stream.conn.shutdown_req->cb) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
|
||||
} else {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
|
||||
@@ -2225,7 +2223,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
/* The wait handle used for raw reading should be unregistered when the
|
||||
* wait callback runs. */
|
||||
|
||||
@@ -36,22 +36,27 @@ const unsigned int uv_active_udp_streams_threshold = 0;
|
||||
|
||||
/* A zero-size buffer for use by uv_udp_read */
|
||||
static char uv_zero_[] = "";
|
||||
int uv_udp_getpeername(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
int result;
|
||||
|
||||
if (handle->socket == INVALID_SOCKET) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
result = getsockname(handle->socket, name, namelen);
|
||||
if (result != 0) {
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +193,7 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
|
||||
|
||||
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
@@ -366,7 +371,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
int err;
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
return WSAEALREADY;
|
||||
return UV_EALREADY;
|
||||
}
|
||||
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
@@ -374,7 +379,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
if (err)
|
||||
return err;
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
@@ -784,6 +789,18 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_is_bound(uv_udp_t* handle) {
|
||||
struct sockaddr_storage addr;
|
||||
int addrlen;
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (uv_udp_getsockname(handle, (struct sockaddr*) &addr, &addrlen) != 0)
|
||||
return 0;
|
||||
|
||||
return addrlen > 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
WSAPROTOCOL_INFOW protocol_info;
|
||||
int opt_len;
|
||||
@@ -803,7 +820,16 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
handle,
|
||||
sock,
|
||||
protocol_info.iAddressFamily);
|
||||
return uv_translate_sys_error(err);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
if (uv__udp_is_bound(handle))
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
if (uv__udp_is_connected(handle))
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -880,6 +906,50 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_connect(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen) {
|
||||
const struct sockaddr* bind_addr;
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
if (addrlen == sizeof(uv_addr_ip4_any_))
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
|
||||
else if (addrlen == sizeof(uv_addr_ip6_any_))
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
err = connect(handle->socket, addr, addrlen);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
int err;
|
||||
struct sockaddr addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
err = connect(handle->socket, &addr, sizeof(addr));
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function is an egress point, i.e. it returns libuv errors rather than
|
||||
* system errors.
|
||||
*/
|
||||
@@ -900,6 +970,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
@@ -925,9 +996,11 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
if (addr != NULL) {
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Already sending a message.*/
|
||||
if (handle->send_queue_count != 0)
|
||||
|
||||
@@ -59,13 +59,6 @@
|
||||
# define UNLEN 256
|
||||
#endif
|
||||
|
||||
/*
|
||||
Max hostname length. The Windows gethostname() documentation states that 256
|
||||
bytes will always be large enough to hold the null-terminated hostname.
|
||||
*/
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
# define MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
/* Maximum environment variable size, including the terminating null */
|
||||
#define MAX_ENV_VAR_LENGTH 32767
|
||||
@@ -333,6 +326,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
uv_pid_t uv_os_getpid(void) {
|
||||
return GetCurrentProcessId();
|
||||
}
|
||||
@@ -690,12 +688,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||
NULL,
|
||||
(BYTE*)&cpu_brand,
|
||||
&cpu_brand_size);
|
||||
if (err != ERROR_SUCCESS) {
|
||||
RegCloseKey(processor_key);
|
||||
goto error;
|
||||
}
|
||||
|
||||
RegCloseKey(processor_key);
|
||||
if (err != ERROR_SUCCESS)
|
||||
goto error;
|
||||
|
||||
cpu_info = &cpu_infos[i];
|
||||
cpu_info->speed = cpu_speed;
|
||||
@@ -719,9 +714,11 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* This is safe because the cpu_infos array is zeroed on allocation. */
|
||||
for (i = 0; i < cpu_count; i++)
|
||||
uv__free(cpu_infos[i].model);
|
||||
if (cpu_infos != NULL) {
|
||||
/* This is safe because the cpu_infos array is zeroed on allocation. */
|
||||
for (i = 0; i < cpu_count; i++)
|
||||
uv__free(cpu_infos[i].model);
|
||||
}
|
||||
|
||||
uv__free(cpu_infos);
|
||||
uv__free(sppi);
|
||||
@@ -822,6 +819,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
int is_vista_or_greater;
|
||||
ULONG flags;
|
||||
|
||||
*addresses_ptr = NULL;
|
||||
*count_ptr = 0;
|
||||
|
||||
is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
|
||||
if (is_vista_or_greater) {
|
||||
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
|
||||
@@ -1514,7 +1514,7 @@ int uv_os_unsetenv(const char* name) {
|
||||
|
||||
|
||||
int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
char buf[MAXHOSTNAMELEN + 1];
|
||||
char buf[UV_MAXHOSTNAMESIZE];
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
@@ -1537,3 +1537,275 @@ int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
*size = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
|
||||
int r;
|
||||
|
||||
if (pid == 0)
|
||||
*handle = GetCurrentProcess();
|
||||
else
|
||||
*handle = OpenProcess(access, FALSE, pid);
|
||||
|
||||
if (*handle == NULL) {
|
||||
r = GetLastError();
|
||||
|
||||
if (r == ERROR_INVALID_PARAMETER)
|
||||
return UV_ESRCH;
|
||||
else
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getpriority(uv_pid_t pid, int* priority) {
|
||||
HANDLE handle;
|
||||
int r;
|
||||
|
||||
if (priority == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = GetPriorityClass(handle);
|
||||
|
||||
if (r == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
} else {
|
||||
/* Map Windows priority classes to Unix nice values. */
|
||||
if (r == REALTIME_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_HIGHEST;
|
||||
else if (r == HIGH_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_HIGH;
|
||||
else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_ABOVE_NORMAL;
|
||||
else if (r == NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_NORMAL;
|
||||
else if (r == BELOW_NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_BELOW_NORMAL;
|
||||
else /* IDLE_PRIORITY_CLASS */
|
||||
*priority = UV_PRIORITY_LOW;
|
||||
|
||||
r = 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
HANDLE handle;
|
||||
int priority_class;
|
||||
int r;
|
||||
|
||||
/* Map Unix nice values to Windows priority classes. */
|
||||
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
|
||||
return UV_EINVAL;
|
||||
else if (priority < UV_PRIORITY_HIGH)
|
||||
priority_class = REALTIME_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_ABOVE_NORMAL)
|
||||
priority_class = HIGH_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_NORMAL)
|
||||
priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_BELOW_NORMAL)
|
||||
priority_class = NORMAL_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_LOW)
|
||||
priority_class = BELOW_NORMAL_PRIORITY_CLASS;
|
||||
else
|
||||
priority_class = IDLE_PRIORITY_CLASS;
|
||||
|
||||
r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (SetPriorityClass(handle, priority_class) == 0)
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
|
||||
CloseHandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
/* Implementation loosely based on
|
||||
https://github.com/gagern/gnulib/blob/master/lib/uname.c */
|
||||
OSVERSIONINFOW os_info;
|
||||
SYSTEM_INFO system_info;
|
||||
HKEY registry_key;
|
||||
WCHAR product_name_w[256];
|
||||
DWORD product_name_w_size;
|
||||
int version_size;
|
||||
int processor_level;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
os_info.dwOSVersionInfoSize = sizeof(os_info);
|
||||
os_info.szCSDVersion[0] = L'\0';
|
||||
|
||||
/* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
|
||||
if RtlGetVersion() is not available. */
|
||||
if (pRtlGetVersion) {
|
||||
pRtlGetVersion(&os_info);
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#pragma warning(suppress : 4996)
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the version field. */
|
||||
version_size = 0;
|
||||
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
®istry_key);
|
||||
|
||||
if (r == ERROR_SUCCESS) {
|
||||
product_name_w_size = sizeof(product_name_w);
|
||||
r = RegGetValueW(registry_key,
|
||||
NULL,
|
||||
L"ProductName",
|
||||
RRF_RT_REG_SZ,
|
||||
NULL,
|
||||
(PVOID) product_name_w,
|
||||
&product_name_w_size);
|
||||
RegCloseKey(registry_key);
|
||||
|
||||
if (r == ERROR_SUCCESS) {
|
||||
version_size = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
product_name_w,
|
||||
-1,
|
||||
buffer->version,
|
||||
sizeof(buffer->version),
|
||||
NULL,
|
||||
NULL);
|
||||
if (version_size == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Append service pack information to the version if present. */
|
||||
if (os_info.szCSDVersion[0] != L'\0') {
|
||||
if (version_size > 0)
|
||||
buffer->version[version_size - 1] = ' ';
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
os_info.szCSDVersion,
|
||||
-1,
|
||||
buffer->version + version_size,
|
||||
sizeof(buffer->version) - version_size,
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the sysname field. */
|
||||
#ifdef __MINGW32__
|
||||
r = snprintf(buffer->sysname,
|
||||
sizeof(buffer->sysname),
|
||||
"MINGW32_NT-%u.%u",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion);
|
||||
assert(r < sizeof(buffer->sysname));
|
||||
#else
|
||||
uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
|
||||
#endif
|
||||
|
||||
/* Populate the release field. */
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%d.%d.%d",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion,
|
||||
(unsigned int) os_info.dwBuildNumber);
|
||||
assert(r < sizeof(buffer->release));
|
||||
|
||||
/* Populate the machine field. */
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
switch (system_info.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
|
||||
|
||||
if (system_info.wProcessorLevel > 3) {
|
||||
processor_level = system_info.wProcessorLevel < 6 ?
|
||||
system_info.wProcessorLevel : 6;
|
||||
buffer->machine[1] = '0' + processor_level;
|
||||
}
|
||||
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
|
||||
uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_MIPS:
|
||||
uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||||
uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_PPC:
|
||||
uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_SHX:
|
||||
uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
|
||||
break;
|
||||
default:
|
||||
uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
int uv_gettimeofday(uv_timeval64_t* tv) {
|
||||
/* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
|
||||
const uint64_t epoch = (uint64_t) 116444736000000000ULL;
|
||||
FILETIME file_time;
|
||||
ULARGE_INTEGER ularge;
|
||||
|
||||
if (tv == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
GetSystemTimeAsFileTime(&file_time);
|
||||
ularge.LowPart = file_time.dwLowDateTime;
|
||||
ularge.HighPart = file_time.dwHighDateTime;
|
||||
tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
|
||||
tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
sRtlGetVersion pRtlGetVersion;
|
||||
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
sNtQueryInformationFile pNtQueryInformationFile;
|
||||
@@ -34,6 +35,9 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
@@ -45,12 +49,16 @@ void uv_winapi_init(void) {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE kernel32_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
|
||||
"RtlGetVersion");
|
||||
|
||||
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
|
||||
ntdll_module,
|
||||
"RtlNtStatusToDosError");
|
||||
@@ -98,6 +106,15 @@ void uv_winapi_init(void) {
|
||||
uv_fatal_error(GetLastError(), "GetProcAddress");
|
||||
}
|
||||
|
||||
kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
|
||||
kernel32_module,
|
||||
"GetQueuedCompletionStatusEx");
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
|
||||
@@ -4109,6 +4109,9 @@
|
||||
#endif
|
||||
|
||||
/* from winternl.h */
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
|
||||
#define __UNICODE_STRING_DEFINED
|
||||
#endif
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
@@ -4516,6 +4519,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG Reserved);
|
||||
|
||||
typedef NTSTATUS (NTAPI *sRtlGetVersion)
|
||||
(PRTL_OSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
typedef ULONG (NTAPI *sRtlNtStatusToDosError)
|
||||
(NTSTATUS Status);
|
||||
|
||||
@@ -4642,6 +4648,14 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
|
||||
# define ERROR_MUI_FILE_NOT_LOADED 15105
|
||||
#endif
|
||||
|
||||
typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
|
||||
(HANDLE CompletionPort,
|
||||
LPOVERLAPPED_ENTRY lpCompletionPortEntries,
|
||||
ULONG ulCount,
|
||||
PULONG ulNumEntriesRemoved,
|
||||
DWORD dwMilliseconds,
|
||||
BOOL fAlertable);
|
||||
|
||||
/* from powerbase.h */
|
||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||
# define DEVICE_NOTIFY_CALLBACK 2
|
||||
@@ -4696,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
extern sNtQueryInformationFile pNtQueryInformationFile;
|
||||
@@ -4704,6 +4719,9 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
|
||||
@@ -89,12 +89,6 @@ void uv_winsock_init(void) {
|
||||
WSAPROTOCOL_INFOW protocol_info;
|
||||
int opt_len;
|
||||
|
||||
/* Initialize winsock */
|
||||
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
if (errorno != 0) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Set implicit binding address used by connectEx */
|
||||
if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
|
||||
abort();
|
||||
@@ -104,6 +98,15 @@ void uv_winsock_init(void) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Skip initialization in safe mode without network support */
|
||||
if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
|
||||
|
||||
/* Initialize winsock */
|
||||
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
if (errorno != 0) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Detect non-IFS LSPs */
|
||||
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user