mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 21:59:54 -06:00
Merge topic 'update-libuv'
db4667cc72libuv: fix compilation with macOS 10.10 SDKcee57246eflibuv: Add uv__statx() stub to cmake-bootstrap.c69b139cfcaMerge branch 'upstream-libuv' into update-libuvb4069b04fflibuv 2019-06-10 (ee24ce90) Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !3457
This commit is contained in:
@@ -206,6 +206,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;
|
||||
@@ -634,7 +635,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);
|
||||
@@ -1111,6 +1116,11 @@ typedef struct {
|
||||
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 */
|
||||
@@ -1162,6 +1172,17 @@ 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);
|
||||
@@ -1199,9 +1220,19 @@ typedef enum {
|
||||
UV_FS_FCHOWN,
|
||||
UV_FS_REALPATH,
|
||||
UV_FS_COPYFILE,
|
||||
UV_FS_LCHOWN
|
||||
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
|
||||
@@ -1294,6 +1325,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,
|
||||
@@ -1536,6 +1579,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);
|
||||
|
||||
@@ -1589,9 +1633,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);
|
||||
|
||||
@@ -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>
|
||||
@@ -50,8 +51,6 @@
|
||||
# include "linux.h"
|
||||
#elif defined (__MVS__)
|
||||
# include "os390.h"
|
||||
#elif defined(__PASE__)
|
||||
# include "posix.h"
|
||||
#elif defined(_AIX)
|
||||
# include "aix.h"
|
||||
#elif defined(__sun)
|
||||
@@ -64,9 +63,12 @@
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "bsd.h"
|
||||
#elif defined(__CYGWIN__) || defined(__MSYS__)
|
||||
#elif defined(__PASE__) || \
|
||||
defined(__CYGWIN__) || \
|
||||
defined(__MSYS__) || \
|
||||
defined(__GNU__)
|
||||
# include "posix.h"
|
||||
#elif defined(__GNU__)
|
||||
#elif defined(__HAIKU__)
|
||||
# include "posix.h"
|
||||
#endif
|
||||
|
||||
@@ -149,7 +151,9 @@ typedef pthread_cond_t uv_cond_t;
|
||||
typedef pthread_key_t uv_key_t;
|
||||
|
||||
/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
|
||||
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
#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;
|
||||
@@ -178,6 +182,9 @@ typedef uid_t uv_uid_t;
|
||||
|
||||
typedef struct dirent uv__dirent_t;
|
||||
|
||||
#define UV_DIR_PRIVATE_FIELDS \
|
||||
DIR* dir;
|
||||
|
||||
#if defined(DT_UNKNOWN)
|
||||
# define HAVE_DIRENT_TYPES
|
||||
# if defined(DT_REG)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 24
|
||||
#define UV_VERSION_MINOR 29
|
||||
#define UV_VERSION_PATCH 2
|
||||
#define UV_VERSION_IS_RELEASE 0
|
||||
#define UV_VERSION_SUFFIX "dev"
|
||||
|
||||
@@ -312,6 +312,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
|
||||
|
||||
@@ -22,12 +22,20 @@
|
||||
#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;
|
||||
@@ -36,6 +44,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 */
|
||||
};
|
||||
|
||||
@@ -49,6 +58,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;
|
||||
}
|
||||
|
||||
@@ -62,7 +72,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;
|
||||
@@ -90,6 +100,8 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
if (handle->poll_ctx != NULL)
|
||||
ctx->previous = handle->poll_ctx;
|
||||
handle->poll_ctx = ctx;
|
||||
uv__handle_start(handle);
|
||||
|
||||
@@ -104,19 +116,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 = 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);
|
||||
@@ -129,7 +139,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;
|
||||
}
|
||||
@@ -153,6 +163,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,14 +186,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) {
|
||||
@@ -205,7 +217,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;
|
||||
}
|
||||
@@ -219,8 +231,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 = handle->poll_ctx, it = last->previous;
|
||||
it != ctx;
|
||||
last = it, it = it->previous) {
|
||||
assert(last->previous != NULL);
|
||||
}
|
||||
last->previous = ctx->previous;
|
||||
}
|
||||
uv__free(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_THREADPOOL_SIZE 128
|
||||
#define MAX_THREADPOOL_SIZE 1024
|
||||
|
||||
static uv_once_t once = UV_ONCE_INIT;
|
||||
static uv_cond_t cond;
|
||||
|
||||
@@ -344,6 +344,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]) {
|
||||
perfstat_cpu_total_t ps_total;
|
||||
int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
|
||||
@@ -1041,6 +1046,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct poll_ctl pc;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct pollfd*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
|
||||
@@ -61,14 +61,43 @@ int uv_async_send(uv_async_t* handle) {
|
||||
if (ACCESS_ONCE(int, handle->pending) != 0)
|
||||
return 0;
|
||||
|
||||
if (cmpxchgi(&handle->pending, 0, 1) == 0)
|
||||
uv__async_send(handle->loop);
|
||||
/* Tell the other thread we're busy with the handle. */
|
||||
if (cmpxchgi(&handle->pending, 0, 1) != 0)
|
||||
return 0;
|
||||
|
||||
/* Wake up the other thread's event loop. */
|
||||
uv__async_send(handle->loop);
|
||||
|
||||
/* Tell the other thread we're done. */
|
||||
if (cmpxchgi(&handle->pending, 1, 2) != 1)
|
||||
abort();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Only call this from the event loop thread. */
|
||||
static int uv__async_spin(uv_async_t* handle) {
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
/* rc=0 -- handle is not pending.
|
||||
* rc=1 -- handle is pending, other thread is still working with it.
|
||||
* rc=2 -- handle is pending, other thread is done.
|
||||
*/
|
||||
rc = cmpxchgi(&handle->pending, 2, 0);
|
||||
|
||||
if (rc != 1)
|
||||
return rc;
|
||||
|
||||
/* Other thread is busy with this handle, spin until it's done. */
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv__async_close(uv_async_t* handle) {
|
||||
uv__async_spin(handle);
|
||||
QUEUE_REMOVE(&handle->queue);
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
@@ -109,8 +138,8 @@ static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->async_handles, q);
|
||||
|
||||
if (cmpxchgi(&h->pending, 1, 0) == 0)
|
||||
continue;
|
||||
if (0 == uv__async_spin(h))
|
||||
continue; /* Not pending. */
|
||||
|
||||
if (h->async_cb == NULL)
|
||||
continue;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#endif
|
||||
|
||||
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
|
||||
UV_UNUSED(static void cpu_relax(void));
|
||||
|
||||
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
|
||||
@@ -49,43 +48,7 @@ UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
|
||||
else
|
||||
return op4;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_uint(ptr, oldval, newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
}
|
||||
|
||||
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
long out;
|
||||
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
|
||||
: "=a" (out), "+m" (*(volatile long*) ptr)
|
||||
: "r" (newval), "0" (oldval)
|
||||
: "memory");
|
||||
return out;
|
||||
#elif defined(_AIX) && (defined(__xlC__) || defined(__ibmxl__))
|
||||
const long out = (*(volatile int*) ptr);
|
||||
# if defined(__64BIT__)
|
||||
__compare_and_swaplp(ptr, &oldval, newval);
|
||||
# else
|
||||
__compare_and_swap(ptr, &oldval, newval);
|
||||
# endif /* if defined(__64BIT__) */
|
||||
return out;
|
||||
#elif defined (__MVS__)
|
||||
#ifdef _LP64
|
||||
unsigned long long op4;
|
||||
if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
|
||||
(unsigned long long*) ptr, *ptr, &op4))
|
||||
#else
|
||||
unsigned long op4;
|
||||
if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
|
||||
(unsigned int*) ptr, *ptr, &op4))
|
||||
#endif
|
||||
return oldval;
|
||||
else
|
||||
return op4;
|
||||
#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
|
||||
return atomic_cas_ulong(ptr, oldval, newval);
|
||||
return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
|
||||
#else
|
||||
return __sync_val_compare_and_swap(ptr, oldval, newval);
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#define IFF_RUNNING IFF_LINK
|
||||
#endif
|
||||
|
||||
static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
|
||||
return 1;
|
||||
@@ -45,7 +49,8 @@ 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.
|
||||
@@ -84,7 +89,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
/* Make sure the memory is initiallized to zero using calloc() */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
|
||||
if (*addresses == NULL) {
|
||||
freeifaddrs(addrs);
|
||||
@@ -116,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))
|
||||
@@ -124,20 +131,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
#else
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
struct sockaddr_dl* sa_addr;
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
} else {
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
}
|
||||
#endif
|
||||
address++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
freeifaddrs(addrs);
|
||||
|
||||
|
||||
@@ -137,4 +137,13 @@ int uv__utimesat(int dirfd, const char* path, const struct timespec times[2],
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int uv__statx(int dirfd,
|
||||
const char* path,
|
||||
int flags,
|
||||
unsigned int mask,
|
||||
struct uv__statx* statxbuf) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
#include <pwd.h>
|
||||
#include <sched.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>
|
||||
@@ -91,13 +91,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);
|
||||
@@ -174,7 +169,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);
|
||||
@@ -520,6 +517,34 @@ skip:
|
||||
}
|
||||
|
||||
|
||||
/* 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__)
|
||||
extern int close$NOCANCEL(int);
|
||||
return close$NOCANCEL(fd);
|
||||
#else
|
||||
extern int close$NOCANCEL$UNIX2003(int);
|
||||
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;
|
||||
@@ -527,7 +552,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))
|
||||
@@ -562,7 +587,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;
|
||||
|
||||
@@ -895,7 +920,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -929,7 +955,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;
|
||||
@@ -1294,7 +1320,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)
|
||||
@@ -1426,3 +1452,39 @@ error:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -137,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);
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel_) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# define HAVE_PREADV 1
|
||||
@@ -60,7 +60,6 @@
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <copyfile.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__linux__) && !defined(FICLONE)
|
||||
# include <sys/ioctl.h>
|
||||
@@ -143,18 +142,33 @@ extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
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)
|
||||
r = fcntl(req->file, 85 /* F_BARRIERFSYNC */); /* fsync + barrier */
|
||||
if (r != 0)
|
||||
r = fsync(req->file);
|
||||
return r;
|
||||
@@ -178,7 +192,8 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
|
||||
|
||||
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71)
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
@@ -327,6 +342,18 @@ done:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -349,7 +376,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;
|
||||
@@ -373,6 +400,87 @@ 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__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 = 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 = req->ptr;
|
||||
|
||||
if (dir->dir != NULL) {
|
||||
closedir(dir->dir);
|
||||
dir->dir = NULL;
|
||||
}
|
||||
|
||||
uv__free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_POSIX_PATH_MAX)
|
||||
# define UV__FS_PATH_MAX _POSIX_PATH_MAX
|
||||
#elif defined(PATH_MAX)
|
||||
@@ -702,7 +810,8 @@ 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(__sun) \
|
||||
|| defined(__HAIKU__)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
@@ -806,45 +915,6 @@ done:
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
/* On macOS, use the native copyfile(3). */
|
||||
static int can_clone;
|
||||
copyfile_flags_t flags;
|
||||
char buf[64];
|
||||
size_t len;
|
||||
int major;
|
||||
|
||||
flags = COPYFILE_ALL;
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_EXCL)
|
||||
flags |= COPYFILE_EXCL;
|
||||
|
||||
/* Check OS version. Cloning is only supported on macOS >= 10.12. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
if (can_clone == 0) {
|
||||
len = sizeof(buf);
|
||||
if (sysctlbyname("kern.osrelease", buf, &len, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (1 != sscanf(buf, "%d", &major))
|
||||
abort();
|
||||
|
||||
can_clone = -1 + 2 * (major >= 16); /* macOS >= 10.12 */
|
||||
}
|
||||
|
||||
if (can_clone < 0)
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
/* copyfile() simply ignores COPYFILE_CLONE if it's not supported. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE)
|
||||
flags |= 1 << 24; /* COPYFILE_CLONE */
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)
|
||||
flags |= 1 << 25; /* COPYFILE_CLONE_FORCE */
|
||||
|
||||
return copyfile(req->path, req->new_path, NULL, flags);
|
||||
#else
|
||||
uv_fs_t fs_req;
|
||||
uv_file srcfd;
|
||||
uv_file dstfd;
|
||||
@@ -971,7 +1041,6 @@ out:
|
||||
|
||||
errno = UV__ERR(result);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
|
||||
@@ -1051,10 +1120,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);
|
||||
@@ -1067,6 +1210,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);
|
||||
@@ -1079,6 +1226,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);
|
||||
@@ -1167,7 +1318,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));
|
||||
@@ -1184,6 +1335,9 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(OPEN, uv__fs_open(req));
|
||||
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));
|
||||
@@ -1454,6 +1608,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,
|
||||
@@ -1594,6 +1782,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);
|
||||
|
||||
@@ -1601,7 +1792,7 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
uv__free(req->bufs);
|
||||
req->bufs = NULL;
|
||||
|
||||
if (req->ptr != &req->statbuf)
|
||||
if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf)
|
||||
uv__free(req->ptr);
|
||||
req->ptr = NULL;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
|
||||
|
||||
/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
|
||||
/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
|
||||
|
||||
int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
return 0;
|
||||
|
||||
@@ -92,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
|
||||
}
|
||||
|
||||
|
||||
|
||||
176
Utilities/cmlibuv/src/unix/haiku.c
Normal file
176
Utilities/cmlibuv/src/unix/haiku.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/* 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 <FindDirectory.h> /* find_path() */
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
void uv_loadavg(double avg[3]) {
|
||||
avg[0] = 0;
|
||||
avg[1] = 0;
|
||||
avg[2] = 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_exepath(char* buffer, size_t* size) {
|
||||
char abspath[B_PATH_NAME_LENGTH];
|
||||
status_t status;
|
||||
ssize_t abspath_len;
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
status = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, NULL, abspath,
|
||||
sizeof(abspath));
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
abspath_len = uv__strscpy(buffer, abspath, *size);
|
||||
*size -= 1;
|
||||
if (abspath_len >= 0 && *size > (size_t)abspath_len)
|
||||
*size = (size_t)abspath_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_free_memory(void) {
|
||||
status_t status;
|
||||
system_info sinfo;
|
||||
|
||||
status = get_system_info(&sinfo);
|
||||
if (status != B_OK)
|
||||
return 0;
|
||||
|
||||
return (sinfo.max_pages - sinfo.used_pages) * B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_total_memory(void) {
|
||||
status_t status;
|
||||
system_info sinfo;
|
||||
|
||||
status = get_system_info(&sinfo);
|
||||
if (status != B_OK)
|
||||
return 0;
|
||||
|
||||
return sinfo.max_pages * B_PAGE_SIZE;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
area_info area;
|
||||
ssize_t cookie;
|
||||
status_t status;
|
||||
thread_info thread;
|
||||
|
||||
status = get_thread_info(find_thread(NULL), &thread);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
cookie = 0;
|
||||
*rss = 0;
|
||||
while (get_next_area_info(thread.team, &cookie, &area) == B_OK)
|
||||
*rss += area.ram_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_uptime(double* uptime) {
|
||||
/* system_time() returns time since booting in microseconds */
|
||||
*uptime = (double)system_time() / 1000000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
cpu_topology_node_info* topology_infos;
|
||||
int i;
|
||||
status_t status;
|
||||
system_info system;
|
||||
uint32_t topology_count;
|
||||
uint64_t cpuspeed;
|
||||
uv_cpu_info_t* cpu_info;
|
||||
|
||||
if (cpu_infos == NULL || count == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
status = get_cpu_topology_info(NULL, &topology_count);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
topology_infos = uv__malloc(topology_count * sizeof(*topology_infos));
|
||||
if (topology_infos == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
status = get_cpu_topology_info(topology_infos, &topology_count);
|
||||
if (status != B_OK) {
|
||||
uv__free(topology_infos);
|
||||
return UV__ERR(status);
|
||||
}
|
||||
|
||||
cpuspeed = 0;
|
||||
for (i = 0; i < (int)topology_count; i++) {
|
||||
if (topology_infos[i].type == B_TOPOLOGY_CORE) {
|
||||
cpuspeed = topology_infos[i].data.core.default_frequency;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uv__free(topology_infos);
|
||||
|
||||
status = get_system_info(&system);
|
||||
if (status != B_OK)
|
||||
return UV__ERR(status);
|
||||
|
||||
*cpu_infos = uv__calloc(system.cpu_count, sizeof(**cpu_infos));
|
||||
if (*cpu_infos == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* CPU time and model are not exposed by Haiku. */
|
||||
cpu_info = *cpu_infos;
|
||||
for (i = 0; i < (int)system.cpu_count; i++) {
|
||||
cpu_info->model = uv__strdup("unknown");
|
||||
cpu_info->speed = (int)(cpuspeed / 1000000);
|
||||
cpu_info++;
|
||||
}
|
||||
*count = system.cpu_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
uv__free(cpu_infos[i].model);
|
||||
|
||||
uv__free(cpu_infos);
|
||||
}
|
||||
@@ -55,19 +55,155 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,3 +247,4 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,8 +105,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
|
||||
@@ -194,6 +193,7 @@ 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);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
@@ -316,4 +316,11 @@ UV_UNUSED(static char* uv__basename_r(const char* path)) {
|
||||
int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
|
||||
#endif
|
||||
|
||||
typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
|
||||
|
||||
int uv__getsockpeername(const uv_handle_t* handle,
|
||||
uv__peersockfunc func,
|
||||
struct sockaddr* name,
|
||||
int* namelen);
|
||||
|
||||
#endif /* UV_UNIX_INTERNAL_H_ */
|
||||
|
||||
@@ -59,7 +59,7 @@ int uv__kqueue_init(uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
static int uv__has_forked_with_cfrunloop;
|
||||
#endif
|
||||
|
||||
@@ -70,7 +70,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (loop->cf_state != NULL) {
|
||||
/* We cannot start another CFRunloop and/or thread in the child
|
||||
process; CF aborts if you try or if you try to touch the thread
|
||||
@@ -86,7 +86,7 @@ int uv__io_fork(uv_loop_t* loop) {
|
||||
uv__free(loop->cf_state);
|
||||
loop->cf_state = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -387,6 +387,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct kevent*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
@@ -457,7 +458,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
handle->realpath = NULL;
|
||||
@@ -481,7 +482,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(__APPLE__) */
|
||||
#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
@@ -489,8 +490,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
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);
|
||||
@@ -509,7 +513,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||
if (!uv__has_forked_with_cfrunloop)
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -79,16 +80,20 @@ 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 = epoll_create1(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 = epoll_create(256);
|
||||
@@ -141,6 +146,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
@@ -714,20 +720,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);
|
||||
@@ -760,7 +766,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,
|
||||
@@ -782,8 +789,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;
|
||||
|
||||
@@ -796,7 +803,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);
|
||||
@@ -859,7 +866,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
/* Make sure the memory is initiallized to zero using calloc() */
|
||||
*addresses = uv__calloc(*count, sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
return UV_ENOMEM;
|
||||
@@ -898,11 +906,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < (*count); i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
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));
|
||||
} else {
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
@@ -932,3 +941,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");
|
||||
}
|
||||
|
||||
@@ -187,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__)
|
||||
@@ -336,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
|
||||
}
|
||||
|
||||
@@ -80,6 +80,36 @@
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
uint32_t mask;
|
||||
@@ -113,5 +143,10 @@ int uv__sendmmsg(int fd,
|
||||
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_ */
|
||||
|
||||
@@ -126,6 +126,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
kvm_t *kd = NULL;
|
||||
struct kinfo_proc2 *kinfo = NULL;
|
||||
|
||||
@@ -136,6 +136,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size = getpagesize();
|
||||
|
||||
@@ -356,6 +356,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_constrained_memory(void) {
|
||||
return 0; /* Memory constraints are unknown. */
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
char* ascb;
|
||||
char* rax;
|
||||
@@ -657,6 +662,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
|
||||
@@ -213,7 +213,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -231,9 +231,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,
|
||||
@@ -244,10 +241,13 @@ static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
|
||||
|
||||
addrlen = sizeof(sa);
|
||||
memset(&sa, 0, addrlen);
|
||||
err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
|
||||
err = uv__getsockpeername((const uv_handle_t*) handle,
|
||||
func,
|
||||
(struct sockaddr*) &sa,
|
||||
(int*) &addrlen);
|
||||
if (err < 0) {
|
||||
*size = 0;
|
||||
return UV__ERR(errno);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
@@ -298,6 +298,8 @@ update_timeout:
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
size_t i;
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (loop->poll_fds_iterating) {
|
||||
/* uv__io_poll is currently iterating. Just invalidate fd. */
|
||||
for (i = 0; i < loop->poll_fds_used; i++)
|
||||
|
||||
@@ -426,6 +426,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;
|
||||
|
||||
@@ -486,6 +491,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);
|
||||
|
||||
@@ -745,13 +745,13 @@ static int uv__write_req_update(uv_stream_t* stream,
|
||||
|
||||
buf = req->bufs + req->write_index;
|
||||
|
||||
while (n > 0) {
|
||||
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;
|
||||
|
||||
@@ -897,7 +897,7 @@ start:
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (n > 0 && uv__write_req_update(stream, req, n)) {
|
||||
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. */
|
||||
}
|
||||
@@ -1541,7 +1541,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;
|
||||
}
|
||||
|
||||
@@ -121,6 +121,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
assert(fd >= 0);
|
||||
|
||||
events = (struct port_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
@@ -138,8 +139,10 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd))
|
||||
if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd)) {
|
||||
perror("(libuv) port_dissociate()");
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -177,8 +180,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
w = QUEUE_DATA(q, uv__io_t, watcher_queue);
|
||||
assert(w->pevents != 0);
|
||||
|
||||
if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
|
||||
if (port_associate(loop->backend_fd,
|
||||
PORT_SOURCE_FD,
|
||||
w->fd,
|
||||
w->pevents,
|
||||
0)) {
|
||||
perror("(libuv) port_associate()");
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
@@ -222,10 +231,12 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
/* Work around another kernel bug: port_getn() may return events even
|
||||
* on error.
|
||||
*/
|
||||
if (errno == EINTR || errno == ETIME)
|
||||
if (errno == EINTR || errno == ETIME) {
|
||||
saved_errno = errno;
|
||||
else
|
||||
} else {
|
||||
perror("(libuv) port_getn()");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
@@ -373,6 +384,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]) {
|
||||
(void) getloadavg(avg, 3);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
@@ -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);
|
||||
}
|
||||
@@ -279,44 +283,28 @@ int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,8 +48,10 @@
|
||||
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
|
||||
#endif
|
||||
|
||||
/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */
|
||||
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
/* 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;
|
||||
@@ -176,8 +178,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
|
||||
|
||||
@@ -192,13 +207,36 @@ static size_t thread_stack_size(void) {
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
uv_thread_options_t params;
|
||||
params.flags = UV_THREAD_NO_FLAGS;
|
||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||
}
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
void *arg) {
|
||||
int err;
|
||||
size_t stack_size;
|
||||
pthread_attr_t* attr;
|
||||
pthread_attr_t attr_storage;
|
||||
size_t pagesize;
|
||||
size_t stack_size;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
attr = NULL;
|
||||
stack_size = thread_stack_size();
|
||||
if (stack_size == 0) {
|
||||
stack_size = thread_stack_size();
|
||||
} else {
|
||||
pagesize = (size_t)getpagesize();
|
||||
/* Round up to the nearest page boundary. */
|
||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||
#ifdef PTHREAD_STACK_MIN
|
||||
if (stack_size < PTHREAD_STACK_MIN)
|
||||
stack_size = PTHREAD_STACK_MIN;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (stack_size > 0) {
|
||||
attr = &attr_storage;
|
||||
@@ -778,7 +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. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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__) */
|
||||
}
|
||||
|
||||
|
||||
@@ -851,23 +940,24 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_udp_getpeername(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getpeername,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
int uv_udp_getsockname(const uv_udp_t* handle,
|
||||
struct sockaddr* name,
|
||||
int* namelen) {
|
||||
socklen_t socklen;
|
||||
|
||||
if (handle->io_watcher.fd == -1)
|
||||
return UV_EINVAL; /* FIXME(bnoordhuis) UV_EBADF */
|
||||
|
||||
/* sizeof(socklen_t) != sizeof(int) on some systems. */
|
||||
socklen = (socklen_t) *namelen;
|
||||
|
||||
if (getsockname(handle->io_watcher.fd, name, &socklen))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*namelen = (int) socklen;
|
||||
return 0;
|
||||
return uv__getsockpeername((const uv_handle_t*) handle,
|
||||
getsockname,
|
||||
name,
|
||||
namelen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
# include <malloc.h> /* malloc */
|
||||
#else
|
||||
# include <net/if.h> /* if_nametoindex */
|
||||
# include <sys/un.h> /* AF_UNIX, sockaddr_un */
|
||||
#endif
|
||||
|
||||
|
||||
@@ -223,6 +224,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) {
|
||||
@@ -315,17 +319,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)
|
||||
@@ -333,6 +340,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);
|
||||
}
|
||||
|
||||
@@ -341,17 +412,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);
|
||||
}
|
||||
@@ -573,37 +638,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 = 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ enum {
|
||||
|
||||
/* 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,
|
||||
@@ -142,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[],
|
||||
@@ -184,6 +193,8 @@ 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);
|
||||
|
||||
@@ -36,7 +36,7 @@ const char* uv_req_type_name(uv_req_type type) {
|
||||
case UV_REQ_TYPE_MAX:
|
||||
case UV_UNKNOWN_REQ:
|
||||
default: /* UV_REQ_TYPE_PRIVATE */
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -627,3 +627,26 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1125,6 +1125,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__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 = 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 = 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 = 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) {
|
||||
@@ -2039,6 +2170,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)
|
||||
@@ -2080,6 +2214,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);
|
||||
}
|
||||
@@ -2247,6 +2383,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) {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -276,6 +276,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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -112,9 +112,34 @@ static UINT __stdcall uv__thread_start(void* arg) {
|
||||
|
||||
|
||||
int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
uv_thread_options_t params;
|
||||
params.flags = UV_THREAD_NO_FLAGS;
|
||||
return uv_thread_create_ex(tid, ¶ms, entry, arg);
|
||||
}
|
||||
|
||||
int uv_thread_create_ex(uv_thread_t* tid,
|
||||
const uv_thread_options_t* params,
|
||||
void (*entry)(void *arg),
|
||||
void *arg) {
|
||||
struct thread_ctx* ctx;
|
||||
int err;
|
||||
HANDLE thread;
|
||||
SYSTEM_INFO sysinfo;
|
||||
size_t stack_size;
|
||||
size_t pagesize;
|
||||
|
||||
stack_size =
|
||||
params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
|
||||
|
||||
if (stack_size != 0) {
|
||||
GetNativeSystemInfo(&sysinfo);
|
||||
pagesize = (size_t)sysinfo.dwPageSize;
|
||||
/* Round up to the nearest page boundary. */
|
||||
stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
|
||||
|
||||
if ((unsigned)stack_size != stack_size)
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
ctx = uv__malloc(sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
@@ -126,7 +151,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
/* Create the thread in suspended state so we have a chance to pass
|
||||
* its own creation handle to it */
|
||||
thread = (HANDLE) _beginthreadex(NULL,
|
||||
0,
|
||||
(unsigned)stack_size,
|
||||
uv__thread_start,
|
||||
ctx,
|
||||
CREATE_SUSPENDED,
|
||||
|
||||
@@ -736,8 +736,8 @@ 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.wVirtualKeyCode != VK_MENU &&
|
||||
KEV.uChar.UnicodeChar != 0) {
|
||||
(KEV.wVirtualKeyCode != VK_MENU ||
|
||||
KEV.uChar.UnicodeChar == 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -784,6 +789,18 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_is_bound(uv_udp_t* handle) {
|
||||
struct sockaddr_storage addr;
|
||||
int addrlen;
|
||||
|
||||
addrlen = sizeof(addr);
|
||||
if (uv_udp_getsockname(handle, (struct sockaddr*) &addr, &addrlen) != 0)
|
||||
return 0;
|
||||
|
||||
return addrlen > 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
WSAPROTOCOL_INFOW protocol_info;
|
||||
int opt_len;
|
||||
@@ -803,7 +820,16 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
handle,
|
||||
sock,
|
||||
protocol_info.iAddressFamily);
|
||||
return uv_translate_sys_error(err);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
if (uv__udp_is_bound(handle))
|
||||
handle->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
if (uv__udp_is_connected(handle))
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -880,6 +906,50 @@ int uv__udp_bind(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_connect(uv_udp_t* handle,
|
||||
const struct sockaddr* addr,
|
||||
unsigned int addrlen) {
|
||||
const struct sockaddr* bind_addr;
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
if (addrlen == sizeof(uv_addr_ip4_any_))
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
|
||||
else if (addrlen == sizeof(uv_addr_ip6_any_))
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
err = connect(handle->socket, addr, addrlen);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags |= UV_HANDLE_UDP_CONNECTED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__udp_disconnect(uv_udp_t* handle) {
|
||||
int err;
|
||||
struct sockaddr addr;
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
|
||||
err = connect(handle->socket, &addr, sizeof(addr));
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function is an egress point, i.e. it returns libuv errors rather than
|
||||
* system errors.
|
||||
*/
|
||||
@@ -900,6 +970,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
|
||||
err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
@@ -925,9 +996,11 @@ int uv__udp_try_send(uv_udp_t* handle,
|
||||
|
||||
assert(nbufs > 0);
|
||||
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
if (addr != NULL) {
|
||||
err = uv__convert_to_localhost_if_unspecified(addr, &converted);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Already sending a message.*/
|
||||
if (handle->send_queue_count != 0)
|
||||
|
||||
@@ -59,13 +59,6 @@
|
||||
# define UNLEN 256
|
||||
#endif
|
||||
|
||||
/*
|
||||
Max hostname length. The Windows gethostname() documentation states that 256
|
||||
bytes will always be large enough to hold the null-terminated hostname.
|
||||
*/
|
||||
#ifndef MAXHOSTNAMELEN
|
||||
# define MAXHOSTNAMELEN 256
|
||||
#endif
|
||||
|
||||
/* Maximum environment variable size, including the terminating null */
|
||||
#define MAX_ENV_VAR_LENGTH 32767
|
||||
@@ -327,6 +320,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();
|
||||
}
|
||||
@@ -684,12 +682,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;
|
||||
@@ -713,9 +708,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);
|
||||
@@ -1510,7 +1507,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)
|
||||
@@ -1634,6 +1631,10 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
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;
|
||||
|
||||
@@ -1658,16 +1659,56 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
}
|
||||
|
||||
/* Populate the version field. */
|
||||
if (WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
os_info.szCSDVersion,
|
||||
-1,
|
||||
buffer->version,
|
||||
sizeof(buffer->version),
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
version_size = 0;
|
||||
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
®istry_key);
|
||||
|
||||
if (r == ERROR_SUCCESS) {
|
||||
product_name_w_size = sizeof(product_name_w);
|
||||
r = RegGetValueW(registry_key,
|
||||
NULL,
|
||||
L"ProductName",
|
||||
RRF_RT_REG_SZ,
|
||||
NULL,
|
||||
(PVOID) product_name_w,
|
||||
&product_name_w_size);
|
||||
RegCloseKey(registry_key);
|
||||
|
||||
if (r == ERROR_SUCCESS) {
|
||||
version_size = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
product_name_w,
|
||||
-1,
|
||||
buffer->version,
|
||||
sizeof(buffer->version),
|
||||
NULL,
|
||||
NULL);
|
||||
if (version_size == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Append service pack information to the version if present. */
|
||||
if (os_info.szCSDVersion[0] != L'\0') {
|
||||
if (version_size > 0)
|
||||
buffer->version[version_size - 1] = ' ';
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
os_info.szCSDVersion,
|
||||
-1,
|
||||
buffer->version + version_size,
|
||||
sizeof(buffer->version) - version_size,
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the sysname field. */
|
||||
@@ -1744,3 +1785,20 @@ error:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -87,12 +87,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();
|
||||
@@ -102,6 +96,15 @@ void uv_winsock_init(void) {
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Skip initialization in safe mode without network support */
|
||||
if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
|
||||
|
||||
/* Initialize winsock */
|
||||
errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||
if (errorno != 0) {
|
||||
uv_fatal_error(errorno, "WSAStartup");
|
||||
}
|
||||
|
||||
/* Detect non-IFS LSPs */
|
||||
dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user