Update libuv to 1.30.1 release

This commit is contained in:
Peter Johnson
2019-07-13 18:09:28 -07:00
parent 85f2f87400
commit 89f7b72b6e
78 changed files with 3867 additions and 2155 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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. */
}

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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. */
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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. */
}

View File

@@ -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. */
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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