mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-11 16:32:14 -06:00
Merge branch 'upstream-libuv' into update-libuv
* upstream-libuv: libuv 2019-01-15 (f84c5e69)
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _UV_PTHREAD_BARRIER_
|
||||
#define _UV_PTHREAD_BARRIER_
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#if !defined(__MVS__)
|
||||
#include <semaphore.h> /* sem_t */
|
||||
#endif
|
||||
|
||||
#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
|
||||
#define UV__PTHREAD_BARRIER_FALLBACK 1
|
||||
|
||||
/*
|
||||
* To maintain ABI compatibility with
|
||||
* libuv v1.x struct is padded according
|
||||
* to target platform
|
||||
*/
|
||||
#if defined(__ANDROID__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
sizeof(pthread_cond_t) + \
|
||||
sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#elif defined(__APPLE__)
|
||||
# define UV_BARRIER_STRUCT_PADDING \
|
||||
sizeof(pthread_mutex_t) + \
|
||||
2 * sizeof(sem_t) + \
|
||||
2 * sizeof(unsigned int) - \
|
||||
sizeof(void *)
|
||||
#else
|
||||
# define UV_BARRIER_STRUCT_PADDING 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
unsigned threshold;
|
||||
unsigned in;
|
||||
unsigned out;
|
||||
} _uv_barrier;
|
||||
|
||||
typedef struct {
|
||||
_uv_barrier* b;
|
||||
char _pad[UV_BARRIER_STRUCT_PADDING];
|
||||
} pthread_barrier_t;
|
||||
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count);
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier);
|
||||
int pthread_barrier_destroy(pthread_barrier_t *barrier);
|
||||
|
||||
#endif /* _UV_PTHREAD_BARRIER_ */
|
||||
@@ -49,21 +49,21 @@ extern "C" {
|
||||
# define UV_EXTERN /* nothing */
|
||||
#endif
|
||||
|
||||
#include "uv-errno.h"
|
||||
#include "uv-version.h"
|
||||
#include "uv/errno.h"
|
||||
#include "uv/version.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# include "uv-win.h"
|
||||
# include "uv/win.h"
|
||||
#else
|
||||
# include "uv-unix.h"
|
||||
# include "uv/unix.h"
|
||||
#endif
|
||||
|
||||
/* Expand this list if necessary. */
|
||||
@@ -146,6 +146,7 @@ extern "C" {
|
||||
XX(EHOSTDOWN, "host is down") \
|
||||
XX(EREMOTEIO, "remote I/O error") \
|
||||
XX(ENOTTY, "inappropriate ioctl for device") \
|
||||
XX(EFTYPE, "inappropriate file type or format") \
|
||||
|
||||
#define UV_HANDLE_TYPE_MAP(XX) \
|
||||
XX(ASYNC, async) \
|
||||
@@ -237,6 +238,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t;
|
||||
typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
@@ -373,7 +375,10 @@ typedef enum {
|
||||
UV_EXTERN int uv_translate_sys_error(int sys_errno);
|
||||
|
||||
UV_EXTERN const char* uv_strerror(int err);
|
||||
UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen);
|
||||
|
||||
UV_EXTERN const char* uv_err_name(int err);
|
||||
UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen);
|
||||
|
||||
|
||||
#define UV_REQ_FIELDS \
|
||||
@@ -507,7 +512,7 @@ UV_EXTERN int uv_try_write(uv_stream_t* handle,
|
||||
struct uv_write_s {
|
||||
UV_REQ_FIELDS
|
||||
uv_write_cb cb;
|
||||
uv_stream_t* send_handle;
|
||||
uv_stream_t* send_handle; /* TODO: make private and unix-only in v2.x. */
|
||||
uv_stream_t* handle;
|
||||
UV_WRITE_PRIVATE_FIELDS
|
||||
};
|
||||
@@ -869,7 +874,13 @@ typedef enum {
|
||||
* flags may be specified to create a duplex data stream.
|
||||
*/
|
||||
UV_READABLE_PIPE = 0x10,
|
||||
UV_WRITABLE_PIPE = 0x20
|
||||
UV_WRITABLE_PIPE = 0x20,
|
||||
|
||||
/*
|
||||
* Open the child pipe handle in overlapped mode on Windows.
|
||||
* On Unix it is silently ignored.
|
||||
*/
|
||||
UV_OVERLAPPED_PIPE = 0x40
|
||||
} uv_stdio_flags;
|
||||
|
||||
typedef struct uv_stdio_container_s {
|
||||
@@ -969,12 +980,23 @@ enum uv_process_flags {
|
||||
* the child's process handle.
|
||||
*/
|
||||
UV_PROCESS_DETACHED = (1 << 3),
|
||||
/*
|
||||
* Hide the subprocess window that would normally be created. This option is
|
||||
* only meaningful on Windows systems. On Unix it is silently ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE = (1 << 4),
|
||||
/*
|
||||
* Hide the subprocess console window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE = (1 << 4)
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5),
|
||||
/*
|
||||
* Hide the subprocess GUI window that would normally be created. This
|
||||
* option is only meaningful on Windows systems. On Unix it is silently
|
||||
* ignored.
|
||||
*/
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1014,16 +1036,18 @@ UV_EXTERN int uv_queue_work(uv_loop_t* loop,
|
||||
UV_EXTERN int uv_cancel(uv_req_t* req);
|
||||
|
||||
|
||||
struct uv_cpu_times_s {
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t sys;
|
||||
uint64_t idle;
|
||||
uint64_t irq;
|
||||
};
|
||||
|
||||
struct uv_cpu_info_s {
|
||||
char* model;
|
||||
int speed;
|
||||
struct uv_cpu_times_s {
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t sys;
|
||||
uint64_t idle;
|
||||
uint64_t irq;
|
||||
} cpu_times;
|
||||
struct uv_cpu_times_s cpu_times;
|
||||
};
|
||||
|
||||
struct uv_interface_address_s {
|
||||
@@ -1048,6 +1072,16 @@ struct uv_passwd_s {
|
||||
char* homedir;
|
||||
};
|
||||
|
||||
struct uv_utsname_s {
|
||||
char sysname[256];
|
||||
char release[256];
|
||||
char version[256];
|
||||
char machine[256];
|
||||
/* This struct does not contain the nodename and domainname fields present in
|
||||
the utsname type. domainname is a GNU extension. Both fields are referred
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@@ -1070,6 +1104,7 @@ UV_EXTERN int uv_set_process_title(const char* title);
|
||||
UV_EXTERN int uv_resident_set_memory(size_t* rss);
|
||||
UV_EXTERN int uv_uptime(double* uptime);
|
||||
UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
|
||||
UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd);
|
||||
|
||||
typedef struct {
|
||||
long tv_sec;
|
||||
@@ -1104,6 +1139,16 @@ UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
|
||||
UV_EXTERN uv_pid_t uv_os_getpid(void);
|
||||
UV_EXTERN uv_pid_t uv_os_getppid(void);
|
||||
|
||||
#define UV_PRIORITY_LOW 19
|
||||
#define UV_PRIORITY_BELOW_NORMAL 10
|
||||
#define UV_PRIORITY_NORMAL 0
|
||||
#define UV_PRIORITY_ABOVE_NORMAL -7
|
||||
#define UV_PRIORITY_HIGH -14
|
||||
#define UV_PRIORITY_HIGHEST -20
|
||||
|
||||
UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
|
||||
UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
|
||||
|
||||
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
|
||||
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
|
||||
UV_EXTERN int uv_cpumask_size(void);
|
||||
@@ -1119,6 +1164,8 @@ UV_EXTERN int uv_os_unsetenv(const char* name);
|
||||
|
||||
UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
|
||||
|
||||
UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
|
||||
|
||||
|
||||
typedef enum {
|
||||
UV_FS_UNKNOWN = -1,
|
||||
@@ -1151,7 +1198,8 @@ typedef enum {
|
||||
UV_FS_CHOWN,
|
||||
UV_FS_FCHOWN,
|
||||
UV_FS_REALPATH,
|
||||
UV_FS_COPYFILE
|
||||
UV_FS_COPYFILE,
|
||||
UV_FS_LCHOWN
|
||||
} uv_fs_type;
|
||||
|
||||
/* uv_fs_t is a subclass of uv_req_t. */
|
||||
@@ -1354,6 +1402,12 @@ UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
enum uv_fs_event {
|
||||
|
||||
@@ -433,5 +433,11 @@
|
||||
# define UV__ENOTTY (-4029)
|
||||
#endif
|
||||
|
||||
#if defined(EFTYPE) && !defined(_WIN32)
|
||||
# define UV__EFTYPE UV__ERR(EFTYPE)
|
||||
#else
|
||||
# define UV__EFTYPE (-4028)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* UV_ERRNO_H_ */
|
||||
@@ -42,34 +42,32 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "uv-threadpool.h"
|
||||
#include "uv/threadpool.h"
|
||||
|
||||
#ifdef CMAKE_BOOTSTRAP
|
||||
# include "uv-posix.h"
|
||||
# include "uv/posix.h"
|
||||
#elif defined(__linux__)
|
||||
# include "uv-linux.h"
|
||||
# include "uv/linux.h"
|
||||
#elif defined (__MVS__)
|
||||
# include "uv-os390.h"
|
||||
# include "uv/os390.h"
|
||||
#elif defined(__PASE__)
|
||||
# include "uv-posix.h"
|
||||
# include "uv/posix.h"
|
||||
#elif defined(_AIX)
|
||||
# include "uv-aix.h"
|
||||
# include "uv/aix.h"
|
||||
#elif defined(__sun)
|
||||
# include "uv-sunos.h"
|
||||
# include "uv/sunos.h"
|
||||
#elif defined(__APPLE__)
|
||||
# include "uv-darwin.h"
|
||||
# include "uv/darwin.h"
|
||||
#elif defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include "uv-bsd.h"
|
||||
# include "uv/bsd.h"
|
||||
#elif defined(__CYGWIN__) || defined(__MSYS__)
|
||||
# include "uv-posix.h"
|
||||
#endif
|
||||
|
||||
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
|
||||
# include "pthread-barrier.h"
|
||||
# include "uv/posix.h"
|
||||
#elif defined(__GNU__)
|
||||
# include "uv/posix.h"
|
||||
#endif
|
||||
|
||||
#ifndef NI_MAXHOST
|
||||
@@ -149,9 +147,30 @@ typedef pthread_rwlock_t uv_rwlock_t;
|
||||
typedef UV_PLATFORM_SEM_T uv_sem_t;
|
||||
typedef pthread_cond_t uv_cond_t;
|
||||
typedef pthread_key_t uv_key_t;
|
||||
|
||||
/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
|
||||
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */
|
||||
struct _uv_barrier {
|
||||
uv_mutex_t mutex;
|
||||
uv_cond_t cond;
|
||||
unsigned threshold;
|
||||
unsigned in;
|
||||
unsigned out;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct _uv_barrier* b;
|
||||
# if defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
/* TODO(bnoordhuis) Remove padding in v2. */
|
||||
char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)];
|
||||
# endif
|
||||
} uv_barrier_t;
|
||||
#else
|
||||
typedef pthread_barrier_t uv_barrier_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Platform-specific definitions for uv_spawn support. */
|
||||
typedef gid_t uv_gid_t;
|
||||
@@ -31,8 +31,8 @@
|
||||
*/
|
||||
|
||||
#define UV_VERSION_MAJOR 1
|
||||
#define UV_VERSION_MINOR 20
|
||||
#define UV_VERSION_PATCH 3
|
||||
#define UV_VERSION_MINOR 24
|
||||
#define UV_VERSION_PATCH 2
|
||||
#define UV_VERSION_IS_RELEASE 0
|
||||
#define UV_VERSION_SUFFIX "dev"
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
# define SSIZE_MAX INTPTR_MAX
|
||||
# define _SSIZE_T_
|
||||
# define _SSIZE_T_DEFINED
|
||||
#endif
|
||||
@@ -53,13 +54,13 @@ typedef struct pollfd {
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "tree.h"
|
||||
#include "uv-threadpool.h"
|
||||
#include "uv/tree.h"
|
||||
#include "uv/threadpool.h"
|
||||
|
||||
#define MAX_PIPENAME_LEN 256
|
||||
|
||||
@@ -86,8 +87,16 @@ typedef struct pollfd {
|
||||
#define SIGKILL 9
|
||||
#define SIGWINCH 28
|
||||
|
||||
/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
|
||||
/* unix-like platforms. However MinGW doesn't define it, so we do. */
|
||||
/* Redefine NSIG to take SIGWINCH into consideration */
|
||||
#if defined(NSIG) && NSIG <= SIGWINCH
|
||||
# undef NSIG
|
||||
#endif
|
||||
#ifndef NSIG
|
||||
# define NSIG SIGWINCH + 1
|
||||
#endif
|
||||
|
||||
/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like
|
||||
* platforms. However MinGW doesn't define it, so we do. */
|
||||
#ifndef SIGABRT_COMPAT
|
||||
# define SIGABRT_COMPAT 6
|
||||
#endif
|
||||
@@ -255,7 +264,7 @@ typedef union {
|
||||
CRITICAL_SECTION waiters_count_lock;
|
||||
HANDLE signal_event;
|
||||
HANDLE broadcast_event;
|
||||
} fallback;
|
||||
} unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
|
||||
} uv_cond_t;
|
||||
|
||||
typedef union {
|
||||
@@ -319,8 +328,6 @@ typedef struct {
|
||||
char* errmsg;
|
||||
} uv_lib_t;
|
||||
|
||||
RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
|
||||
#define UV_LOOP_PRIVATE_FIELDS \
|
||||
/* The loop's I/O completion port */ \
|
||||
HANDLE iocp; \
|
||||
@@ -332,8 +339,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
uv_req_t* pending_reqs_tail; \
|
||||
/* Head of a single-linked list of closed handles */ \
|
||||
uv_handle_t* endgame_handles; \
|
||||
/* The head of the timers tree */ \
|
||||
struct uv_timer_tree_s timers; \
|
||||
/* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */ \
|
||||
void* timer_heap; \
|
||||
/* Lists of active loop (prepare / check / idle) watchers */ \
|
||||
uv_prepare_t* prepare_handles; \
|
||||
uv_check_t* check_handles; \
|
||||
@@ -379,10 +386,10 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
} u; \
|
||||
struct uv_req_s* next_req;
|
||||
|
||||
#define UV_WRITE_PRIVATE_FIELDS \
|
||||
int ipc_header; \
|
||||
uv_buf_t write_buffer; \
|
||||
HANDLE event_handle; \
|
||||
#define UV_WRITE_PRIVATE_FIELDS \
|
||||
int coalesced; \
|
||||
uv_buf_t write_buffer; \
|
||||
HANDLE event_handle; \
|
||||
HANDLE wait_handle;
|
||||
|
||||
#define UV_CONNECT_PRIVATE_FIELDS \
|
||||
@@ -470,16 +477,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
|
||||
#define uv_pipe_connection_fields \
|
||||
uv_timer_t* eof_timer; \
|
||||
uv_write_t ipc_header_write_req; \
|
||||
int ipc_pid; \
|
||||
uint64_t remaining_ipc_rawdata_bytes; \
|
||||
struct { \
|
||||
void* queue[2]; \
|
||||
int queue_len; \
|
||||
} pending_ipc_info; \
|
||||
uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
|
||||
DWORD ipc_remote_pid; \
|
||||
union { \
|
||||
uint32_t payload_remaining; \
|
||||
uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
|
||||
} ipc_data_frame; \
|
||||
void* ipc_xfer_queue[2]; \
|
||||
int ipc_xfer_queue_length; \
|
||||
uv_write_t* non_overlapped_writes_tail; \
|
||||
uv_mutex_t readfile_mutex; \
|
||||
volatile HANDLE readfile_thread;
|
||||
CRITICAL_SECTION readfile_thread_lock; \
|
||||
volatile HANDLE readfile_thread_handle;
|
||||
|
||||
#define UV_PIPE_PRIVATE_FIELDS \
|
||||
HANDLE handle; \
|
||||
@@ -489,8 +497,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
struct { uv_pipe_connection_fields } conn; \
|
||||
} pipe;
|
||||
|
||||
/* TODO: put the parser states in an union - TTY handles are always */
|
||||
/* half-duplex so read-state can safely overlap write-state. */
|
||||
/* TODO: put the parser states in an union - TTY handles are always half-duplex
|
||||
* so read-state can safely overlap write-state. */
|
||||
#define UV_TTY_PRIVATE_FIELDS \
|
||||
HANDLE handle; \
|
||||
union { \
|
||||
@@ -539,8 +547,9 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
unsigned char events;
|
||||
|
||||
#define UV_TIMER_PRIVATE_FIELDS \
|
||||
RB_ENTRY(uv_timer_s) tree_entry; \
|
||||
uint64_t due; \
|
||||
void* heap_node[3]; \
|
||||
int unused; \
|
||||
uint64_t timeout; \
|
||||
uint64_t repeat; \
|
||||
uint64_t start_id; \
|
||||
uv_timer_cb timer_cb;
|
||||
@@ -83,7 +83,7 @@ int uv_fs_poll_start(uv_fs_poll_t* handle,
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
|
||||
ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
|
||||
uv__handle_unref(&ctx->timer_handle);
|
||||
|
||||
err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
|
||||
@@ -248,7 +248,7 @@ static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
|
||||
#include "win/handle-inl.h"
|
||||
|
||||
void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
|
||||
291
Utilities/cmlibuv/src/idna.c
Normal file
291
Utilities/cmlibuv/src/idna.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Derived from https://github.com/bnoordhuis/punycode
|
||||
* but updated to support IDNA 2008.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "idna.h"
|
||||
#include <string.h>
|
||||
|
||||
static unsigned uv__utf8_decode1_slow(const char** p,
|
||||
const char* pe,
|
||||
unsigned a) {
|
||||
unsigned b;
|
||||
unsigned c;
|
||||
unsigned d;
|
||||
unsigned min;
|
||||
|
||||
if (a > 0xF7)
|
||||
return -1;
|
||||
|
||||
switch (*p - pe) {
|
||||
default:
|
||||
if (a > 0xEF) {
|
||||
min = 0x10000;
|
||||
a = a & 7;
|
||||
b = (unsigned char) *(*p)++;
|
||||
c = (unsigned char) *(*p)++;
|
||||
d = (unsigned char) *(*p)++;
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case 2:
|
||||
if (a > 0xDF) {
|
||||
min = 0x800;
|
||||
b = 0x80 | (a & 15);
|
||||
c = (unsigned char) *(*p)++;
|
||||
d = (unsigned char) *(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through. */
|
||||
case 1:
|
||||
if (a > 0xBF) {
|
||||
min = 0x80;
|
||||
b = 0x80;
|
||||
c = 0x80 | (a & 31);
|
||||
d = (unsigned char) *(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
return -1; /* Invalid continuation byte. */
|
||||
}
|
||||
|
||||
if (0x80 != (0xC0 & (b ^ c ^ d)))
|
||||
return -1; /* Invalid sequence. */
|
||||
|
||||
b &= 63;
|
||||
c &= 63;
|
||||
d &= 63;
|
||||
a = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
|
||||
if (a < min)
|
||||
return -1; /* Overlong sequence. */
|
||||
|
||||
if (a > 0x10FFFF)
|
||||
return -1; /* Four-byte sequence > U+10FFFF. */
|
||||
|
||||
if (a >= 0xD800 && a <= 0xDFFF)
|
||||
return -1; /* Surrogate pair. */
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe) {
|
||||
unsigned a;
|
||||
|
||||
a = (unsigned char) *(*p)++;
|
||||
|
||||
if (a < 128)
|
||||
return a; /* ASCII, common case. */
|
||||
|
||||
return uv__utf8_decode1_slow(p, pe, a);
|
||||
}
|
||||
|
||||
#define foreach_codepoint(c, p, pe) \
|
||||
for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
|
||||
|
||||
static int uv__idna_toascii_label(const char* s, const char* se,
|
||||
char** d, char* de) {
|
||||
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const char* ss;
|
||||
unsigned c;
|
||||
unsigned h;
|
||||
unsigned k;
|
||||
unsigned n;
|
||||
unsigned m;
|
||||
unsigned q;
|
||||
unsigned t;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned bias;
|
||||
unsigned delta;
|
||||
unsigned todo;
|
||||
int first;
|
||||
|
||||
h = 0;
|
||||
ss = s;
|
||||
todo = 0;
|
||||
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c < 128)
|
||||
h++;
|
||||
else if (c == (unsigned) -1)
|
||||
return UV_EINVAL;
|
||||
else
|
||||
todo++;
|
||||
}
|
||||
|
||||
if (todo > 0) {
|
||||
if (*d < de) *(*d)++ = 'x';
|
||||
if (*d < de) *(*d)++ = 'n';
|
||||
if (*d < de) *(*d)++ = '-';
|
||||
if (*d < de) *(*d)++ = '-';
|
||||
}
|
||||
|
||||
x = 0;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c > 127)
|
||||
continue;
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = c;
|
||||
|
||||
if (++x == h)
|
||||
break; /* Visited all ASCII characters. */
|
||||
}
|
||||
|
||||
if (todo == 0)
|
||||
return h;
|
||||
|
||||
/* Only write separator when we've written ASCII characters first. */
|
||||
if (h > 0)
|
||||
if (*d < de)
|
||||
*(*d)++ = '-';
|
||||
|
||||
n = 128;
|
||||
bias = 72;
|
||||
delta = 0;
|
||||
first = 1;
|
||||
|
||||
while (todo > 0) {
|
||||
m = -1;
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se)
|
||||
if (c >= n)
|
||||
if (c < m)
|
||||
m = c;
|
||||
|
||||
x = m - n;
|
||||
y = h + 1;
|
||||
|
||||
if (x > ~delta / y)
|
||||
return UV_E2BIG; /* Overflow. */
|
||||
|
||||
delta += x * y;
|
||||
n = m;
|
||||
|
||||
s = ss;
|
||||
foreach_codepoint(c, &s, se) {
|
||||
if (c < n)
|
||||
if (++delta == 0)
|
||||
return UV_E2BIG; /* Overflow. */
|
||||
|
||||
if (c != n)
|
||||
continue;
|
||||
|
||||
for (k = 36, q = delta; /* empty */; k += 36) {
|
||||
t = 1;
|
||||
|
||||
if (k > bias)
|
||||
t = k - bias;
|
||||
|
||||
if (t > 26)
|
||||
t = 26;
|
||||
|
||||
if (q < t)
|
||||
break;
|
||||
|
||||
/* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore
|
||||
* 10 <= y <= 35, we can optimize the long division
|
||||
* into a table-based reciprocal multiplication.
|
||||
*/
|
||||
x = q - t;
|
||||
y = 36 - t; /* 10 <= y <= 35 since 1 <= t <= 26. */
|
||||
q = x / y;
|
||||
t = t + x % y; /* 1 <= t <= 35 because of y. */
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = alphabet[t];
|
||||
}
|
||||
|
||||
if (*d < de)
|
||||
*(*d)++ = alphabet[q];
|
||||
|
||||
delta /= 2;
|
||||
|
||||
if (first) {
|
||||
delta /= 350;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
/* No overflow check is needed because |delta| was just
|
||||
* divided by 2 and |delta+delta >= delta + delta/h|.
|
||||
*/
|
||||
h++;
|
||||
delta += delta / h;
|
||||
|
||||
for (bias = 0; delta > 35 * 26 / 2; bias += 36)
|
||||
delta /= 35;
|
||||
|
||||
bias += 36 * delta / (delta + 38);
|
||||
delta = 0;
|
||||
todo--;
|
||||
}
|
||||
|
||||
delta++;
|
||||
n++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef foreach_codepoint
|
||||
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
|
||||
const char* si;
|
||||
const char* st;
|
||||
unsigned c;
|
||||
char* ds;
|
||||
int rc;
|
||||
|
||||
ds = d;
|
||||
|
||||
for (si = s; si < se; /* empty */) {
|
||||
st = si;
|
||||
c = uv__utf8_decode1(&si, se);
|
||||
|
||||
if (c != '.')
|
||||
if (c != 0x3002) /* 。 */
|
||||
if (c != 0xFF0E) /* . */
|
||||
if (c != 0xFF61) /* 。 */
|
||||
continue;
|
||||
|
||||
rc = uv__idna_toascii_label(s, st, &d, de);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (d < de)
|
||||
*d++ = '.';
|
||||
|
||||
s = si;
|
||||
}
|
||||
|
||||
if (s < se) {
|
||||
rc = uv__idna_toascii_label(s, se, &d, de);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (d < de)
|
||||
*d++ = '\0';
|
||||
|
||||
return d - ds; /* Number of bytes written. */
|
||||
}
|
||||
31
Utilities/cmlibuv/src/idna.h
Normal file
31
Utilities/cmlibuv/src/idna.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef UV_SRC_IDNA_H_
|
||||
#define UV_SRC_IDNA_H_
|
||||
|
||||
/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error.
|
||||
* |p| is updated on success _and_ error, i.e., bad multi-byte sequences are
|
||||
* skipped in their entirety, not just the first bad byte.
|
||||
*/
|
||||
unsigned uv__utf8_decode1(const char** p, const char* pe);
|
||||
|
||||
/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0
|
||||
* is the number of bytes written to |d|, including the trailing nul byte.
|
||||
* A return value < 0 is a libuv error code. |s| and |d| can not overlap.
|
||||
*/
|
||||
long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
|
||||
|
||||
#endif /* UV_SRC_IDNA_H_ */
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
@@ -59,8 +59,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
|
||||
if (l <= 0 || (size_t) l >= size) {
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strncpy(dst, tmp, size);
|
||||
dst[size - 1] = '\0';
|
||||
uv__strscpy(dst, tmp, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -142,14 +141,8 @@ static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
|
||||
if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
|
||||
*tp++ = ':';
|
||||
*tp++ = '\0';
|
||||
|
||||
/*
|
||||
* Check for overflow, copy, and we're done.
|
||||
*/
|
||||
if ((size_t)(tp - tmp) > size) {
|
||||
if (UV_E2BIG == uv__strscpy(dst, tmp, size))
|
||||
return UV_ENOSPC;
|
||||
}
|
||||
strcpy(dst, tmp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
17
Utilities/cmlibuv/src/strscpy.c
Normal file
17
Utilities/cmlibuv/src/strscpy.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "strscpy.h"
|
||||
#include <limits.h> /* SSIZE_MAX */
|
||||
|
||||
ssize_t uv__strscpy(char* d, const char* s, size_t n) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if ('\0' == (d[i] = s[i]))
|
||||
return i > SSIZE_MAX ? UV_E2BIG : (ssize_t) i;
|
||||
|
||||
if (i == 0)
|
||||
return 0;
|
||||
|
||||
d[--i] = '\0';
|
||||
|
||||
return UV_E2BIG;
|
||||
}
|
||||
18
Utilities/cmlibuv/src/strscpy.h
Normal file
18
Utilities/cmlibuv/src/strscpy.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef UV_STRSCPY_H_
|
||||
#define UV_STRSCPY_H_
|
||||
|
||||
/* Include uv.h for its definitions of size_t and ssize_t.
|
||||
* size_t can be obtained directly from <stddef.h> but ssize_t requires
|
||||
* some hoop jumping on Windows that I didn't want to duplicate here.
|
||||
*/
|
||||
#include "uv.h"
|
||||
|
||||
/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
|
||||
* the result, except when |n==0|. Returns the number of bytes copied
|
||||
* or UV_E2BIG if |d| is too small.
|
||||
*
|
||||
* See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html
|
||||
*/
|
||||
ssize_t uv__strscpy(char* d, const char* s, size_t n);
|
||||
|
||||
#endif /* UV_STRSCPY_H_ */
|
||||
@@ -33,12 +33,18 @@ static uv_once_t once = UV_ONCE_INIT;
|
||||
static uv_cond_t cond;
|
||||
static uv_mutex_t mutex;
|
||||
static unsigned int idle_threads;
|
||||
static unsigned int slow_io_work_running;
|
||||
static unsigned int nthreads;
|
||||
static uv_thread_t* threads;
|
||||
static uv_thread_t default_threads[4];
|
||||
static QUEUE exit_message;
|
||||
static QUEUE wq;
|
||||
static QUEUE run_slow_work_message;
|
||||
static QUEUE slow_io_pending_wq;
|
||||
|
||||
static unsigned int slow_work_thread_threshold(void) {
|
||||
return (nthreads + 1) / 2;
|
||||
}
|
||||
|
||||
static void uv__cancelled(struct uv__work* w) {
|
||||
abort();
|
||||
@@ -51,34 +57,67 @@ static void uv__cancelled(struct uv__work* w) {
|
||||
static void worker(void* arg) {
|
||||
struct uv__work* w;
|
||||
QUEUE* q;
|
||||
int is_slow_work;
|
||||
|
||||
uv_sem_post((uv_sem_t*) arg);
|
||||
arg = NULL;
|
||||
|
||||
uv_mutex_lock(&mutex);
|
||||
for (;;) {
|
||||
uv_mutex_lock(&mutex);
|
||||
/* `mutex` should always be locked at this point. */
|
||||
|
||||
while (QUEUE_EMPTY(&wq)) {
|
||||
/* Keep waiting while either no work is present or only slow I/O
|
||||
and we're at the threshold for that. */
|
||||
while (QUEUE_EMPTY(&wq) ||
|
||||
(QUEUE_HEAD(&wq) == &run_slow_work_message &&
|
||||
QUEUE_NEXT(&run_slow_work_message) == &wq &&
|
||||
slow_io_work_running >= slow_work_thread_threshold())) {
|
||||
idle_threads += 1;
|
||||
uv_cond_wait(&cond, &mutex);
|
||||
idle_threads -= 1;
|
||||
}
|
||||
|
||||
q = QUEUE_HEAD(&wq);
|
||||
|
||||
if (q == &exit_message)
|
||||
if (q == &exit_message) {
|
||||
uv_cond_signal(&cond);
|
||||
else {
|
||||
uv_mutex_unlock(&mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
|
||||
|
||||
is_slow_work = 0;
|
||||
if (q == &run_slow_work_message) {
|
||||
/* If we're at the slow I/O threshold, re-schedule until after all
|
||||
other work in the queue is done. */
|
||||
if (slow_io_work_running >= slow_work_thread_threshold()) {
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we encountered a request to run slow I/O work but there is none
|
||||
to run, that means it's cancelled => Start over. */
|
||||
if (QUEUE_EMPTY(&slow_io_pending_wq))
|
||||
continue;
|
||||
|
||||
is_slow_work = 1;
|
||||
slow_io_work_running++;
|
||||
|
||||
q = QUEUE_HEAD(&slow_io_pending_wq);
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
|
||||
executing. */
|
||||
QUEUE_INIT(q);
|
||||
|
||||
/* If there is more slow I/O work, schedule it to be run as well. */
|
||||
if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
|
||||
QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
}
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&mutex);
|
||||
|
||||
if (q == &exit_message)
|
||||
break;
|
||||
|
||||
w = QUEUE_DATA(q, struct uv__work, wq);
|
||||
w->work(w);
|
||||
|
||||
@@ -88,12 +127,32 @@ static void worker(void* arg) {
|
||||
QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
|
||||
uv_async_send(&w->loop->wq_async);
|
||||
uv_mutex_unlock(&w->loop->wq_mutex);
|
||||
|
||||
/* Lock `mutex` since that is expected at the start of the next
|
||||
* iteration. */
|
||||
uv_mutex_lock(&mutex);
|
||||
if (is_slow_work) {
|
||||
/* `slow_io_work_running` is protected by `mutex`. */
|
||||
slow_io_work_running--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void post(QUEUE* q) {
|
||||
static void post(QUEUE* q, enum uv__work_kind kind) {
|
||||
uv_mutex_lock(&mutex);
|
||||
if (kind == UV__WORK_SLOW_IO) {
|
||||
/* Insert into a separate queue. */
|
||||
QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
|
||||
if (!QUEUE_EMPTY(&run_slow_work_message)) {
|
||||
/* Running slow I/O tasks is already scheduled => Nothing to do here.
|
||||
The worker that runs said other task will schedule this one as well. */
|
||||
uv_mutex_unlock(&mutex);
|
||||
return;
|
||||
}
|
||||
q = &run_slow_work_message;
|
||||
}
|
||||
|
||||
QUEUE_INSERT_TAIL(&wq, q);
|
||||
if (idle_threads > 0)
|
||||
uv_cond_signal(&cond);
|
||||
@@ -108,7 +167,7 @@ UV_DESTRUCTOR(static void cleanup(void)) {
|
||||
if (nthreads == 0)
|
||||
return;
|
||||
|
||||
post(&exit_message);
|
||||
post(&exit_message, UV__WORK_CPU);
|
||||
|
||||
for (i = 0; i < nthreads; i++)
|
||||
if (uv_thread_join(threads + i))
|
||||
@@ -156,6 +215,8 @@ static void init_threads(void) {
|
||||
abort();
|
||||
|
||||
QUEUE_INIT(&wq);
|
||||
QUEUE_INIT(&slow_io_pending_wq);
|
||||
QUEUE_INIT(&run_slow_work_message);
|
||||
|
||||
if (uv_sem_init(&sem, 0))
|
||||
abort();
|
||||
@@ -194,13 +255,14 @@ static void init_once(void) {
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work* w,
|
||||
enum uv__work_kind kind,
|
||||
void (*work)(struct uv__work* w),
|
||||
void (*done)(struct uv__work* w, int status)) {
|
||||
uv_once(&once, init_once);
|
||||
w->loop = loop;
|
||||
w->work = work;
|
||||
w->done = done;
|
||||
post(&w->wq);
|
||||
post(&w->wq, kind);
|
||||
}
|
||||
|
||||
|
||||
@@ -284,7 +346,11 @@ int uv_queue_work(uv_loop_t* loop,
|
||||
req->loop = loop;
|
||||
req->work_cb = work_cb;
|
||||
req->after_work_cb = after_work_cb;
|
||||
uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_CPU,
|
||||
uv__queue_work,
|
||||
uv__queue_done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,13 +19,22 @@
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "uv-common.h"
|
||||
#include "heap-inl.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
static struct heap *timer_heap(const uv_loop_t* loop) {
|
||||
#ifdef _WIN32
|
||||
return (struct heap*) loop->timer_heap;
|
||||
#else
|
||||
return (struct heap*) &loop->timer_heap;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int timer_less_than(const struct heap_node* ha,
|
||||
const struct heap_node* hb) {
|
||||
const uv_timer_t* a;
|
||||
@@ -81,7 +90,7 @@ int uv_timer_start(uv_timer_t* handle,
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
heap_insert((struct heap*) &handle->loop->timer_heap,
|
||||
heap_insert(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_start(handle);
|
||||
@@ -94,7 +103,7 @@ int uv_timer_stop(uv_timer_t* handle) {
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
heap_remove((struct heap*) &handle->loop->timer_heap,
|
||||
heap_remove(timer_heap(handle->loop),
|
||||
(struct heap_node*) &handle->heap_node,
|
||||
timer_less_than);
|
||||
uv__handle_stop(handle);
|
||||
@@ -131,7 +140,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
const uv_timer_t* handle;
|
||||
uint64_t diff;
|
||||
|
||||
heap_node = heap_min((const struct heap*) &loop->timer_heap);
|
||||
heap_node = heap_min(timer_heap(loop));
|
||||
if (heap_node == NULL)
|
||||
return -1; /* block indefinitely */
|
||||
|
||||
@@ -143,7 +152,7 @@ int uv__next_timeout(const uv_loop_t* loop) {
|
||||
if (diff > INT_MAX)
|
||||
diff = INT_MAX;
|
||||
|
||||
return diff;
|
||||
return (int) diff;
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +161,7 @@ void uv__run_timers(uv_loop_t* loop) {
|
||||
uv_timer_t* handle;
|
||||
|
||||
for (;;) {
|
||||
heap_node = heap_min((struct heap*) &loop->timer_heap);
|
||||
heap_node = heap_min(timer_heap(loop));
|
||||
if (heap_node == NULL)
|
||||
break;
|
||||
|
||||
@@ -166,8 +166,7 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
int sockfd, inet6, size = 1;
|
||||
struct ifconf ifc;
|
||||
@@ -175,6 +174,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
struct sockaddr_dl* sa_addr;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
|
||||
return UV__ERR(errno);
|
||||
@@ -217,6 +217,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
|
||||
if (!(*addresses)) {
|
||||
@@ -290,3 +295,4 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses,
|
||||
|
||||
uv__free(addresses);
|
||||
}
|
||||
|
||||
|
||||
@@ -358,19 +358,15 @@ void uv_loadavg(double avg[3]) {
|
||||
|
||||
|
||||
#ifdef HAVE_SYS_AHAFS_EVPRODS_H
|
||||
static char *uv__rawname(char *cp) {
|
||||
static char rawbuf[FILENAME_MAX+1];
|
||||
char *dp = rindex(cp, '/');
|
||||
static char* uv__rawname(const char* cp, char (*dst)[FILENAME_MAX+1]) {
|
||||
char* dp;
|
||||
|
||||
dp = rindex(cp, '/');
|
||||
if (dp == 0)
|
||||
return 0;
|
||||
|
||||
*dp = 0;
|
||||
strcpy(rawbuf, cp);
|
||||
*dp = '/';
|
||||
strcat(rawbuf, "/r");
|
||||
strcat(rawbuf, dp+1);
|
||||
return rawbuf;
|
||||
snprintf(*dst, sizeof(*dst), "%.*s/r%s", (int) (dp - cp), cp, dp + 1);
|
||||
return *dst;
|
||||
}
|
||||
|
||||
|
||||
@@ -399,6 +395,7 @@ static int uv__path_is_a_directory(char* filename) {
|
||||
* Returns 0 if AHAFS is mounted, or an error code < 0 on failure
|
||||
*/
|
||||
static int uv__is_ahafs_mounted(void){
|
||||
char rawbuf[FILENAME_MAX+1];
|
||||
int rv, i = 2;
|
||||
struct vmount *p;
|
||||
int size_multiplier = 10;
|
||||
@@ -432,7 +429,7 @@ static int uv__is_ahafs_mounted(void){
|
||||
obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
|
||||
stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
|
||||
|
||||
if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
|
||||
if (EQ(obj, dev) || EQ(uv__rawname(obj, &rawbuf), dev) || EQ(stub, dev)) {
|
||||
uv__free(p); /* Found a match */
|
||||
return 0;
|
||||
}
|
||||
@@ -453,7 +450,8 @@ static int uv__makedir_p(const char *dir) {
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
snprintf(tmp, sizeof(tmp),"%s",dir);
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(tmp, dir, sizeof(tmp));
|
||||
len = strlen(tmp);
|
||||
if (tmp[len - 1] == '/')
|
||||
tmp[len - 1] = 0;
|
||||
@@ -557,7 +555,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) {
|
||||
sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
|
||||
|
||||
rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
|
||||
if (rc < 0)
|
||||
if (rc < 0 && errno != EBUSY)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
@@ -702,9 +700,9 @@ static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int
|
||||
else
|
||||
p++;
|
||||
}
|
||||
strncpy(fname, p, sizeof(fname) - 1);
|
||||
/* Just in case */
|
||||
fname[sizeof(fname) - 1] = '\0';
|
||||
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(fname, p, sizeof(fname));
|
||||
|
||||
handle->cb(handle, fname, events, 0);
|
||||
}
|
||||
@@ -730,12 +728,19 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
char cwd[PATH_MAX];
|
||||
char absolute_path[PATH_MAX];
|
||||
char readlink_cwd[PATH_MAX];
|
||||
struct timeval zt;
|
||||
fd_set pollfd;
|
||||
|
||||
|
||||
/* Figure out whether filename is absolute or not */
|
||||
if (filename[0] == '/') {
|
||||
if (filename[0] == '\0') {
|
||||
/* Missing a pathname */
|
||||
return UV_ENOENT;
|
||||
}
|
||||
else if (filename[0] == '/') {
|
||||
/* We have absolute pathname */
|
||||
snprintf(absolute_path, sizeof(absolute_path), "%s", filename);
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(absolute_path, filename, sizeof(absolute_path));
|
||||
} else {
|
||||
/* We have a relative pathname, compose the absolute pathname */
|
||||
snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
|
||||
@@ -769,6 +774,15 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
|
||||
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
|
||||
|
||||
/* AHAFS wants someone to poll for it to start mointoring.
|
||||
* so kick-start it so that we don't miss an event in the
|
||||
* eventuality of an event that occurs in the current loop. */
|
||||
do {
|
||||
memset(&zt, 0, sizeof(zt));
|
||||
FD_ZERO(&pollfd);
|
||||
FD_SET(fd, &pollfd);
|
||||
rc = select(fd + 1, &pollfd, NULL, NULL, &zt);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
return 0;
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
@@ -886,16 +900,20 @@ int uv_set_process_title(const char* title) {
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
len = strlen(process_argv[0]);
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
else if (size <= len)
|
||||
return UV_ENOBUFS;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
memcpy(buffer, process_argv[0], len + 1);
|
||||
len = strlen(process_argv[0]);
|
||||
if (size <= len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_argv[0], len);
|
||||
buffer[len] = '\0';
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
@@ -982,7 +1000,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
strcpy(cpu_id.name, FIRST_CPU);
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(cpu_id.name, FIRST_CPU, sizeof(cpu_id.name));
|
||||
result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
|
||||
if (result == -1) {
|
||||
uv__free(ps_cpus);
|
||||
|
||||
@@ -23,7 +23,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "android-ifaddrs.h"
|
||||
#include "uv/android-ifaddrs.h"
|
||||
#include "uv-common.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@@ -52,13 +52,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
*/
|
||||
if (ent->ifa_addr->sa_family == AF_LINK)
|
||||
return 1;
|
||||
#elif defined(__NetBSD__)
|
||||
#elif defined(__NetBSD__) || defined(__OpenBSD__)
|
||||
if (ent->ifa_addr->sa_family != PF_INET &&
|
||||
ent->ifa_addr->sa_family != PF_INET6)
|
||||
return 1;
|
||||
#elif defined(__OpenBSD__)
|
||||
if (ent->ifa_addr->sa_family != PF_INET)
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -69,11 +66,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
uv_interface_address_t* address;
|
||||
int i;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
@@ -81,6 +79,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
|
||||
if (*addresses == NULL) {
|
||||
@@ -121,15 +124,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address = *addresses;
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
#if defined(__CYGWIN__) || defined(__MSYS__)
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
#else
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
struct sockaddr_dl* sa_addr;
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
#endif
|
||||
} else {
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
}
|
||||
#endif
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
93
Utilities/cmlibuv/src/unix/bsd-proctitle.c
Normal file
93
Utilities/cmlibuv/src/unix/bsd-proctitle.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Copyright libuv project contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char* process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
if (uv_mutex_init(&process_title_mutex))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc > 0 ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
if (new_title == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title != NULL) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <sys/resource.h> /* getrusage */
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifdef __sun
|
||||
# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
|
||||
@@ -119,7 +120,7 @@ uint64_t uv_hrtime(void) {
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
assert(!uv__is_closing(handle));
|
||||
|
||||
handle->flags |= UV_CLOSING;
|
||||
handle->flags |= UV_HANDLE_CLOSING;
|
||||
handle->close_cb = close_cb;
|
||||
|
||||
switch (handle->type) {
|
||||
@@ -177,8 +178,8 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
|
||||
|
||||
case UV_SIGNAL:
|
||||
uv__signal_close((uv_signal_t*) handle);
|
||||
/* Signal handles may not be closed immediately. The signal code will */
|
||||
/* itself close uv__make_close_pending whenever appropriate. */
|
||||
/* Signal handles may not be closed immediately. The signal code will
|
||||
* itself close uv__make_close_pending whenever appropriate. */
|
||||
return;
|
||||
|
||||
default:
|
||||
@@ -217,8 +218,8 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
|
||||
}
|
||||
|
||||
void uv__make_close_pending(uv_handle_t* handle) {
|
||||
assert(handle->flags & UV_CLOSING);
|
||||
assert(!(handle->flags & UV_CLOSED));
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->next_closing = handle->loop->closing_handles;
|
||||
handle->loop->closing_handles = handle;
|
||||
}
|
||||
@@ -244,15 +245,17 @@ int uv__getiovmax(void) {
|
||||
|
||||
|
||||
static void uv__finish_close(uv_handle_t* handle) {
|
||||
/* Note: while the handle is in the UV_CLOSING state now, it's still possible
|
||||
* for it to be active in the sense that uv__is_active() returns true.
|
||||
/* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
|
||||
* possible for it to be active in the sense that uv__is_active() returns
|
||||
* true.
|
||||
*
|
||||
* A good example is when the user calls uv_shutdown(), immediately followed
|
||||
* by uv_close(). The handle is considered active at this point because the
|
||||
* completion of the shutdown req is still pending.
|
||||
*/
|
||||
assert(handle->flags & UV_CLOSING);
|
||||
assert(!(handle->flags & UV_CLOSED));
|
||||
handle->flags |= UV_CLOSED;
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
|
||||
switch (handle->type) {
|
||||
case UV_PREPARE:
|
||||
@@ -637,27 +640,6 @@ int uv__cloexec_fcntl(int fd, int set) {
|
||||
}
|
||||
|
||||
|
||||
/* This function is not execve-safe, there is a race window
|
||||
* between the call to dup() and fcntl(FD_CLOEXEC).
|
||||
*/
|
||||
int uv__dup(int fd) {
|
||||
int err;
|
||||
|
||||
fd = dup(fd);
|
||||
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
err = uv__cloexec(fd, 1);
|
||||
if (err) {
|
||||
uv__close(fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
|
||||
struct cmsghdr* cmsg;
|
||||
ssize_t rc;
|
||||
@@ -930,6 +912,11 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
|
||||
}
|
||||
|
||||
|
||||
int uv__fd_exists(uv_loop_t* loop, int fd) {
|
||||
return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
|
||||
}
|
||||
|
||||
|
||||
int uv_getrusage(uv_rusage_t* rusage) {
|
||||
struct rusage usage;
|
||||
|
||||
@@ -1343,6 +1330,9 @@ uv_os_fd_t uv_get_osfhandle(int fd) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
int uv_open_osfhandle(uv_os_fd_t os_fd) {
|
||||
return os_fd;
|
||||
}
|
||||
|
||||
uv_pid_t uv_os_getpid(void) {
|
||||
return getpid();
|
||||
@@ -1352,3 +1342,87 @@ uv_pid_t uv_os_getpid(void) {
|
||||
uv_pid_t uv_os_getppid(void) {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getpriority(uv_pid_t pid, int* priority) {
|
||||
int r;
|
||||
|
||||
if (priority == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
errno = 0;
|
||||
r = getpriority(PRIO_PROCESS, (int) pid);
|
||||
|
||||
if (r == -1 && errno != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
*priority = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
|
||||
return UV__ERR(errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
struct utsname buf;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uname(&buf) == -1) {
|
||||
r = UV__ERR(errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#ifdef _AIX
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%s.%s",
|
||||
buf.version,
|
||||
buf.release);
|
||||
if (r >= sizeof(buffer->release)) {
|
||||
r = UV_E2BIG;
|
||||
goto error;
|
||||
}
|
||||
#else
|
||||
r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
#if defined(_AIX) || defined(__PASE__)
|
||||
r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
|
||||
#else
|
||||
r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
|
||||
#endif
|
||||
|
||||
if (r == UV_E2BIG)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ int uv_uptime(double* uptime) {
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
/* FIXME: read /proc/meminfo? */
|
||||
*rss = 0;
|
||||
return UV_ENOSYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
|
||||
|
||||
@@ -33,61 +33,56 @@
|
||||
# include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
static int uv__pthread_setname_np(const char* name) {
|
||||
int (*dynamic_pthread_setname_np)(const char* name);
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
int err;
|
||||
|
||||
static int (*dynamic_pthread_setname_np)(const char* name);
|
||||
#if !TARGET_OS_IPHONE
|
||||
static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
static CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
static OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
static void* application_services_handle;
|
||||
static void* core_foundation_handle;
|
||||
static CFBundleRef launch_services_bundle;
|
||||
static CFStringRef* display_name_key;
|
||||
static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
static CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
static CFBundleRef hi_services_bundle;
|
||||
static OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
|
||||
if (core_foundation_handle != NULL) {
|
||||
dlclose(core_foundation_handle);
|
||||
core_foundation_handle = NULL;
|
||||
}
|
||||
|
||||
if (application_services_handle != NULL) {
|
||||
dlclose(application_services_handle);
|
||||
application_services_handle = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
|
||||
void uv__set_process_title_platform_init(void) {
|
||||
/* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
|
||||
*(void **)(&dynamic_pthread_setname_np) =
|
||||
dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||
|
||||
if (dynamic_pthread_setname_np == NULL)
|
||||
return UV_ENOSYS;
|
||||
|
||||
strncpy(namebuf, name, sizeof(namebuf) - 1);
|
||||
namebuf[sizeof(namebuf) - 1] = '\0';
|
||||
|
||||
err = dynamic_pthread_setname_np(namebuf);
|
||||
if (err)
|
||||
return UV__ERR(err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__set_process_title(const char* title) {
|
||||
#if TARGET_OS_IPHONE
|
||||
return uv__pthread_setname_np(title);
|
||||
#else
|
||||
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
|
||||
const char*,
|
||||
CFStringEncoding);
|
||||
CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
|
||||
void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
|
||||
void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
|
||||
CFTypeRef (*pLSGetCurrentApplicationASN)(void);
|
||||
OSStatus (*pLSSetApplicationInformationItem)(int,
|
||||
CFTypeRef,
|
||||
CFStringRef,
|
||||
CFStringRef,
|
||||
CFDictionaryRef*);
|
||||
void* application_services_handle;
|
||||
void* core_foundation_handle;
|
||||
CFBundleRef launch_services_bundle;
|
||||
CFStringRef* display_name_key;
|
||||
CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
|
||||
CFBundleRef (*pCFBundleGetMainBundle)(void);
|
||||
CFBundleRef hi_services_bundle;
|
||||
OSStatus (*pSetApplicationIsDaemon)(int);
|
||||
CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
|
||||
void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
|
||||
void*);
|
||||
CFTypeRef asn;
|
||||
int err;
|
||||
|
||||
err = UV_ENOENT;
|
||||
#if !TARGET_OS_IPHONE
|
||||
application_services_handle = dlopen("/System/Library/Frameworks/"
|
||||
"ApplicationServices.framework/"
|
||||
"Versions/A/ApplicationServices",
|
||||
@@ -116,8 +111,6 @@ int uv__set_process_title(const char* title) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
|
||||
|
||||
launch_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
|
||||
|
||||
@@ -148,13 +141,14 @@ int uv__set_process_title(const char* title) {
|
||||
"CFBundleGetInfoDictionary");
|
||||
*(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
|
||||
"CFBundleGetMainBundle");
|
||||
|
||||
if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
|
||||
goto out;
|
||||
|
||||
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
|
||||
hi_services_bundle =
|
||||
pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
|
||||
err = UV_ENOENT;
|
||||
|
||||
if (hi_services_bundle == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -168,42 +162,37 @@ int uv__set_process_title(const char* title) {
|
||||
pCFBundleGetFunctionPointerForName(
|
||||
launch_services_bundle,
|
||||
S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
|
||||
|
||||
if (pSetApplicationIsDaemon == NULL ||
|
||||
pLSApplicationCheckIn == NULL ||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pSetApplicationIsDaemon(1) != noErr)
|
||||
goto out;
|
||||
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
|
||||
/* Check into process manager?! */
|
||||
pLSApplicationCheckIn(-2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
|
||||
err = UV_EINVAL;
|
||||
if (pLSSetApplicationInformationItem(-2, /* Magic value. */
|
||||
asn,
|
||||
*display_name_key,
|
||||
S(title),
|
||||
NULL) != noErr) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uv__pthread_setname_np(title); /* Don't care if it fails. */
|
||||
err = 0;
|
||||
return;
|
||||
|
||||
out:
|
||||
if (core_foundation_handle != NULL)
|
||||
dlclose(core_foundation_handle);
|
||||
|
||||
if (application_services_handle != NULL)
|
||||
dlclose(application_services_handle);
|
||||
|
||||
return err;
|
||||
uv__set_process_title_platform_fini();
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
}
|
||||
|
||||
|
||||
void uv__set_process_title(const char* title) {
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) {
|
||||
CFTypeRef asn;
|
||||
pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
|
||||
pLSApplicationCheckIn(/* Magic value */ -2,
|
||||
pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
|
||||
asn = pLSGetCurrentApplicationASN();
|
||||
pLSSetApplicationInformationItem(/* Magic value */ -2, asn,
|
||||
*display_name_key, S(title), NULL);
|
||||
}
|
||||
#endif /* !TARGET_OS_IPHONE */
|
||||
|
||||
if (dynamic_pthread_setname_np != NULL) {
|
||||
char namebuf[64]; /* MAXTHREADNAMESIZE */
|
||||
uv__strscpy(namebuf, title, sizeof(namebuf));
|
||||
dynamic_pthread_setname_np(namebuf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,15 +47,6 @@
|
||||
# define CP_INTR 4
|
||||
#endif
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
@@ -159,76 +150,6 @@ void uv_loadavg(double avg[3]) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
int oid[4];
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
|
||||
oid[0] = CTL_KERN;
|
||||
oid[1] = KERN_PROC;
|
||||
oid[2] = KERN_PROC_ARGS;
|
||||
oid[3] = getpid();
|
||||
|
||||
sysctl(oid,
|
||||
ARRAY_SIZE(oid),
|
||||
NULL,
|
||||
NULL,
|
||||
process_title,
|
||||
strlen(process_title) + 1);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size;
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
#include <poll.h>
|
||||
|
||||
#if defined(__DragonFly__) || \
|
||||
@@ -62,11 +61,20 @@
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <copyfile.h>
|
||||
# include <sys/sysctl.h>
|
||||
#elif defined(__linux__) && !defined(FICLONE)
|
||||
# include <sys/ioctl.h>
|
||||
# define FICLONE _IOW(0x94, 9, int)
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && !defined(_AIX71)
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
|
||||
#define INIT(subtype) \
|
||||
do { \
|
||||
if (req == NULL) \
|
||||
@@ -120,7 +128,11 @@
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
uv__fs_work, \
|
||||
uv__fs_done); \
|
||||
return 0; \
|
||||
} \
|
||||
else { \
|
||||
@@ -143,7 +155,7 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) {
|
||||
int r;
|
||||
|
||||
r = fcntl(req->file, F_FULLFSYNC);
|
||||
if (r != 0 && errno == ENOTTY)
|
||||
if (r != 0)
|
||||
r = fsync(req->file);
|
||||
return r;
|
||||
#else
|
||||
@@ -165,59 +177,17 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_futime(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
static int no_utimesat;
|
||||
struct timespec ts[2];
|
||||
struct timeval tv[2];
|
||||
char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
|
||||
int r;
|
||||
|
||||
if (no_utimesat)
|
||||
goto skip;
|
||||
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
|
||||
r = uv__utimesat(req->file, NULL, ts, 0);
|
||||
if (r == 0)
|
||||
return r;
|
||||
|
||||
if (errno != ENOSYS)
|
||||
return r;
|
||||
|
||||
no_utimesat = 1;
|
||||
|
||||
skip:
|
||||
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
|
||||
|
||||
r = utimes(path, tv);
|
||||
if (r == 0)
|
||||
return r;
|
||||
|
||||
switch (errno) {
|
||||
case ENOENT:
|
||||
if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
|
||||
break;
|
||||
/* Fall through. */
|
||||
|
||||
case EACCES:
|
||||
case ENOTDIR:
|
||||
errno = ENOSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
@@ -235,13 +205,6 @@ skip:
|
||||
# else
|
||||
return futimes(req->file, tv);
|
||||
# endif
|
||||
#elif defined(_AIX71)
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
return futimens(req->file, ts);
|
||||
#elif defined(__MVS__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
@@ -314,17 +277,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
#if defined(__linux__)
|
||||
static int no_preadv;
|
||||
#endif
|
||||
unsigned int iovmax;
|
||||
ssize_t result;
|
||||
|
||||
#if defined(_AIX)
|
||||
struct stat buf;
|
||||
if(fstat(req->file, &buf))
|
||||
return -1;
|
||||
if(S_ISDIR(buf.st_mode)) {
|
||||
errno = EISDIR;
|
||||
return -1;
|
||||
}
|
||||
#endif /* defined(_AIX) */
|
||||
iovmax = uv__getiovmax();
|
||||
if (req->nbufs > iovmax)
|
||||
req->nbufs = iovmax;
|
||||
|
||||
if (req->off < 0) {
|
||||
if (req->nbufs == 1)
|
||||
result = read(req->file, req->bufs[0].base, req->bufs[0].len);
|
||||
@@ -343,25 +302,7 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
if (no_preadv) retry:
|
||||
# endif
|
||||
{
|
||||
off_t nread;
|
||||
size_t index;
|
||||
|
||||
nread = 0;
|
||||
index = 0;
|
||||
result = 1;
|
||||
do {
|
||||
if (req->bufs[index].len > 0) {
|
||||
result = pread(req->file,
|
||||
req->bufs[index].base,
|
||||
req->bufs[index].len,
|
||||
req->off + nread);
|
||||
if (result > 0)
|
||||
nread += result;
|
||||
}
|
||||
index++;
|
||||
} while (index < req->nbufs && result > 0);
|
||||
if (nread > 0)
|
||||
result = nread;
|
||||
result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
@@ -379,6 +320,13 @@ static ssize_t uv__fs_read(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
done:
|
||||
/* Early cleanup of bufs allocation, since we're done with it. */
|
||||
if (req->bufs != req->bufsml)
|
||||
uv__free(req->bufs);
|
||||
|
||||
req->bufs = NULL;
|
||||
req->nbufs = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -446,8 +394,10 @@ static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
ssize_t maxlen;
|
||||
ssize_t len;
|
||||
char* buf;
|
||||
char* newbuf;
|
||||
|
||||
#if defined(UV__FS_PATH_MAX_FALLBACK)
|
||||
/* We may not have a real PATH_MAX. Read size of link. */
|
||||
@@ -461,17 +411,17 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = st.st_size;
|
||||
maxlen = st.st_size;
|
||||
|
||||
/* According to readlink(2) lstat can report st_size == 0
|
||||
for some symlinks, such as those in /proc or /sys. */
|
||||
if (len == 0)
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
if (maxlen == 0)
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#else
|
||||
len = uv__fs_pathmax_size(req->path);
|
||||
maxlen = uv__fs_pathmax_size(req->path);
|
||||
#endif
|
||||
|
||||
buf = uv__malloc(len + 1);
|
||||
buf = uv__malloc(maxlen);
|
||||
|
||||
if (buf == NULL) {
|
||||
errno = ENOMEM;
|
||||
@@ -479,17 +429,28 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
#if defined(__MVS__)
|
||||
len = os390_readlink(req->path, buf, len);
|
||||
len = os390_readlink(req->path, buf, maxlen);
|
||||
#else
|
||||
len = readlink(req->path, buf, len);
|
||||
len = readlink(req->path, buf, maxlen);
|
||||
#endif
|
||||
|
||||
|
||||
if (len == -1) {
|
||||
uv__free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Uncommon case: resize to make room for the trailing nul byte. */
|
||||
if (len == maxlen) {
|
||||
newbuf = uv__realloc(buf, len + 1);
|
||||
|
||||
if (newbuf == NULL) {
|
||||
uv__free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf = newbuf;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
req->ptr = buf;
|
||||
|
||||
@@ -739,10 +700,48 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) {
|
||||
|
||||
|
||||
static ssize_t uv__fs_utime(uv_fs_t* req) {
|
||||
#if defined(__linux__) \
|
||||
|| defined(_AIX71) \
|
||||
|| defined(__sun)
|
||||
/* utimesat() has nanosecond resolution but we stick to microseconds
|
||||
* for the sake of consistency with other platforms.
|
||||
*/
|
||||
struct timespec ts[2];
|
||||
ts[0].tv_sec = req->atime;
|
||||
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
|
||||
ts[1].tv_sec = req->mtime;
|
||||
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
|
||||
return utimensat(AT_FDCWD, req->path, ts, 0);
|
||||
#elif defined(__APPLE__) \
|
||||
|| defined(__DragonFly__) \
|
||||
|| defined(__FreeBSD__) \
|
||||
|| defined(__FreeBSD_kernel__) \
|
||||
|| defined(__NetBSD__) \
|
||||
|| defined(__OpenBSD__)
|
||||
struct timeval tv[2];
|
||||
tv[0].tv_sec = req->atime;
|
||||
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
|
||||
tv[1].tv_sec = req->mtime;
|
||||
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
|
||||
return utimes(req->path, tv);
|
||||
#elif defined(_AIX) \
|
||||
&& !defined(_AIX71)
|
||||
struct utimbuf buf;
|
||||
buf.actime = req->atime;
|
||||
buf.modtime = req->mtime;
|
||||
return utime(req->path, &buf); /* TODO use utimes() where available */
|
||||
return utime(req->path, &buf);
|
||||
#elif defined(__MVS__)
|
||||
attrib_t atr;
|
||||
memset(&atr, 0, sizeof(atr));
|
||||
atr.att_mtimechg = 1;
|
||||
atr.att_atimechg = 1;
|
||||
atr.att_mtime = req->mtime;
|
||||
atr.att_atime = req->atime;
|
||||
return __lchattr((char*) req->path, &atr, sizeof(atr));
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -780,25 +779,7 @@ static ssize_t uv__fs_write(uv_fs_t* req) {
|
||||
if (no_pwritev) retry:
|
||||
# endif
|
||||
{
|
||||
off_t written;
|
||||
size_t index;
|
||||
|
||||
written = 0;
|
||||
index = 0;
|
||||
r = 0;
|
||||
do {
|
||||
if (req->bufs[index].len > 0) {
|
||||
r = pwrite(req->file,
|
||||
req->bufs[index].base,
|
||||
req->bufs[index].len,
|
||||
req->off + written);
|
||||
if (r > 0)
|
||||
written += r;
|
||||
}
|
||||
index++;
|
||||
} while (index < req->nbufs && r >= 0);
|
||||
if (written > 0)
|
||||
r = written;
|
||||
r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
|
||||
}
|
||||
# if defined(__linux__)
|
||||
else {
|
||||
@@ -827,26 +808,41 @@ done:
|
||||
static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
#if defined(__APPLE__) && !TARGET_OS_IPHONE
|
||||
/* On macOS, use the native copyfile(3). */
|
||||
static int can_clone;
|
||||
copyfile_flags_t flags;
|
||||
char buf[64];
|
||||
size_t len;
|
||||
int major;
|
||||
|
||||
flags = COPYFILE_ALL;
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_EXCL)
|
||||
flags |= COPYFILE_EXCL;
|
||||
|
||||
#ifdef COPYFILE_CLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE)
|
||||
flags |= COPYFILE_CLONE;
|
||||
#endif
|
||||
|
||||
/* Check OS version. Cloning is only supported on macOS >= 10.12. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
#ifdef COPYFILE_CLONE_FORCE
|
||||
flags |= COPYFILE_CLONE_FORCE;
|
||||
#else
|
||||
return UV_ENOSYS;
|
||||
#endif
|
||||
if (can_clone == 0) {
|
||||
len = sizeof(buf);
|
||||
if (sysctlbyname("kern.osrelease", buf, &len, NULL, 0))
|
||||
return UV__ERR(errno);
|
||||
|
||||
if (1 != sscanf(buf, "%d", &major))
|
||||
abort();
|
||||
|
||||
can_clone = -1 + 2 * (major >= 16); /* macOS >= 10.12 */
|
||||
}
|
||||
|
||||
if (can_clone < 0)
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
|
||||
/* copyfile() simply ignores COPYFILE_CLONE if it's not supported. */
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE)
|
||||
flags |= 1 << 24; /* COPYFILE_CLONE */
|
||||
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE)
|
||||
flags |= 1 << 25; /* COPYFILE_CLONE_FORCE */
|
||||
|
||||
return copyfile(req->path, req->new_path, NULL, flags);
|
||||
#else
|
||||
uv_fs_t fs_req;
|
||||
@@ -906,9 +902,11 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
/* If an error occurred that the sendfile fallback also won't handle, or
|
||||
this is a force clone then exit. Otherwise, fall through to try using
|
||||
sendfile(). */
|
||||
if ((errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) ||
|
||||
req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = -errno;
|
||||
if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) {
|
||||
err = UV__ERR(errno);
|
||||
goto out;
|
||||
} else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
|
||||
err = UV_ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
@@ -968,7 +966,11 @@ out:
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
if (result == 0)
|
||||
return 0;
|
||||
|
||||
errno = UV__ERR(result);
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1084,9 +1086,21 @@ static int uv__fs_fstat(int fd, uv_stat_t *buf) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
|
||||
size_t offset;
|
||||
/* Figure out which bufs are done */
|
||||
for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
|
||||
size -= bufs[offset].len;
|
||||
|
||||
typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
|
||||
static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
|
||||
/* Fix a partial read/write */
|
||||
if (size > 0) {
|
||||
bufs[offset].base += size;
|
||||
bufs[offset].len -= size;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_write_all(uv_fs_t* req) {
|
||||
unsigned int iovmax;
|
||||
unsigned int nbufs;
|
||||
uv_buf_t* bufs;
|
||||
@@ -1103,7 +1117,10 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
|
||||
if (req->nbufs > iovmax)
|
||||
req->nbufs = iovmax;
|
||||
|
||||
result = process(req);
|
||||
do
|
||||
result = uv__fs_write(req);
|
||||
while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result <= 0) {
|
||||
if (total == 0)
|
||||
total = result;
|
||||
@@ -1113,14 +1130,12 @@ static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process)
|
||||
if (req->off >= 0)
|
||||
req->off += result;
|
||||
|
||||
req->nbufs = uv__fs_buf_offset(req->bufs, result);
|
||||
req->bufs += req->nbufs;
|
||||
nbufs -= req->nbufs;
|
||||
total += result;
|
||||
}
|
||||
|
||||
if (errno == EINTR && total == -1)
|
||||
return total;
|
||||
|
||||
if (bufs != req->bufsml)
|
||||
uv__free(bufs);
|
||||
|
||||
@@ -1137,7 +1152,8 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
ssize_t r;
|
||||
|
||||
req = container_of(w, uv_fs_t, work_req);
|
||||
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
|
||||
retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
|
||||
req->fs_type == UV_FS_READ);
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
@@ -1155,6 +1171,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(COPYFILE, uv__fs_copyfile(req));
|
||||
X(FCHMOD, fchmod(req->file, req->mode));
|
||||
X(FCHOWN, fchown(req->file, req->uid, req->gid));
|
||||
X(LCHOWN, lchown(req->path, req->uid, req->gid));
|
||||
X(FDATASYNC, uv__fs_fdatasync(req));
|
||||
X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
|
||||
X(FSYNC, uv__fs_fsync(req));
|
||||
@@ -1165,7 +1182,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(MKDIR, mkdir(req->path, req->mode));
|
||||
X(MKDTEMP, uv__fs_mkdtemp(req));
|
||||
X(OPEN, uv__fs_open(req));
|
||||
X(READ, uv__fs_buf_iter(req, uv__fs_read));
|
||||
X(READ, uv__fs_read(req));
|
||||
X(SCANDIR, uv__fs_scandir(req));
|
||||
X(READLINK, uv__fs_readlink(req));
|
||||
X(REALPATH, uv__fs_realpath(req));
|
||||
@@ -1176,7 +1193,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(SYMLINK, symlink(req->path, req->new_path));
|
||||
X(UNLINK, unlink(req->path));
|
||||
X(UTIME, uv__fs_utime(req));
|
||||
X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
|
||||
X(WRITE, uv__fs_write_all(req));
|
||||
default: abort();
|
||||
}
|
||||
#undef X
|
||||
@@ -1281,6 +1298,20 @@ int uv_fs_fchown(uv_loop_t* loop,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_lchown(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb) {
|
||||
INIT(LCHOWN);
|
||||
PATH;
|
||||
req->uid = uid;
|
||||
req->gid = gid;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
|
||||
INIT(FDATASYNC);
|
||||
req->file = file;
|
||||
|
||||
@@ -255,42 +255,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
path = paths[i];
|
||||
len = strlen(path);
|
||||
|
||||
if (handle->realpath_len == 0)
|
||||
continue; /* This should be unreachable */
|
||||
|
||||
/* Filter out paths that are outside handle's request */
|
||||
if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
if (len < handle->realpath_len)
|
||||
continue;
|
||||
|
||||
if (handle->realpath_len > 1 || *handle->realpath != '/') {
|
||||
if (handle->realpath_len != len &&
|
||||
path[handle->realpath_len] != '/')
|
||||
/* Make sure that realpath actually named a directory,
|
||||
* or that we matched the whole string */
|
||||
continue;
|
||||
|
||||
if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
|
||||
continue;
|
||||
|
||||
if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
|
||||
/* Remove common prefix, unless the watched folder is "/" */
|
||||
path += handle->realpath_len;
|
||||
len -= handle->realpath_len;
|
||||
|
||||
/* Skip forward slash */
|
||||
if (*path != '\0') {
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
|
||||
if (len == 0) {
|
||||
/* Since we're using fsevents to watch the file itself,
|
||||
* realpath == path, and we now need to get the basename of the file back
|
||||
* (for commonality with other codepaths and platforms). */
|
||||
while (len < handle->realpath_len && path[-1] != '/') {
|
||||
path--;
|
||||
len++;
|
||||
}
|
||||
/* Created and Removed seem to be always set, but don't make sense */
|
||||
flags &= ~kFSEventsRenamed;
|
||||
} else {
|
||||
/* Skip forward slash */
|
||||
path++;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
/* Ignore events with path equal to directory itself */
|
||||
if (len == 0)
|
||||
continue;
|
||||
#else
|
||||
if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
continue;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
/* Do not emit events from subdirectories (without option set) */
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
|
||||
if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
|
||||
pos = strchr(path + 1, '/');
|
||||
if (pos != NULL)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
path = "";
|
||||
len = 0;
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
event = uv__malloc(sizeof(*event) + len);
|
||||
if (event == NULL)
|
||||
break;
|
||||
@@ -299,22 +312,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
|
||||
memcpy(event->path, path, len + 1);
|
||||
event->events = UV_RENAME;
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_7
|
||||
if (0 != (flags & kFSEventsModified) &&
|
||||
0 == (flags & kFSEventsRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
if (0 == (flags & kFSEventsRenamed)) {
|
||||
if (0 != (flags & kFSEventsModified) ||
|
||||
0 == (flags & kFSEventStreamEventFlagItemIsDir))
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
#else
|
||||
if (0 != (flags & kFSEventsModified) &&
|
||||
0 != (flags & kFSEventStreamEventFlagItemIsDir) &&
|
||||
0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
if (0 == (flags & kFSEventStreamEventFlagItemIsDir) &&
|
||||
0 == (flags & kFSEventStreamEventFlagItemRenamed)) {
|
||||
event->events = UV_CHANGE;
|
||||
}
|
||||
#endif /* MAC_OS_X_VERSION_10_7 */
|
||||
|
||||
QUEUE_INSERT_TAIL(&head, &event->member);
|
||||
}
|
||||
@@ -836,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
|
||||
|
||||
handle->cf_cb->data = handle;
|
||||
uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
|
||||
handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
|
||||
handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
|
||||
uv_unref((uv_handle_t*) handle->cf_cb);
|
||||
|
||||
err = uv_mutex_init(&handle->cf_mutex);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "idna.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h> /* NULL */
|
||||
@@ -141,15 +142,34 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* hostname,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
size_t hostname_len;
|
||||
size_t service_len;
|
||||
size_t hints_len;
|
||||
size_t len;
|
||||
char* buf;
|
||||
long rc;
|
||||
|
||||
if (req == NULL || (hostname == NULL && service == NULL))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
|
||||
* probably because it uses EBCDIC rather than ASCII.
|
||||
*/
|
||||
#ifdef __MVS__
|
||||
(void) &hostname_ascii;
|
||||
#else
|
||||
if (hostname != NULL) {
|
||||
rc = uv__idna_toascii(hostname,
|
||||
hostname + strlen(hostname),
|
||||
hostname_ascii,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
hostname = hostname_ascii;
|
||||
}
|
||||
#endif
|
||||
|
||||
hostname_len = hostname ? strlen(hostname) + 1 : 0;
|
||||
service_len = service ? strlen(service) + 1 : 0;
|
||||
hints_len = hints ? sizeof(*hints) : 0;
|
||||
@@ -186,6 +206,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
if (cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -109,6 +109,7 @@ int uv_getnameinfo(uv_loop_t* loop,
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -72,7 +72,8 @@ void uv_loadavg(double avg[3]) {
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
return UV_ENOSYS;
|
||||
*rss = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -137,26 +137,6 @@ int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
|
||||
|
||||
typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
|
||||
|
||||
/* handle flags */
|
||||
enum {
|
||||
UV_CLOSING = 0x01, /* uv_close() called but not finished. */
|
||||
UV_CLOSED = 0x02, /* close(2) finished. */
|
||||
UV_STREAM_READING = 0x04, /* uv_read_start() called. */
|
||||
UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
|
||||
UV_STREAM_SHUT = 0x10, /* Write side closed. */
|
||||
UV_STREAM_READABLE = 0x20, /* The stream is readable */
|
||||
UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
|
||||
UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
|
||||
UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
|
||||
UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
|
||||
UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
|
||||
UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
|
||||
UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
|
||||
UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
|
||||
UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */
|
||||
UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */
|
||||
};
|
||||
|
||||
/* loop flags */
|
||||
enum {
|
||||
UV_LOOP_BLOCK_SIGPROF = 1
|
||||
@@ -215,7 +195,6 @@ int uv__nonblock_fcntl(int fd, int set);
|
||||
int uv__close(int fd); /* preserves errno */
|
||||
int uv__close_nocheckstdio(int fd);
|
||||
int uv__socket(int domain, int type, int protocol);
|
||||
int uv__dup(int fd);
|
||||
ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
|
||||
void uv__make_close_pending(uv_handle_t* handle);
|
||||
int uv__getiovmax(void);
|
||||
@@ -229,6 +208,7 @@ int uv__io_active(const uv__io_t* w, unsigned int events);
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd);
|
||||
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
|
||||
int uv__io_fork(uv_loop_t* loop);
|
||||
int uv__fd_exists(uv_loop_t* loop, int fd);
|
||||
|
||||
/* async */
|
||||
void uv__async_stop(uv_loop_t* loop);
|
||||
@@ -261,10 +241,6 @@ int uv__tcp_keepalive(int fd, int on, unsigned int delay);
|
||||
/* pipe */
|
||||
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
|
||||
/* timer */
|
||||
void uv__run_timers(uv_loop_t* loop);
|
||||
int uv__next_timeout(const uv_loop_t* loop);
|
||||
|
||||
/* signal */
|
||||
void uv__signal_close(uv_signal_t* handle);
|
||||
void uv__signal_global_once_init(void);
|
||||
@@ -289,7 +265,6 @@ void uv__prepare_close(uv_prepare_t* handle);
|
||||
void uv__process_close(uv_process_t* handle);
|
||||
void uv__stream_close(uv_stream_t* handle);
|
||||
void uv__tcp_close(uv_tcp_t* handle);
|
||||
void uv__timer_close(uv_timer_t* handle);
|
||||
void uv__udp_close(uv_udp_t* handle);
|
||||
void uv__udp_finish_close(uv_udp_t* handle);
|
||||
uv_handle_type uv__handle_type(int fd);
|
||||
@@ -319,24 +294,6 @@ int uv__fsevents_init(uv_fs_event_t* handle);
|
||||
int uv__fsevents_close(uv_fs_event_t* handle);
|
||||
void uv__fsevents_loop_delete(uv_loop_t* loop);
|
||||
|
||||
/* OSX < 10.7 has no file events, polyfill them */
|
||||
#ifndef MAC_OS_X_VERSION_10_7
|
||||
|
||||
static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
|
||||
static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
|
||||
static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
|
||||
static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
|
||||
static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
|
||||
static const int kFSEventStreamEventFlagItemModified = 0x00001000;
|
||||
static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
|
||||
static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
|
||||
static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
|
||||
static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
|
||||
static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
|
||||
static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
|
||||
|
||||
#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
|
||||
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
|
||||
|
||||
@@ -261,8 +261,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
w = loop->watchers[fd];
|
||||
|
||||
if (w == NULL) {
|
||||
/* File descriptor that we've stopped watching, disarm it. */
|
||||
/* TODO batch up */
|
||||
/* File descriptor that we've stopped watching, disarm it.
|
||||
* TODO: batch up. */
|
||||
struct kevent events[1];
|
||||
|
||||
EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
|
||||
@@ -452,49 +452,48 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv_fs_event_cb cb,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
#if defined(__APPLE__)
|
||||
struct stat statbuf;
|
||||
#endif /* defined(__APPLE__) */
|
||||
int fd;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
handle->path = uv__strdup(path);
|
||||
handle->cb = cb;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (uv__has_forked_with_cfrunloop)
|
||||
goto fallback;
|
||||
|
||||
/* Nullify field to perform checks later */
|
||||
handle->cf_cb = NULL;
|
||||
handle->realpath = NULL;
|
||||
handle->realpath_len = 0;
|
||||
handle->cf_flags = flags;
|
||||
|
||||
if (fstat(fd, &statbuf))
|
||||
goto fallback;
|
||||
/* FSEvents works only with directories */
|
||||
if (!(statbuf.st_mode & S_IFDIR))
|
||||
goto fallback;
|
||||
|
||||
/* The fallback fd is no longer needed */
|
||||
uv__close(fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
|
||||
return uv__fsevents_init(handle);
|
||||
|
||||
fallback:
|
||||
if (!uv__has_forked_with_cfrunloop) {
|
||||
int r;
|
||||
/* The fallback fd is not used */
|
||||
handle->event_watcher.fd = -1;
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->cb = cb;
|
||||
r = uv__fsevents_init(handle);
|
||||
if (r == 0) {
|
||||
uv__handle_start(handle);
|
||||
} else {
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
/* TODO open asynchronously - but how do we report back errors? */
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd == -1)
|
||||
return UV__ERR(errno);
|
||||
|
||||
handle->path = uv__strdup(path);
|
||||
if (handle->path == NULL)
|
||||
return UV_ENOMEM;
|
||||
handle->cb = cb;
|
||||
uv__handle_start(handle);
|
||||
uv__io_init(&handle->event_watcher, uv__fs_event, fd);
|
||||
uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
|
||||
|
||||
return 0;
|
||||
@@ -502,29 +501,29 @@ fallback:
|
||||
|
||||
|
||||
int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
int r;
|
||||
r = 0;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
uv__handle_stop(handle);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle))
|
||||
#endif /* defined(__APPLE__) */
|
||||
{
|
||||
if (!uv__has_forked_with_cfrunloop)
|
||||
r = uv__fsevents_close(handle);
|
||||
#endif
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
uv__io_close(handle->loop, &handle->event_watcher);
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
uv__free(handle->path);
|
||||
handle->path = NULL;
|
||||
|
||||
if (handle->event_watcher.fd != -1) {
|
||||
/* When FSEvents is used, we don't use the event_watcher's fd under certain
|
||||
* confitions. (see uv_fs_event_start) */
|
||||
uv__close(handle->event_watcher.fd);
|
||||
handle->event_watcher.fd = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
|
||||
* EPOLL* counterparts. We use the POLL* variants in this file because that
|
||||
* is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
|
||||
* is what libuv uses elsewhere.
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -51,7 +52,7 @@
|
||||
|
||||
#ifdef HAVE_IFADDRS_H
|
||||
# if defined(__ANDROID__)
|
||||
# include "android-ifaddrs.h"
|
||||
# include "uv/android-ifaddrs.h"
|
||||
# else
|
||||
# include <ifaddrs.h>
|
||||
# endif
|
||||
@@ -84,13 +85,13 @@ static unsigned long read_cpufreq(unsigned int cpunum);
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
int fd;
|
||||
|
||||
fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
|
||||
fd = epoll_create1(EPOLL_CLOEXEC);
|
||||
|
||||
/* epoll_create1() can fail either because it's not implemented (old kernel)
|
||||
* or because it doesn't understand the EPOLL_CLOEXEC flag.
|
||||
*/
|
||||
if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
|
||||
fd = uv__epoll_create(256);
|
||||
fd = epoll_create(256);
|
||||
|
||||
if (fd != -1)
|
||||
uv__cloexec(fd, 1);
|
||||
@@ -134,20 +135,20 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
|
||||
|
||||
|
||||
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event* events;
|
||||
struct uv__epoll_event dummy;
|
||||
struct epoll_event* events;
|
||||
struct epoll_event dummy;
|
||||
uintptr_t i;
|
||||
uintptr_t nfds;
|
||||
|
||||
assert(loop->watchers != NULL);
|
||||
|
||||
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
|
||||
events = (struct epoll_event*) loop->watchers[loop->nwatchers];
|
||||
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
|
||||
if (events != NULL)
|
||||
/* Invalidate events with same file descriptor */
|
||||
for (i = 0; i < nfds; i++)
|
||||
if ((int) events[i].data == fd)
|
||||
events[i].data = -1;
|
||||
if (events[i].data.fd == fd)
|
||||
events[i].data.fd = -1;
|
||||
|
||||
/* Remove the file descriptor from the epoll.
|
||||
* This avoids a problem where the same file description remains open
|
||||
@@ -160,25 +161,26 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
* has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
|
||||
*/
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv__io_check_fd(uv_loop_t* loop, int fd) {
|
||||
struct uv__epoll_event e;
|
||||
struct epoll_event e;
|
||||
int rc;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
e.events = POLLIN;
|
||||
e.data = -1;
|
||||
e.data.fd = -1;
|
||||
|
||||
rc = 0;
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
|
||||
if (errno != EEXIST)
|
||||
rc = UV__ERR(errno);
|
||||
|
||||
if (rc == 0)
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
|
||||
abort();
|
||||
|
||||
return rc;
|
||||
@@ -195,16 +197,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* that being the largest value I have seen in the wild (and only once.)
|
||||
*/
|
||||
static const int max_safe_timeout = 1789569;
|
||||
static int no_epoll_pwait;
|
||||
static int no_epoll_wait;
|
||||
struct uv__epoll_event events[1024];
|
||||
struct uv__epoll_event* pe;
|
||||
struct uv__epoll_event e;
|
||||
struct epoll_event events[1024];
|
||||
struct epoll_event* pe;
|
||||
struct epoll_event e;
|
||||
int real_timeout;
|
||||
QUEUE* q;
|
||||
uv__io_t* w;
|
||||
sigset_t sigset;
|
||||
uint64_t sigmask;
|
||||
sigset_t* psigset;
|
||||
uint64_t base;
|
||||
int have_signals;
|
||||
int nevents;
|
||||
@@ -219,6 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
|
||||
while (!QUEUE_EMPTY(&loop->watcher_queue)) {
|
||||
q = QUEUE_HEAD(&loop->watcher_queue);
|
||||
QUEUE_REMOVE(q);
|
||||
@@ -230,35 +232,35 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
assert(w->fd < (int) loop->nwatchers);
|
||||
|
||||
e.events = w->pevents;
|
||||
e.data = w->fd;
|
||||
e.data.fd = w->fd;
|
||||
|
||||
if (w->events == 0)
|
||||
op = UV__EPOLL_CTL_ADD;
|
||||
op = EPOLL_CTL_ADD;
|
||||
else
|
||||
op = UV__EPOLL_CTL_MOD;
|
||||
op = EPOLL_CTL_MOD;
|
||||
|
||||
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
|
||||
* events, skip the syscall and squelch the events after epoll_wait().
|
||||
*/
|
||||
if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
|
||||
if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
|
||||
if (errno != EEXIST)
|
||||
abort();
|
||||
|
||||
assert(op == UV__EPOLL_CTL_ADD);
|
||||
assert(op == EPOLL_CTL_ADD);
|
||||
|
||||
/* We've reactivated a file descriptor that's been watched before. */
|
||||
if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
|
||||
if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
w->events = w->pevents;
|
||||
}
|
||||
|
||||
sigmask = 0;
|
||||
psigset = NULL;
|
||||
if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPROF);
|
||||
sigmask |= 1 << (SIGPROF - 1);
|
||||
psigset = &sigset;
|
||||
}
|
||||
|
||||
assert(timeout >= -1);
|
||||
@@ -273,30 +275,11 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
|
||||
timeout = max_safe_timeout;
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
|
||||
abort();
|
||||
|
||||
if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
|
||||
nfds = uv__epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
sigmask);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_pwait = 1;
|
||||
} else {
|
||||
nfds = uv__epoll_wait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout);
|
||||
if (nfds == -1 && errno == ENOSYS)
|
||||
no_epoll_wait = 1;
|
||||
}
|
||||
|
||||
if (sigmask != 0 && no_epoll_pwait != 0)
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
|
||||
abort();
|
||||
nfds = epoll_pwait(loop->backend_fd,
|
||||
events,
|
||||
ARRAY_SIZE(events),
|
||||
timeout,
|
||||
psigset);
|
||||
|
||||
/* Update loop->time unconditionally. It's tempting to skip the update when
|
||||
* timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
|
||||
@@ -317,12 +300,6 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
}
|
||||
|
||||
if (nfds == -1) {
|
||||
if (errno == ENOSYS) {
|
||||
/* epoll_wait() or epoll_pwait() failed, try the other system call. */
|
||||
assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errno != EINTR)
|
||||
abort();
|
||||
|
||||
@@ -344,7 +321,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
pe = events + i;
|
||||
fd = pe->data;
|
||||
fd = pe->data.fd;
|
||||
|
||||
/* Skip invalidated events, see uv__platform_invalidate_fd */
|
||||
if (fd == -1)
|
||||
@@ -361,7 +338,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* Ignore all errors because we may be racing with another thread
|
||||
* when the file descriptor is closed.
|
||||
*/
|
||||
uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
|
||||
epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -388,7 +365,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* free when we switch over to edge-triggered I/O.
|
||||
*/
|
||||
if (pe->events == POLLERR || pe->events == POLLHUP)
|
||||
pe->events |= w->pevents & (POLLIN | POLLOUT | UV__POLLPRI);
|
||||
pe->events |=
|
||||
w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
|
||||
|
||||
if (pe->events != 0) {
|
||||
/* Run signal watchers last. This also affects child process watchers
|
||||
@@ -851,9 +829,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
|
||||
return !exclude_type;
|
||||
}
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int* count) {
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
#ifndef HAVE_IFADDRS_H
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
return UV_ENOSYS;
|
||||
#else
|
||||
struct ifaddrs *addrs, *ent;
|
||||
@@ -861,12 +840,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
int i;
|
||||
struct sockaddr_ll *sll;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
|
||||
@@ -875,8 +854,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0)
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
@@ -920,6 +901,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses,
|
||||
if (strcmp(address->name, ent->ifa_name) == 0) {
|
||||
sll = (struct sockaddr_ll*)ent->ifa_addr;
|
||||
memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
|
||||
} else {
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
}
|
||||
address++;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "uv/tree.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -278,6 +278,7 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
const char* path,
|
||||
unsigned int flags) {
|
||||
struct watcher_list* w;
|
||||
size_t len;
|
||||
int events;
|
||||
int err;
|
||||
int wd;
|
||||
@@ -306,12 +307,13 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
if (w)
|
||||
goto no_insert;
|
||||
|
||||
w = uv__malloc(sizeof(*w) + strlen(path) + 1);
|
||||
len = strlen(path) + 1;
|
||||
w = uv__malloc(sizeof(*w) + len);
|
||||
if (w == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
w->wd = wd;
|
||||
w->path = strcpy((char*)(w + 1), path);
|
||||
w->path = memcpy(w + 1, path, len);
|
||||
QUEUE_INIT(&w->watchers);
|
||||
w->iterating = 0;
|
||||
RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
|
||||
|
||||
@@ -77,56 +77,6 @@
|
||||
# endif
|
||||
#endif /* __NR_eventfd2 */
|
||||
|
||||
#ifndef __NR_epoll_create
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create 213
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create 254
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create */
|
||||
|
||||
#ifndef __NR_epoll_create1
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_create1 291
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_create1 329
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
|
||||
# endif
|
||||
#endif /* __NR_epoll_create1 */
|
||||
|
||||
#ifndef __NR_epoll_ctl
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_ctl 233 /* used to be 214 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_ctl 255
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
|
||||
# endif
|
||||
#endif /* __NR_epoll_ctl */
|
||||
|
||||
#ifndef __NR_epoll_wait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_wait 232 /* used to be 215 */
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_wait 256
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
|
||||
# endif
|
||||
#endif /* __NR_epoll_wait */
|
||||
|
||||
#ifndef __NR_epoll_pwait
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_epoll_pwait 281
|
||||
# elif defined(__i386__)
|
||||
# define __NR_epoll_pwait 319
|
||||
# elif defined(__arm__)
|
||||
# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
|
||||
# endif
|
||||
#endif /* __NR_epoll_pwait */
|
||||
|
||||
#ifndef __NR_inotify_init
|
||||
# if defined(__x86_64__)
|
||||
# define __NR_inotify_init 253
|
||||
@@ -285,76 +235,6 @@ int uv__eventfd2(unsigned int count, int flags) {
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create(int size) {
|
||||
#if defined(__NR_epoll_create)
|
||||
return syscall(__NR_epoll_create, size);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_create1(int flags) {
|
||||
#if defined(__NR_epoll_create1)
|
||||
return syscall(__NR_epoll_create1, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
|
||||
#if defined(__NR_epoll_ctl)
|
||||
return syscall(__NR_epoll_ctl, epfd, op, fd, events);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout) {
|
||||
#if defined(__NR_epoll_wait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask) {
|
||||
#if defined(__NR_epoll_pwait)
|
||||
int result;
|
||||
result = syscall(__NR_epoll_pwait,
|
||||
epfd,
|
||||
events,
|
||||
nevents,
|
||||
timeout,
|
||||
&sigmask,
|
||||
sizeof(sigmask));
|
||||
#if MSAN_ACTIVE
|
||||
if (result > 0)
|
||||
__msan_unpoison(events, sizeof(events[0]) * result);
|
||||
#endif
|
||||
return result;
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int uv__inotify_init(void) {
|
||||
#if defined(__NR_inotify_init)
|
||||
return syscall(__NR_inotify_init);
|
||||
@@ -431,19 +311,6 @@ int uv__recvmmsg(int fd,
|
||||
}
|
||||
|
||||
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags)
|
||||
{
|
||||
#if defined(__NR_utimensat)
|
||||
return syscall(__NR_utimensat, dirfd, path, times, flags);
|
||||
#else
|
||||
return errno = ENOSYS, -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
|
||||
#if defined(__NR_preadv)
|
||||
return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
|
||||
|
||||
@@ -66,12 +66,6 @@
|
||||
# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
|
||||
#endif
|
||||
|
||||
/* epoll flags */
|
||||
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EPOLL_CTL_ADD 1
|
||||
#define UV__EPOLL_CTL_DEL 2
|
||||
#define UV__EPOLL_CTL_MOD 3
|
||||
|
||||
/* inotify flags */
|
||||
#define UV__IN_ACCESS 0x001
|
||||
#define UV__IN_MODIFY 0x002
|
||||
@@ -86,18 +80,6 @@
|
||||
#define UV__IN_DELETE_SELF 0x400
|
||||
#define UV__IN_MOVE_SELF 0x800
|
||||
|
||||
#if defined(__x86_64__)
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
struct uv__epoll_event {
|
||||
uint32_t events;
|
||||
uint64_t data;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct uv__inotify_event {
|
||||
int32_t wd;
|
||||
uint32_t mask;
|
||||
@@ -113,18 +95,6 @@ struct uv__mmsghdr {
|
||||
|
||||
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
|
||||
int uv__eventfd(unsigned int count);
|
||||
int uv__epoll_create(int size);
|
||||
int uv__epoll_create1(int flags);
|
||||
int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
|
||||
int uv__epoll_wait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout);
|
||||
int uv__epoll_pwait(int epfd,
|
||||
struct uv__epoll_event* events,
|
||||
int nevents,
|
||||
int timeout,
|
||||
uint64_t sigmask);
|
||||
int uv__eventfd2(unsigned int count, int flags);
|
||||
int uv__inotify_init(void);
|
||||
int uv__inotify_init1(int flags);
|
||||
@@ -140,10 +110,6 @@ int uv__sendmmsg(int fd,
|
||||
struct uv__mmsghdr* mmsg,
|
||||
unsigned int vlen,
|
||||
unsigned int flags);
|
||||
int uv__utimesat(int dirfd,
|
||||
const char* path,
|
||||
const struct timespec times[2],
|
||||
int flags);
|
||||
ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
|
||||
int uv__dup3(int oldfd, int newfd, int flags);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "uv/tree.h"
|
||||
#include "internal.h"
|
||||
#include "heap-inl.h"
|
||||
#include <stdlib.h>
|
||||
@@ -74,7 +74,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_signal_init;
|
||||
|
||||
uv__handle_unref(&loop->child_watcher);
|
||||
loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
|
||||
QUEUE_INIT(&loop->process_handles);
|
||||
|
||||
err = uv_rwlock_init(&loop->cloexec_lock);
|
||||
@@ -90,7 +90,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -40,15 +40,6 @@
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
@@ -96,7 +87,8 @@ int uv_exepath(char* buffer, size_t* size) {
|
||||
/* Copy string from the intermediate buffer to outer one with appropriate
|
||||
* length.
|
||||
*/
|
||||
strlcpy(buffer, int_buf, *size);
|
||||
/* TODO(bnoordhuis) Check uv__strscpy() return value. */
|
||||
uv__strscpy(buffer, int_buf, *size);
|
||||
|
||||
/* Set new size. */
|
||||
*size = strlen(buffer);
|
||||
@@ -134,65 +126,6 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
kvm_t *kd = NULL;
|
||||
struct kinfo_proc2 *kinfo = NULL;
|
||||
|
||||
@@ -36,16 +36,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
|
||||
static char *process_title;
|
||||
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv__platform_loop_init(uv_loop_t* loop) {
|
||||
return uv__kqueue_init(loop);
|
||||
}
|
||||
@@ -146,65 +136,6 @@ uint64_t uv_get_total_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
process_title = argc ? uv__strdup(argv[0]) : NULL;
|
||||
return argv;
|
||||
}
|
||||
|
||||
|
||||
int uv_set_process_title(const char* title) {
|
||||
char* new_title;
|
||||
|
||||
new_title = uv__strdup(title);
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title == NULL) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
uv__free(process_title);
|
||||
process_title = new_title;
|
||||
setproctitle("%s", title);
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv_once(&process_title_mutex_once, init_process_title_mutex_once);
|
||||
uv_mutex_lock(&process_title_mutex);
|
||||
|
||||
if (process_title) {
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uv_mutex_unlock(&process_title_mutex);
|
||||
|
||||
buffer[len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
struct kinfo_proc kinfo;
|
||||
size_t page_size = getpagesize();
|
||||
|
||||
@@ -141,7 +141,7 @@ static void init_message_queue(uv__os390_epoll* lst) {
|
||||
} msg;
|
||||
|
||||
/* initialize message queue */
|
||||
lst->msg_queue = msgget(IPC_PRIVATE, 0622 | IPC_CREAT);
|
||||
lst->msg_queue = msgget(IPC_PRIVATE, 0600 | IPC_CREAT);
|
||||
if (lst->msg_queue == -1)
|
||||
abort();
|
||||
|
||||
@@ -255,12 +255,13 @@ int epoll_ctl(uv__os390_epoll* lst,
|
||||
lst->items[fd].events = event->events;
|
||||
lst->items[fd].revents = 0;
|
||||
} else if (op == EPOLL_CTL_MOD) {
|
||||
if (fd >= lst->size || lst->items[fd].fd == -1) {
|
||||
if (fd >= lst->size - 1 || lst->items[fd].fd == -1) {
|
||||
uv_mutex_unlock(&global_epoll_lock);
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
lst->items[fd].events = event->events;
|
||||
lst->items[fd].revents = 0;
|
||||
} else
|
||||
abort();
|
||||
|
||||
@@ -275,8 +276,9 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
struct pollfd* pfds;
|
||||
int pollret;
|
||||
int reventcount;
|
||||
int nevents;
|
||||
|
||||
size = _SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
_SET_FDS_MSGS(size, 1, lst->size - 1);
|
||||
pfds = lst->items;
|
||||
pollret = poll(pfds, size, timeout);
|
||||
if (pollret <= 0)
|
||||
@@ -285,19 +287,28 @@ int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
|
||||
pollret = _NFDS(pollret) + _NMSGS(pollret);
|
||||
|
||||
reventcount = 0;
|
||||
nevents = 0;
|
||||
for (int i = 0;
|
||||
i < lst->size && i < maxevents && reventcount < pollret; ++i) {
|
||||
struct epoll_event ev;
|
||||
struct pollfd* pfd;
|
||||
|
||||
if (pfds[i].fd == -1 || pfds[i].revents == 0)
|
||||
pfd = &pfds[i];
|
||||
if (pfd->fd == -1 || pfd->revents == 0)
|
||||
continue;
|
||||
|
||||
ev.fd = pfds[i].fd;
|
||||
ev.events = pfds[i].revents;
|
||||
events[reventcount++] = ev;
|
||||
ev.fd = pfd->fd;
|
||||
ev.events = pfd->revents;
|
||||
if (pfd->revents & POLLIN && pfd->revents & POLLOUT)
|
||||
reventcount += 2;
|
||||
else if (pfd->revents & (POLLIN | POLLOUT))
|
||||
++reventcount;
|
||||
|
||||
pfd->revents = 0;
|
||||
events[nevents++] = ev;
|
||||
}
|
||||
|
||||
return reventcount;
|
||||
return nevents;
|
||||
}
|
||||
|
||||
|
||||
@@ -493,7 +504,7 @@ ssize_t os390_readlink(const char* path, char* buf, size_t len) {
|
||||
|
||||
|
||||
size_t strnlen(const char* str, size_t maxlen) {
|
||||
void* p = memchr(str, 0, maxlen);
|
||||
char* p = memchr(str, 0, maxlen);
|
||||
if (p == NULL)
|
||||
return maxlen;
|
||||
else
|
||||
|
||||
@@ -36,10 +36,6 @@
|
||||
#define MAX_ITEMS_PER_EPOLL 1024
|
||||
|
||||
#define UV__O_CLOEXEC 0x80000
|
||||
#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
|
||||
#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD
|
||||
#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL
|
||||
#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD
|
||||
|
||||
struct epoll_event {
|
||||
int events;
|
||||
|
||||
@@ -229,15 +229,15 @@ static int getexe(const int pid, char* buf, size_t len) {
|
||||
assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
|
||||
|
||||
/* Get the offset from the lowest 3 bytes */
|
||||
Output_path = (char*)(&Output_buf) +
|
||||
(Output_buf.Output_data.offsetPath & 0x00FFFFFF);
|
||||
Output_path = (struct Output_path_type*) ((char*) (&Output_buf) +
|
||||
(Output_buf.Output_data.offsetPath & 0x00FFFFFF));
|
||||
|
||||
if (Output_path->len >= len) {
|
||||
errno = ENOBUFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(buf, Output_path->path, len);
|
||||
uv__strscpy(buf, Output_path->path, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -357,13 +357,11 @@ uint64_t uv_get_total_memory(void) {
|
||||
|
||||
|
||||
int uv_resident_set_memory(size_t* rss) {
|
||||
char* psa;
|
||||
char* ascb;
|
||||
char* rax;
|
||||
size_t nframes;
|
||||
|
||||
psa = PSA_PTR;
|
||||
ascb = *(char* __ptr32 *)(psa + PSAAOLD);
|
||||
ascb = *(char* __ptr32 *)(PSA_PTR + PSAAOLD);
|
||||
rax = *(char* __ptr32 *)(ascb + ASCBRSME);
|
||||
nframes = *(unsigned int*)(rax + RAXFMCT);
|
||||
|
||||
@@ -512,7 +510,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
/* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
|
||||
|
||||
address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
|
||||
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
address++;
|
||||
}
|
||||
|
||||
@@ -531,12 +529,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifreq* p;
|
||||
int count_v6;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
/* get the ipv6 addresses first */
|
||||
uv_interface_address_t* addresses_v6;
|
||||
uv__interface_addresses_v6(&addresses_v6, &count_v6);
|
||||
|
||||
/* now get the ipv4 addresses */
|
||||
*count = 0;
|
||||
|
||||
/* Assume maximum buffer size allowable */
|
||||
maxsize = 16384;
|
||||
@@ -578,6 +578,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc((*count + count_v6) *
|
||||
sizeof(uv_interface_address_t));
|
||||
@@ -624,6 +629,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
}
|
||||
|
||||
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
address++;
|
||||
}
|
||||
|
||||
@@ -662,7 +668,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
|
||||
|
||||
/* Remove the file descriptor from the epoll. */
|
||||
if (loop->ep != NULL)
|
||||
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
|
||||
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, &dummy);
|
||||
}
|
||||
|
||||
|
||||
@@ -751,7 +757,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
memcpy(reg_struct.__rfis_rftok, handle->rfis_rftok,
|
||||
sizeof(handle->rfis_rftok));
|
||||
|
||||
/*
|
||||
/*
|
||||
* This call will take "/" as the path argument in case we
|
||||
* don't care to supply the correct path. The system will simply
|
||||
* ignore it.
|
||||
@@ -838,9 +844,9 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
e.fd = w->fd;
|
||||
|
||||
if (w->events == 0)
|
||||
op = UV__EPOLL_CTL_ADD;
|
||||
op = EPOLL_CTL_ADD;
|
||||
else
|
||||
op = UV__EPOLL_CTL_MOD;
|
||||
op = EPOLL_CTL_MOD;
|
||||
|
||||
/* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
|
||||
* events, skip the syscall and squelch the events after epoll_wait().
|
||||
@@ -849,10 +855,10 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
if (errno != EEXIST)
|
||||
abort();
|
||||
|
||||
assert(op == UV__EPOLL_CTL_ADD);
|
||||
assert(op == EPOLL_CTL_ADD);
|
||||
|
||||
/* We've reactivated a file descriptor that's been watched before. */
|
||||
if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
|
||||
if (epoll_ctl(loop->ep, EPOLL_CTL_MOD, w->fd, &e))
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -934,7 +940,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
|
||||
* Ignore all errors because we may be racing with another thread
|
||||
* when the file descriptor is closed.
|
||||
*/
|
||||
epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
|
||||
epoll_ctl(loop->ep, EPOLL_CTL_DEL, fd, pe);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -987,7 +993,7 @@ void uv__set_process_title(const char* title) {
|
||||
}
|
||||
|
||||
int uv__io_fork(uv_loop_t* loop) {
|
||||
/*
|
||||
/*
|
||||
Nullify the msg queue but don't close it because
|
||||
it is still being used by the parent.
|
||||
*/
|
||||
|
||||
@@ -64,8 +64,7 @@ int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
|
||||
sockfd = err;
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
|
||||
@@ -130,7 +129,20 @@ void uv__pipe_close(uv_pipe_t* handle) {
|
||||
|
||||
|
||||
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
int flags;
|
||||
int mode;
|
||||
int err;
|
||||
flags = 0;
|
||||
|
||||
if (uv__fd_exists(handle->loop, fd))
|
||||
return UV_EEXIST;
|
||||
|
||||
do
|
||||
mode = fcntl(fd, F_GETFL);
|
||||
while (mode == -1 && errno == EINTR);
|
||||
|
||||
if (mode == -1)
|
||||
return UV__ERR(errno); /* according to docs, must be EBADF */
|
||||
|
||||
err = uv__nonblock(fd, 1);
|
||||
if (err)
|
||||
@@ -142,9 +154,13 @@ int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
|
||||
return err;
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
mode &= O_ACCMODE;
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle, fd, flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -167,8 +183,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
}
|
||||
|
||||
memset(&saddr, 0, sizeof saddr);
|
||||
strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
|
||||
saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
|
||||
uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
|
||||
saddr.sun_family = AF_UNIX;
|
||||
|
||||
do {
|
||||
@@ -194,7 +209,7 @@ void uv_pipe_connect(uv_connect_t* req,
|
||||
if (new_sock) {
|
||||
err = uv__stream_open((uv_stream_t*)handle,
|
||||
uv__stream_fd(handle),
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
|
||||
@@ -68,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
|
||||
int err;
|
||||
|
||||
if (uv__fd_exists(loop, fd))
|
||||
return UV_EEXIST;
|
||||
|
||||
err = uv__io_check_fd(loop, fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -250,9 +250,9 @@ static int uv__process_open_stream(uv_stdio_container_t* container,
|
||||
|
||||
flags = 0;
|
||||
if (container->flags & UV_WRITABLE_PIPE)
|
||||
flags |= UV_STREAM_READABLE;
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (container->flags & UV_READABLE_PIPE)
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
return uv__stream_open(container->data.stream, pipefds[0], flags);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void uv__set_process_title_platform_init(void);
|
||||
extern void uv__set_process_title(const char* title);
|
||||
|
||||
static uv_mutex_t process_title_mutex;
|
||||
@@ -38,6 +39,9 @@ static struct {
|
||||
|
||||
static void init_process_title_mutex_once(void) {
|
||||
uv_mutex_init(&process_title_mutex);
|
||||
#ifdef __APPLE__
|
||||
uv__set_process_title_platform_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -54,8 +54,7 @@ static void uv__signal_unregister_handler(int signum);
|
||||
static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
|
||||
static struct uv__signal_tree_s uv__signal_tree =
|
||||
RB_INITIALIZER(uv__signal_tree);
|
||||
static int uv__signal_lock_pipefd[2];
|
||||
|
||||
static int uv__signal_lock_pipefd[2] = { -1, -1 };
|
||||
|
||||
RB_GENERATE_STATIC(uv__signal_tree_s,
|
||||
uv_signal_s, tree_entry,
|
||||
@@ -64,7 +63,7 @@ RB_GENERATE_STATIC(uv__signal_tree_s,
|
||||
static void uv__signal_global_reinit(void);
|
||||
|
||||
static void uv__signal_global_init(void) {
|
||||
if (!uv__signal_lock_pipefd[0])
|
||||
if (uv__signal_lock_pipefd[0] == -1)
|
||||
/* pthread_atfork can register before and after handlers, one
|
||||
* for each child. This only registers one for the child. That
|
||||
* state is both persistent and cumulative, so if we keep doing
|
||||
@@ -74,6 +73,33 @@ static void uv__signal_global_init(void) {
|
||||
if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
|
||||
abort();
|
||||
|
||||
uv__signal_global_reinit();
|
||||
}
|
||||
|
||||
|
||||
UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
|
||||
/* We can only use signal-safe functions here.
|
||||
* That includes read/write and close, fortunately.
|
||||
* We do all of this directly here instead of resetting
|
||||
* uv__signal_global_init_guard because
|
||||
* uv__signal_global_once_init is only called from uv_loop_init
|
||||
* and this needs to function in existing loops.
|
||||
*/
|
||||
if (uv__signal_lock_pipefd[0] != -1) {
|
||||
uv__close(uv__signal_lock_pipefd[0]);
|
||||
uv__signal_lock_pipefd[0] = -1;
|
||||
}
|
||||
|
||||
if (uv__signal_lock_pipefd[1] != -1) {
|
||||
uv__close(uv__signal_lock_pipefd[1]);
|
||||
uv__signal_lock_pipefd[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_global_reinit(void) {
|
||||
uv__signal_global_fini();
|
||||
|
||||
if (uv__make_pipe(uv__signal_lock_pipefd, 0))
|
||||
abort();
|
||||
|
||||
@@ -82,28 +108,11 @@ static void uv__signal_global_init(void) {
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_global_reinit(void) {
|
||||
/* We can only use signal-safe functions here.
|
||||
* That includes read/write and close, fortunately.
|
||||
* We do all of this directly here instead of resetting
|
||||
* uv__signal_global_init_guard because
|
||||
* uv__signal_global_once_init is only called from uv_loop_init
|
||||
* and this needs to function in existing loops.
|
||||
*/
|
||||
uv__close(uv__signal_lock_pipefd[0]);
|
||||
uv__signal_lock_pipefd[0] = -1;
|
||||
uv__close(uv__signal_lock_pipefd[1]);
|
||||
uv__signal_lock_pipefd[1] = -1;
|
||||
uv__signal_global_init();
|
||||
}
|
||||
|
||||
|
||||
void uv__signal_global_once_init(void) {
|
||||
uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int uv__signal_lock(void) {
|
||||
int r;
|
||||
char data;
|
||||
@@ -387,7 +396,7 @@ static int uv__signal_start(uv_signal_t* handle,
|
||||
*/
|
||||
first_handle = uv__signal_first_handle(signum);
|
||||
if (first_handle == NULL ||
|
||||
(!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) {
|
||||
(!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
|
||||
err = uv__signal_register_handler(signum, oneshot);
|
||||
if (err) {
|
||||
/* Registering the signal handler failed. Must be an invalid signal. */
|
||||
@@ -398,7 +407,7 @@ static int uv__signal_start(uv_signal_t* handle,
|
||||
|
||||
handle->signum = signum;
|
||||
if (oneshot)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT;
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT;
|
||||
|
||||
RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
@@ -455,20 +464,20 @@ static void uv__signal_event(uv_loop_t* loop,
|
||||
handle = msg->handle;
|
||||
|
||||
if (msg->signum == handle->signum) {
|
||||
assert(!(handle->flags & UV_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
handle->signal_cb(handle, handle->signum);
|
||||
}
|
||||
|
||||
handle->dispatched_signals++;
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv__signal_stop(handle);
|
||||
|
||||
/* If uv_close was called while there were caught signals that were not
|
||||
* yet dispatched, the uv__finish_close was deferred. Make close pending
|
||||
* now if this has happened.
|
||||
*/
|
||||
if ((handle->flags & UV_CLOSING) &&
|
||||
if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
(handle->caught_signals == handle->dispatched_signals)) {
|
||||
uv__make_close_pending((uv_handle_t*) handle);
|
||||
}
|
||||
@@ -496,11 +505,11 @@ static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first
|
||||
/* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
|
||||
* handler returned is a one-shot handler, the rest will be too.
|
||||
*/
|
||||
f1 = w1->flags & UV__SIGNAL_ONE_SHOT;
|
||||
f2 = w2->flags & UV__SIGNAL_ONE_SHOT;
|
||||
f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
|
||||
f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (f1 < f2) return -1;
|
||||
if (f1 > f2) return 1;
|
||||
|
||||
@@ -549,8 +558,8 @@ static void uv__signal_stop(uv_signal_t* handle) {
|
||||
if (first_handle == NULL) {
|
||||
uv__signal_unregister_handler(handle->signum);
|
||||
} else {
|
||||
rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT;
|
||||
first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT;
|
||||
rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
|
||||
if (first_oneshot && !rem_oneshot) {
|
||||
ret = uv__signal_register_handler(handle->signum, 1);
|
||||
assert(ret == 0);
|
||||
|
||||
@@ -58,11 +58,19 @@ struct uv__stream_select_s {
|
||||
fd_set* swrite;
|
||||
size_t swrite_sz;
|
||||
};
|
||||
# define WRITE_RETRY_ON_ERROR(send_handle) \
|
||||
|
||||
/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
|
||||
(errno == EMSGSIZE && send_handle))
|
||||
(errno == EMSGSIZE && send_handle != NULL))
|
||||
#else
|
||||
# define WRITE_RETRY_ON_ERROR(send_handle) \
|
||||
# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
|
||||
# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
@@ -220,7 +228,7 @@ static void uv__stream_osx_select(void* arg) {
|
||||
uv_sem_wait(&s->async_sem);
|
||||
|
||||
/* Should be processed at this stage */
|
||||
assert((s->events == 0) || (stream->flags & UV_CLOSING));
|
||||
assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +256,7 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) {
|
||||
if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
|
||||
if (stream->flags & UV_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return;
|
||||
|
||||
/* NOTE: It is important to do it here, otherwise `select()` might be called
|
||||
@@ -342,7 +350,7 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd) {
|
||||
if (err)
|
||||
goto failed_async_init;
|
||||
|
||||
s->async.flags |= UV__HANDLE_INTERNAL;
|
||||
s->async.flags |= UV_HANDLE_INTERNAL;
|
||||
uv__handle_unref(&s->async);
|
||||
|
||||
err = uv_sem_init(&s->close_sem, 0);
|
||||
@@ -407,12 +415,14 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
|
||||
stream->flags |= flags;
|
||||
|
||||
if (stream->type == UV_TCP) {
|
||||
if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
|
||||
if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
|
||||
return UV__ERR(errno);
|
||||
|
||||
/* TODO Use delay the user passed in. */
|
||||
if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
|
||||
if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) &&
|
||||
uv__tcp_keepalive(fd, 1, 60)) {
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -447,7 +457,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
|
||||
|
||||
void uv__stream_destroy(uv_stream_t* stream) {
|
||||
assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
|
||||
assert(stream->flags & UV_CLOSED);
|
||||
assert(stream->flags & UV_HANDLE_CLOSED);
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__req_unregister(stream->loop, stream->connect_req);
|
||||
@@ -522,7 +532,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
stream = container_of(w, uv_stream_t, io_watcher);
|
||||
assert(events & POLLIN);
|
||||
assert(stream->accepted_fd == -1);
|
||||
assert(!(stream->flags & UV_CLOSING));
|
||||
assert(!(stream->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
|
||||
|
||||
@@ -565,7 +575,8 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
|
||||
if (stream->type == UV_TCP &&
|
||||
(stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
|
||||
/* Give other processes a chance to accept connections. */
|
||||
struct timespec timeout = { 0, 1 };
|
||||
nanosleep(&timeout, NULL);
|
||||
@@ -590,7 +601,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) {
|
||||
case UV_TCP:
|
||||
err = uv__stream_open(client,
|
||||
server->accepted_fd,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
if (err) {
|
||||
/* TODO handle error */
|
||||
uv__close(server->accepted_fd);
|
||||
@@ -674,14 +685,14 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
|
||||
/* Shutdown? */
|
||||
if ((stream->flags & UV_STREAM_SHUTTING) &&
|
||||
!(stream->flags & UV_CLOSING) &&
|
||||
!(stream->flags & UV_STREAM_SHUT)) {
|
||||
if ((stream->flags & UV_HANDLE_SHUTTING) &&
|
||||
!(stream->flags & UV_HANDLE_CLOSING) &&
|
||||
!(stream->flags & UV_HANDLE_SHUT)) {
|
||||
assert(stream->shutdown_req);
|
||||
|
||||
req = stream->shutdown_req;
|
||||
stream->shutdown_req = NULL;
|
||||
stream->flags &= ~UV_STREAM_SHUTTING;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
uv__req_unregister(stream->loop, req);
|
||||
|
||||
err = 0;
|
||||
@@ -689,7 +700,7 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
err = UV__ERR(errno);
|
||||
|
||||
if (err == 0)
|
||||
stream->flags |= UV_STREAM_SHUT;
|
||||
stream->flags |= UV_HANDLE_SHUT;
|
||||
|
||||
if (req->cb != NULL)
|
||||
req->cb(req, err);
|
||||
@@ -697,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) {
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) {
|
||||
if (n == 1)
|
||||
return write(fd, vec->iov_base, vec->iov_len);
|
||||
else
|
||||
return writev(fd, vec, n);
|
||||
}
|
||||
|
||||
|
||||
static size_t uv__write_req_size(uv_write_t* req) {
|
||||
size_t size;
|
||||
|
||||
@@ -709,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) {
|
||||
}
|
||||
|
||||
|
||||
/* Returns 1 if all write request data has been written, or 0 if there is still
|
||||
* more data to write.
|
||||
*
|
||||
* Note: the return value only says something about the *current* request.
|
||||
* There may still be other write requests sitting in the queue.
|
||||
*/
|
||||
static int uv__write_req_update(uv_stream_t* stream,
|
||||
uv_write_t* req,
|
||||
size_t n) {
|
||||
uv_buf_t* buf;
|
||||
size_t len;
|
||||
|
||||
assert(n <= stream->write_queue_size);
|
||||
stream->write_queue_size -= n;
|
||||
|
||||
buf = req->bufs + req->write_index;
|
||||
|
||||
while (n > 0) {
|
||||
len = n < buf->len ? n : buf->len;
|
||||
buf->base += len;
|
||||
buf->len -= len;
|
||||
buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */
|
||||
n -= len;
|
||||
}
|
||||
|
||||
req->write_index = buf - req->bufs;
|
||||
|
||||
return req->write_index == req->nbufs;
|
||||
}
|
||||
|
||||
|
||||
static void uv__write_req_finish(uv_write_t* req) {
|
||||
uv_stream_t* stream = req->handle;
|
||||
|
||||
@@ -829,102 +879,32 @@ start:
|
||||
*pi = fd_to_send;
|
||||
}
|
||||
|
||||
do {
|
||||
do
|
||||
n = sendmsg(uv__stream_fd(stream), &msg, 0);
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
/*
|
||||
* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
|
||||
#else
|
||||
while (n == -1 && errno == EINTR);
|
||||
#endif
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
|
||||
/* Ensure the handle isn't sent again in case this is a partial write. */
|
||||
if (n >= 0)
|
||||
req->send_handle = NULL;
|
||||
} else {
|
||||
do {
|
||||
if (iovcnt == 1) {
|
||||
n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
|
||||
} else {
|
||||
n = writev(uv__stream_fd(stream), iov, iovcnt);
|
||||
}
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
/*
|
||||
* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
|
||||
* EPROTOTYPE can be returned while trying to write to a socket that is
|
||||
* shutting down. If we retry the write, we should get the expected EPIPE
|
||||
* instead.
|
||||
*/
|
||||
while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
|
||||
#else
|
||||
while (n == -1 && errno == EINTR);
|
||||
#endif
|
||||
do
|
||||
n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
|
||||
while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
if (!WRITE_RETRY_ON_ERROR(req->send_handle)) {
|
||||
err = UV__ERR(errno);
|
||||
goto error;
|
||||
} else if (stream->flags & UV_STREAM_BLOCKING) {
|
||||
/* If this is a blocking stream, try again. */
|
||||
goto start;
|
||||
}
|
||||
} else {
|
||||
/* Successful write */
|
||||
|
||||
while (n >= 0) {
|
||||
uv_buf_t* buf = &(req->bufs[req->write_index]);
|
||||
size_t len = buf->len;
|
||||
|
||||
assert(req->write_index < req->nbufs);
|
||||
|
||||
if ((size_t)n < len) {
|
||||
buf->base += n;
|
||||
buf->len -= n;
|
||||
stream->write_queue_size -= n;
|
||||
n = 0;
|
||||
|
||||
/* There is more to write. */
|
||||
if (stream->flags & UV_STREAM_BLOCKING) {
|
||||
/*
|
||||
* If we're blocking then we should not be enabling the write
|
||||
* watcher - instead we need to try again.
|
||||
*/
|
||||
goto start;
|
||||
} else {
|
||||
/* Break loop and ensure the watcher is pending. */
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Finished writing the buf at index req->write_index. */
|
||||
req->write_index++;
|
||||
|
||||
assert((size_t)n >= len);
|
||||
n -= len;
|
||||
|
||||
assert(stream->write_queue_size >= len);
|
||||
stream->write_queue_size -= len;
|
||||
|
||||
if (req->write_index == req->nbufs) {
|
||||
/* Then we're done! */
|
||||
assert(n == 0);
|
||||
uv__write_req_finish(req);
|
||||
/* TODO: start trying to write the next request. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
|
||||
err = UV__ERR(errno);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Either we've counted n down to zero or we've got EAGAIN. */
|
||||
assert(n == 0 || n == -1);
|
||||
if (n > 0 && uv__write_req_update(stream, req, n)) {
|
||||
uv__write_req_finish(req);
|
||||
return; /* TODO(bnoordhuis) Start trying to write the next request. */
|
||||
}
|
||||
|
||||
/* Only non-blocking streams should use the write_watcher. */
|
||||
assert(!(stream->flags & UV_STREAM_BLOCKING));
|
||||
/* If this is a blocking stream, try again. */
|
||||
if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
|
||||
goto start;
|
||||
|
||||
/* We're not done. */
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
@@ -947,10 +927,16 @@ error:
|
||||
static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
uv_write_t* req;
|
||||
QUEUE* q;
|
||||
QUEUE pq;
|
||||
|
||||
while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
|
||||
if (QUEUE_EMPTY(&stream->write_completed_queue))
|
||||
return;
|
||||
|
||||
QUEUE_MOVE(&stream->write_completed_queue, &pq);
|
||||
|
||||
while (!QUEUE_EMPTY(&pq)) {
|
||||
/* Pop a req off write_completed_queue. */
|
||||
q = QUEUE_HEAD(&stream->write_completed_queue);
|
||||
q = QUEUE_HEAD(&pq);
|
||||
req = QUEUE_DATA(q, uv_write_t, queue);
|
||||
QUEUE_REMOVE(q);
|
||||
uv__req_unregister(stream->loop, req);
|
||||
@@ -966,8 +952,6 @@ static void uv__write_callbacks(uv_stream_t* stream) {
|
||||
if (req->cb)
|
||||
req->cb(req, req->error);
|
||||
}
|
||||
|
||||
assert(QUEUE_EMPTY(&stream->write_completed_queue));
|
||||
}
|
||||
|
||||
|
||||
@@ -1015,13 +999,13 @@ uv_handle_type uv__handle_type(int fd) {
|
||||
|
||||
|
||||
static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
|
||||
stream->flags |= UV_STREAM_READ_EOF;
|
||||
stream->flags |= UV_HANDLE_READ_EOF;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
stream->read_cb(stream, UV_EOF, buf);
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
}
|
||||
|
||||
|
||||
@@ -1121,6 +1105,7 @@ static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wgnu-folding-constant"
|
||||
# pragma clang diagnostic ignored "-Wvla-extension"
|
||||
#endif
|
||||
|
||||
static void uv__read(uv_stream_t* stream) {
|
||||
@@ -1132,7 +1117,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
int err;
|
||||
int is_ipc;
|
||||
|
||||
stream->flags &= ~UV_STREAM_READ_PARTIAL;
|
||||
stream->flags &= ~UV_HANDLE_READ_PARTIAL;
|
||||
|
||||
/* Prevent loop starvation when the data comes in as fast as (or faster than)
|
||||
* we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
|
||||
@@ -1141,11 +1126,11 @@ static void uv__read(uv_stream_t* stream) {
|
||||
|
||||
is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
|
||||
|
||||
/* XXX: Maybe instead of having UV_STREAM_READING we just test if
|
||||
/* XXX: Maybe instead of having UV_HANDLE_READING we just test if
|
||||
* tcp->read_cb is NULL or not?
|
||||
*/
|
||||
while (stream->read_cb
|
||||
&& (stream->flags & UV_STREAM_READING)
|
||||
&& (stream->flags & UV_HANDLE_READING)
|
||||
&& (count-- > 0)) {
|
||||
assert(stream->alloc_cb != NULL);
|
||||
|
||||
@@ -1186,7 +1171,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
/* Error */
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
/* Wait for the next one. */
|
||||
if (stream->flags & UV_STREAM_READING) {
|
||||
if (stream->flags & UV_HANDLE_READING) {
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
@@ -1199,8 +1184,8 @@ static void uv__read(uv_stream_t* stream) {
|
||||
} else {
|
||||
/* Error. User should call uv_close(). */
|
||||
stream->read_cb(stream, UV__ERR(errno), &buf);
|
||||
if (stream->flags & UV_STREAM_READING) {
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
if (stream->flags & UV_HANDLE_READING) {
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
@@ -1250,7 +1235,7 @@ static void uv__read(uv_stream_t* stream) {
|
||||
|
||||
/* Return if we didn't fill the buffer, there is no more data to read. */
|
||||
if (nread < buflen) {
|
||||
stream->flags |= UV_STREAM_READ_PARTIAL;
|
||||
stream->flags |= UV_HANDLE_READ_PARTIAL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1271,9 +1256,9 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
stream->type == UV_TTY ||
|
||||
stream->type == UV_NAMED_PIPE);
|
||||
|
||||
if (!(stream->flags & UV_STREAM_WRITABLE) ||
|
||||
stream->flags & UV_STREAM_SHUT ||
|
||||
stream->flags & UV_STREAM_SHUTTING ||
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE) ||
|
||||
stream->flags & UV_HANDLE_SHUT ||
|
||||
stream->flags & UV_HANDLE_SHUTTING ||
|
||||
uv__is_closing(stream)) {
|
||||
return UV_ENOTCONN;
|
||||
}
|
||||
@@ -1285,7 +1270,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
|
||||
req->handle = stream;
|
||||
req->cb = cb;
|
||||
stream->shutdown_req = req;
|
||||
stream->flags |= UV_STREAM_SHUTTING;
|
||||
stream->flags |= UV_HANDLE_SHUTTING;
|
||||
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
@@ -1302,7 +1287,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
assert(stream->type == UV_TCP ||
|
||||
stream->type == UV_NAMED_PIPE ||
|
||||
stream->type == UV_TTY);
|
||||
assert(!(stream->flags & UV_CLOSING));
|
||||
assert(!(stream->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
if (stream->connect_req) {
|
||||
uv__stream_connect(stream);
|
||||
@@ -1311,7 +1296,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
|
||||
assert(uv__stream_fd(stream) >= 0);
|
||||
|
||||
/* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
|
||||
/* Ignore POLLHUP here. Even if it's set, there may still be data to read. */
|
||||
if (events & (POLLIN | POLLERR | POLLHUP))
|
||||
uv__read(stream);
|
||||
|
||||
@@ -1325,9 +1310,9 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
|
||||
* report the EOF yet because there is still data to read.
|
||||
*/
|
||||
if ((events & POLLHUP) &&
|
||||
(stream->flags & UV_STREAM_READING) &&
|
||||
(stream->flags & UV_STREAM_READ_PARTIAL) &&
|
||||
!(stream->flags & UV_STREAM_READ_EOF)) {
|
||||
(stream->flags & UV_HANDLE_READING) &&
|
||||
(stream->flags & UV_HANDLE_READ_PARTIAL) &&
|
||||
!(stream->flags & UV_HANDLE_READ_EOF)) {
|
||||
uv_buf_t buf = { NULL, 0 };
|
||||
uv__stream_eof(stream, &buf);
|
||||
}
|
||||
@@ -1417,7 +1402,7 @@ int uv_write2(uv_write_t* req,
|
||||
if (uv__stream_fd(stream) < 0)
|
||||
return UV_EBADF;
|
||||
|
||||
if (!(stream->flags & UV_STREAM_WRITABLE))
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return -EPIPE;
|
||||
|
||||
if (send_handle) {
|
||||
@@ -1487,7 +1472,7 @@ int uv_write2(uv_write_t* req,
|
||||
* if this assert fires then somehow the blocking stream isn't being
|
||||
* sufficiently flushed in uv__write.
|
||||
*/
|
||||
assert(!(stream->flags & UV_STREAM_BLOCKING));
|
||||
assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES));
|
||||
uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
|
||||
uv__stream_osx_interrupt_select(stream);
|
||||
}
|
||||
@@ -1568,16 +1553,16 @@ int uv_read_start(uv_stream_t* stream,
|
||||
assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
|
||||
stream->type == UV_TTY);
|
||||
|
||||
if (stream->flags & UV_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (!(stream->flags & UV_STREAM_READABLE))
|
||||
if (!(stream->flags & UV_HANDLE_READABLE))
|
||||
return -ENOTCONN;
|
||||
|
||||
/* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
|
||||
/* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
|
||||
* expresses the desired state of the user.
|
||||
*/
|
||||
stream->flags |= UV_STREAM_READING;
|
||||
stream->flags |= UV_HANDLE_READING;
|
||||
|
||||
/* TODO: try to do the read inline? */
|
||||
/* TODO: keep track of tcp state. If we've gotten a EOF then we should
|
||||
@@ -1598,10 +1583,10 @@ int uv_read_start(uv_stream_t* stream,
|
||||
|
||||
|
||||
int uv_read_stop(uv_stream_t* stream) {
|
||||
if (!(stream->flags & UV_STREAM_READING))
|
||||
if (!(stream->flags & UV_HANDLE_READING))
|
||||
return 0;
|
||||
|
||||
stream->flags &= ~UV_STREAM_READING;
|
||||
stream->flags &= ~UV_HANDLE_READING;
|
||||
uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
|
||||
if (!uv__io_active(&stream->io_watcher, POLLOUT))
|
||||
uv__handle_stop(stream);
|
||||
@@ -1614,12 +1599,12 @@ int uv_read_stop(uv_stream_t* stream) {
|
||||
|
||||
|
||||
int uv_is_readable(const uv_stream_t* stream) {
|
||||
return !!(stream->flags & UV_STREAM_READABLE);
|
||||
return !!(stream->flags & UV_HANDLE_READABLE);
|
||||
}
|
||||
|
||||
|
||||
int uv_is_writable(const uv_stream_t* stream) {
|
||||
return !!(stream->flags & UV_STREAM_WRITABLE);
|
||||
return !!(stream->flags & UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1668,6 +1653,7 @@ void uv__stream_close(uv_stream_t* handle) {
|
||||
uv__io_close(handle->loop, &handle->io_watcher);
|
||||
uv_read_stop(handle);
|
||||
uv__handle_stop(handle);
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
|
||||
if (handle->io_watcher.fd != -1) {
|
||||
/* Don't close stdio file descriptors. Nothing good comes from it. */
|
||||
|
||||
@@ -696,6 +696,8 @@ void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
|
||||
|
||||
#ifdef SUNOS_NO_IFADDRS
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
#else /* SUNOS_NO_IFADDRS */
|
||||
@@ -709,13 +711,14 @@ static int uv__set_phys_addr(uv_interface_address_t* address,
|
||||
|
||||
struct sockaddr_dl* sa_addr;
|
||||
int sockfd;
|
||||
int i;
|
||||
size_t i;
|
||||
struct arpreq arpreq;
|
||||
|
||||
/* This appears to only work as root */
|
||||
sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
|
||||
memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
|
||||
for (i = 0; i < sizeof(address->phys_addr); i++) {
|
||||
/* Check that all bytes of phys_addr are zero. */
|
||||
if (address->phys_addr[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
@@ -762,11 +765,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifaddrs* addrs;
|
||||
struct ifaddrs* ent;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
if (getifaddrs(&addrs))
|
||||
return UV__ERR(errno);
|
||||
|
||||
*count = 0;
|
||||
|
||||
/* Count the number of interfaces */
|
||||
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
||||
if (uv__ifaddr_exclude(ent))
|
||||
@@ -774,6 +778,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
freeifaddrs(addrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*addresses = uv__malloc(*count * sizeof(**addresses));
|
||||
if (!(*addresses)) {
|
||||
freeifaddrs(addrs);
|
||||
|
||||
@@ -216,7 +216,7 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
|
||||
err = maybe_new_socket(handle,
|
||||
addr->sa_family,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -263,13 +263,16 @@ int uv__tcp_connect(uv_connect_t* req,
|
||||
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
||||
int err;
|
||||
|
||||
if (uv__fd_exists(handle->loop, sock))
|
||||
return UV_EEXIST;
|
||||
|
||||
err = uv__nonblock(sock, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return uv__stream_open((uv_stream_t*)handle,
|
||||
sock,
|
||||
UV_STREAM_READABLE | UV_STREAM_WRITABLE);
|
||||
UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -331,7 +334,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
||||
}
|
||||
|
||||
if (single_accept)
|
||||
tcp->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
|
||||
flags = 0;
|
||||
#if defined(__MVS__)
|
||||
@@ -398,9 +401,9 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_NODELAY;
|
||||
handle->flags |= UV_HANDLE_TCP_NODELAY;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_NODELAY;
|
||||
handle->flags &= ~UV_HANDLE_TCP_NODELAY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -416,9 +419,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
}
|
||||
|
||||
if (on)
|
||||
handle->flags |= UV_TCP_KEEPALIVE;
|
||||
handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
|
||||
else
|
||||
handle->flags &= ~UV_TCP_KEEPALIVE;
|
||||
handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
|
||||
|
||||
/* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
|
||||
* uv_tcp_t with an int that's almost never used...
|
||||
@@ -430,9 +433,9 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
||||
|
||||
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
if (enable)
|
||||
handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
|
||||
handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
else
|
||||
handle->flags |= UV_TCP_SINGLE_ACCEPT;
|
||||
handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,108 +44,119 @@
|
||||
#undef NANOSEC
|
||||
#define NANOSEC ((uint64_t) 1e9)
|
||||
|
||||
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
|
||||
#endif
|
||||
|
||||
#if defined(UV__PTHREAD_BARRIER_FALLBACK)
|
||||
/* TODO: support barrier_attr */
|
||||
int pthread_barrier_init(pthread_barrier_t* barrier,
|
||||
const void* barrier_attr,
|
||||
unsigned count) {
|
||||
/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */
|
||||
#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
struct _uv_barrier* b;
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || count == 0)
|
||||
return EINVAL;
|
||||
|
||||
if (barrier_attr != NULL)
|
||||
return ENOTSUP;
|
||||
return UV_EINVAL;
|
||||
|
||||
b = uv__malloc(sizeof(*b));
|
||||
if (b == NULL)
|
||||
return ENOMEM;
|
||||
return UV_ENOMEM;
|
||||
|
||||
b->in = 0;
|
||||
b->out = 0;
|
||||
b->threshold = count;
|
||||
|
||||
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
|
||||
rc = uv_mutex_init(&b->mutex);
|
||||
if (rc != 0)
|
||||
goto error2;
|
||||
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
|
||||
|
||||
rc = uv_cond_init(&b->cond);
|
||||
if (rc != 0)
|
||||
goto error;
|
||||
|
||||
barrier->b = b;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
error2:
|
||||
uv__free(b);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pthread_barrier_wait(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
int last;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
return UV_EINVAL;
|
||||
|
||||
b = barrier->b;
|
||||
/* Lock the mutex*/
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
/* Increment the count. If this is the first thread to reach the threshold,
|
||||
wake up waiters, unlock the mutex, then return
|
||||
PTHREAD_BARRIER_SERIAL_THREAD. */
|
||||
if (++b->in == b->threshold) {
|
||||
b->in = 0;
|
||||
b->out = b->threshold - 1;
|
||||
rc = pthread_cond_signal(&b->cond);
|
||||
assert(rc == 0);
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
b->out = b->threshold;
|
||||
uv_cond_signal(&b->cond);
|
||||
} else {
|
||||
do
|
||||
uv_cond_wait(&b->cond, &b->mutex);
|
||||
while (b->in != 0);
|
||||
}
|
||||
/* Otherwise, wait for other threads until in is set to 0,
|
||||
then return 0 to indicate this is not the first thread. */
|
||||
do {
|
||||
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
|
||||
break;
|
||||
} while (b->in != 0);
|
||||
|
||||
/* mark thread exit */
|
||||
b->out--;
|
||||
pthread_cond_signal(&b->cond);
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
return rc;
|
||||
last = (--b->out == 0);
|
||||
if (!last)
|
||||
uv_cond_signal(&b->cond); /* Not needed for last thread. */
|
||||
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
return last;
|
||||
}
|
||||
|
||||
int pthread_barrier_destroy(pthread_barrier_t* barrier) {
|
||||
int rc;
|
||||
_uv_barrier* b;
|
||||
|
||||
if (barrier == NULL || barrier->b == NULL)
|
||||
return EINVAL;
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
struct _uv_barrier* b;
|
||||
|
||||
b = barrier->b;
|
||||
uv_mutex_lock(&b->mutex);
|
||||
|
||||
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
|
||||
return rc;
|
||||
assert(b->in == 0);
|
||||
assert(b->out == 0);
|
||||
|
||||
if (b->in > 0 || b->out > 0)
|
||||
rc = EBUSY;
|
||||
if (b->in != 0 || b->out != 0)
|
||||
abort();
|
||||
|
||||
pthread_mutex_unlock(&b->mutex);
|
||||
uv_mutex_unlock(&b->mutex);
|
||||
uv_mutex_destroy(&b->mutex);
|
||||
uv_cond_destroy(&b->cond);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pthread_cond_destroy(&b->cond);
|
||||
pthread_mutex_destroy(&b->mutex);
|
||||
uv__free(barrier->b);
|
||||
barrier->b = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int rc;
|
||||
|
||||
rc = pthread_barrier_wait(barrier);
|
||||
if (rc != 0)
|
||||
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
|
||||
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -771,25 +782,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
if (pthread_barrier_destroy(barrier))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int r = pthread_barrier_wait(barrier);
|
||||
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
|
||||
abort();
|
||||
return r == PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
|
||||
|
||||
int uv_key_create(uv_key_t* key) {
|
||||
return UV__ERR(pthread_key_create(key, NULL));
|
||||
}
|
||||
|
||||
@@ -92,13 +92,15 @@ static int uv__tty_is_slave(const int fd) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
|
||||
uv_handle_type type;
|
||||
int flags = 0;
|
||||
int newfd = -1;
|
||||
int r;
|
||||
int saved_flags;
|
||||
int mode;
|
||||
char path[256];
|
||||
(void)unused; /* deprecated parameter is no longer needed */
|
||||
|
||||
/* File descriptors that refer to files cannot be monitored with epoll.
|
||||
* That restriction also applies to character devices like /dev/random
|
||||
@@ -108,6 +110,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1)
|
||||
return UV__ERR(errno);
|
||||
mode = saved_flags & O_ACCMODE;
|
||||
|
||||
/* Reopen the file descriptor when it refers to a tty. This lets us put the
|
||||
* tty in non-blocking mode without affecting other processes that share it
|
||||
* with us.
|
||||
@@ -125,14 +136,14 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
* slave device.
|
||||
*/
|
||||
if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
|
||||
r = uv__open_cloexec(path, O_RDWR);
|
||||
r = uv__open_cloexec(path, mode);
|
||||
else
|
||||
r = -1;
|
||||
|
||||
if (r < 0) {
|
||||
/* fallback to using blocking writes */
|
||||
if (!readable)
|
||||
flags |= UV_STREAM_BLOCKING;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_BLOCKING_WRITES;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
@@ -151,22 +162,6 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
|
||||
fd = newfd;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
/* Save the fd flags in case we need to restore them due to an error. */
|
||||
do
|
||||
saved_flags = fcntl(fd, F_GETFL);
|
||||
while (saved_flags == -1 && errno == EINTR);
|
||||
|
||||
if (saved_flags == -1) {
|
||||
if (newfd != -1)
|
||||
uv__close(newfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pacify the compiler. */
|
||||
(void) &saved_flags;
|
||||
|
||||
skip:
|
||||
uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
|
||||
@@ -174,7 +169,7 @@ skip:
|
||||
* the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
||||
*/
|
||||
|
||||
if (!(flags & UV_STREAM_BLOCKING))
|
||||
if (!(flags & UV_HANDLE_BLOCKING_WRITES))
|
||||
uv__nonblock(fd, 1);
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -191,10 +186,10 @@ skip:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (readable)
|
||||
flags |= UV_STREAM_READABLE;
|
||||
else
|
||||
flags |= UV_STREAM_WRITABLE;
|
||||
if (mode != O_WRONLY)
|
||||
flags |= UV_HANDLE_READABLE;
|
||||
if (mode != O_RDONLY)
|
||||
flags |= UV_HANDLE_WRITABLE;
|
||||
|
||||
uv__stream_open((uv_stream_t*) tty, fd, flags);
|
||||
tty->mode = UV_TTY_MODE_NORMAL;
|
||||
|
||||
@@ -92,8 +92,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv_udp_send_t* req;
|
||||
QUEUE* q;
|
||||
|
||||
assert(!(handle->flags & UV_UDP_PROCESSING));
|
||||
handle->flags |= UV_UDP_PROCESSING;
|
||||
assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
|
||||
handle->flags |= UV_HANDLE_UDP_PROCESSING;
|
||||
|
||||
while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
|
||||
q = QUEUE_HEAD(&handle->write_completed_queue);
|
||||
@@ -128,7 +128,7 @@ static void uv__udp_run_completed(uv_udp_t* handle) {
|
||||
uv__handle_stop(handle);
|
||||
}
|
||||
|
||||
handle->flags &= ~UV_UDP_PROCESSING;
|
||||
handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
|
||||
}
|
||||
|
||||
|
||||
@@ -427,7 +427,7 @@ int uv__udp_send(uv_udp_send_t* req,
|
||||
QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
|
||||
uv__handle_start(handle);
|
||||
|
||||
if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
|
||||
if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
|
||||
uv__udp_sendmsg(handle);
|
||||
|
||||
/* `uv__udp_sendmsg` may not be able to do non-blocking write straight
|
||||
@@ -624,6 +624,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
if (handle->io_watcher.fd != -1)
|
||||
return UV_EBUSY;
|
||||
|
||||
if (uv__fd_exists(handle->loop, sock))
|
||||
return UV_EEXIST;
|
||||
|
||||
err = uv__nonblock(sock, 1);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -757,14 +760,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
|
||||
* IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
IPV6_MULTICAST_HOPS,
|
||||
&ttl,
|
||||
sizeof(ttl));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_TTL,
|
||||
@@ -780,14 +785,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
|
||||
* IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
|
||||
* and use the general uv__setsockopt_maybe_char call otherwise.
|
||||
*/
|
||||
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
|
||||
defined(__MVS__)
|
||||
if (handle->flags & UV_HANDLE_IPV6)
|
||||
return uv__setsockopt(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
IPV6_MULTICAST_LOOP,
|
||||
&on,
|
||||
sizeof(on));
|
||||
#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
|
||||
#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
|
||||
defined(__MVS__) */
|
||||
|
||||
return uv__setsockopt_maybe_char(handle,
|
||||
IP_MULTICAST_LOOP,
|
||||
|
||||
@@ -72,7 +72,9 @@ char* uv__strndup(const char* s, size_t n) {
|
||||
}
|
||||
|
||||
void* uv__malloc(size_t size) {
|
||||
return uv__allocator.local_malloc(size);
|
||||
if (size > 0)
|
||||
return uv__allocator.local_malloc(size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void uv__free(void* ptr) {
|
||||
@@ -91,7 +93,10 @@ void* uv__calloc(size_t count, size_t size) {
|
||||
}
|
||||
|
||||
void* uv__realloc(void* ptr, size_t size) {
|
||||
return uv__allocator.local_realloc(ptr, size);
|
||||
if (size > 0)
|
||||
return uv__allocator.local_realloc(ptr, size);
|
||||
uv__free(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uv_replace_allocator(uv_malloc_func malloc_func,
|
||||
@@ -155,6 +160,18 @@ static const char* uv__unknown_err_code(int err) {
|
||||
return copy != NULL ? copy : "Unknown system error";
|
||||
}
|
||||
|
||||
#define UV_ERR_NAME_GEN_R(name, _) \
|
||||
case UV_## name: \
|
||||
uv__strscpy(buf, #name, buflen); break;
|
||||
char* uv_err_name_r(int err, char* buf, size_t buflen) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
|
||||
default: snprintf(buf, buflen, "Unknown system error %d", err);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#undef UV_ERR_NAME_GEN_R
|
||||
|
||||
|
||||
#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
|
||||
const char* uv_err_name(int err) {
|
||||
@@ -166,6 +183,19 @@ const char* uv_err_name(int err) {
|
||||
#undef UV_ERR_NAME_GEN
|
||||
|
||||
|
||||
#define UV_STRERROR_GEN_R(name, msg) \
|
||||
case UV_ ## name: \
|
||||
snprintf(buf, buflen, "%s", msg); break;
|
||||
char* uv_strerror_r(int err, char* buf, size_t buflen) {
|
||||
switch (err) {
|
||||
UV_ERRNO_MAP(UV_STRERROR_GEN_R)
|
||||
default: snprintf(buf, buflen, "Unknown system error %d", err);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
#undef UV_STRERROR_GEN_R
|
||||
|
||||
|
||||
#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
|
||||
const char* uv_strerror(int err) {
|
||||
switch (err) {
|
||||
@@ -359,7 +389,7 @@ void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
|
||||
QUEUE_REMOVE(q);
|
||||
QUEUE_INSERT_TAIL(&loop->handle_queue, q);
|
||||
|
||||
if (h->flags & UV__HANDLE_INTERNAL) continue;
|
||||
if (h->flags & UV_HANDLE_INTERNAL) continue;
|
||||
walk_cb(h, arg);
|
||||
}
|
||||
}
|
||||
@@ -388,9 +418,9 @@ static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
|
||||
|
||||
fprintf(stream,
|
||||
"[%c%c%c] %-8s %p\n",
|
||||
"R-"[!(h->flags & UV__HANDLE_REF)],
|
||||
"A-"[!(h->flags & UV__HANDLE_ACTIVE)],
|
||||
"I-"[!(h->flags & UV__HANDLE_INTERNAL)],
|
||||
"R-"[!(h->flags & UV_HANDLE_REF)],
|
||||
"A-"[!(h->flags & UV_HANDLE_ACTIVE)],
|
||||
"I-"[!(h->flags & UV_HANDLE_INTERNAL)],
|
||||
type,
|
||||
(void*)h);
|
||||
}
|
||||
@@ -634,7 +664,7 @@ int uv_loop_close(uv_loop_t* loop) {
|
||||
|
||||
QUEUE_FOREACH(q, &loop->handle_queue) {
|
||||
h = QUEUE_DATA(q, uv_handle_t, handle_queue);
|
||||
if (!(h->flags & UV__HANDLE_INTERNAL))
|
||||
if (!(h->flags & UV_HANDLE_INTERNAL))
|
||||
return UV_EBUSY;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,14 +32,15 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "tree.h"
|
||||
#include "uv/tree.h"
|
||||
#include "queue.h"
|
||||
#include "strscpy.h"
|
||||
|
||||
#if EDOM > 0
|
||||
# define UV__ERR(x) (-(x))
|
||||
@@ -59,22 +60,67 @@ extern int snprintf(char*, size_t, const char*, ...);
|
||||
#define STATIC_ASSERT(expr) \
|
||||
void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Handle flags. Some flags are specific to Windows or UNIX. */
|
||||
enum {
|
||||
UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */
|
||||
UV__HANDLE_INTERNAL = 0x8000,
|
||||
UV__HANDLE_ACTIVE = 0x4000,
|
||||
UV__HANDLE_REF = 0x2000,
|
||||
UV__HANDLE_CLOSING = 0 /* no-op on unix */
|
||||
/* Used by all handles. */
|
||||
UV_HANDLE_CLOSING = 0x00000001,
|
||||
UV_HANDLE_CLOSED = 0x00000002,
|
||||
UV_HANDLE_ACTIVE = 0x00000004,
|
||||
UV_HANDLE_REF = 0x00000008,
|
||||
UV_HANDLE_INTERNAL = 0x00000010,
|
||||
UV_HANDLE_ENDGAME_QUEUED = 0x00000020,
|
||||
|
||||
/* Used by streams. */
|
||||
UV_HANDLE_LISTENING = 0x00000040,
|
||||
UV_HANDLE_CONNECTION = 0x00000080,
|
||||
UV_HANDLE_SHUTTING = 0x00000100,
|
||||
UV_HANDLE_SHUT = 0x00000200,
|
||||
UV_HANDLE_READ_PARTIAL = 0x00000400,
|
||||
UV_HANDLE_READ_EOF = 0x00000800,
|
||||
|
||||
/* Used by streams and UDP handles. */
|
||||
UV_HANDLE_READING = 0x00001000,
|
||||
UV_HANDLE_BOUND = 0x00002000,
|
||||
UV_HANDLE_READABLE = 0x00004000,
|
||||
UV_HANDLE_WRITABLE = 0x00008000,
|
||||
UV_HANDLE_READ_PENDING = 0x00010000,
|
||||
UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000,
|
||||
UV_HANDLE_ZERO_READ = 0x00040000,
|
||||
UV_HANDLE_EMULATE_IOCP = 0x00080000,
|
||||
UV_HANDLE_BLOCKING_WRITES = 0x00100000,
|
||||
UV_HANDLE_CANCELLATION_PENDING = 0x00200000,
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
UV_HANDLE_IPV6 = 0x00400000,
|
||||
|
||||
/* Only used by uv_tcp_t handles. */
|
||||
UV_HANDLE_TCP_NODELAY = 0x01000000,
|
||||
UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
|
||||
UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
|
||||
UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
|
||||
UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000,
|
||||
UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
|
||||
|
||||
/* Only used by uv_udp_t handles. */
|
||||
UV_HANDLE_UDP_PROCESSING = 0x01000000,
|
||||
|
||||
/* Only used by uv_pipe_t handles. */
|
||||
UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,
|
||||
UV_HANDLE_PIPESERVER = 0x02000000,
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
UV_HANDLE_TTY_READABLE = 0x01000000,
|
||||
UV_HANDLE_TTY_RAW = 0x02000000,
|
||||
UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
|
||||
UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
|
||||
|
||||
/* Only used by uv_signal_t handles. */
|
||||
UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000,
|
||||
UV_SIGNAL_ONE_SHOT = 0x02000000,
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
UV_HANDLE_POLL_SLOW = 0x01000000
|
||||
};
|
||||
#else
|
||||
# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200
|
||||
# define UV__SIGNAL_ONE_SHOT 0x100
|
||||
# define UV__HANDLE_INTERNAL 0x80
|
||||
# define UV__HANDLE_ACTIVE 0x40
|
||||
# define UV__HANDLE_REF 0x20
|
||||
# define UV__HANDLE_CLOSING 0x01
|
||||
#endif
|
||||
|
||||
int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
|
||||
|
||||
@@ -119,8 +165,15 @@ void uv__fs_poll_close(uv_fs_poll_t* handle);
|
||||
|
||||
int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
|
||||
|
||||
enum uv__work_kind {
|
||||
UV__WORK_CPU,
|
||||
UV__WORK_FAST_IO,
|
||||
UV__WORK_SLOW_IO
|
||||
};
|
||||
|
||||
void uv__work_submit(uv_loop_t* loop,
|
||||
struct uv__work *w,
|
||||
enum uv__work_kind kind,
|
||||
void (*work)(struct uv__work *w),
|
||||
void (*done)(struct uv__work *w, int status));
|
||||
|
||||
@@ -132,6 +185,10 @@ int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
|
||||
|
||||
void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
|
||||
int uv__next_timeout(const uv_loop_t* loop);
|
||||
void uv__run_timers(uv_loop_t* loop);
|
||||
void uv__timer_close(uv_timer_t* handle);
|
||||
|
||||
#define uv__has_active_reqs(loop) \
|
||||
((loop)->active_reqs.count > 0)
|
||||
|
||||
@@ -164,49 +221,47 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
while (0)
|
||||
|
||||
#define uv__is_active(h) \
|
||||
(((h)->flags & UV__HANDLE_ACTIVE) != 0)
|
||||
(((h)->flags & UV_HANDLE_ACTIVE) != 0)
|
||||
|
||||
#define uv__is_closing(h) \
|
||||
(((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
|
||||
(((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
|
||||
|
||||
#define uv__handle_start(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \
|
||||
(h)->flags |= UV_HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_stop(h) \
|
||||
do { \
|
||||
assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \
|
||||
(h)->flags &= ~UV_HANDLE_ACTIVE; \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_ref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) != 0) break; \
|
||||
(h)->flags |= UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
|
||||
if (((h)->flags & UV_HANDLE_REF) != 0) break; \
|
||||
(h)->flags |= UV_HANDLE_REF; \
|
||||
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__handle_unref(h) \
|
||||
do { \
|
||||
if (((h)->flags & UV__HANDLE_REF) == 0) break; \
|
||||
(h)->flags &= ~UV__HANDLE_REF; \
|
||||
if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
|
||||
if (((h)->flags & UV_HANDLE_REF) == 0) break; \
|
||||
(h)->flags &= ~UV_HANDLE_REF; \
|
||||
if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
|
||||
if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define uv__has_ref(h) \
|
||||
(((h)->flags & UV__HANDLE_REF) != 0)
|
||||
(((h)->flags & UV_HANDLE_REF) != 0)
|
||||
|
||||
#if defined(_WIN32)
|
||||
# define uv__handle_platform_init(h) ((h)->u.fd = -1)
|
||||
@@ -218,7 +273,7 @@ void uv__fs_scandir_cleanup(uv_fs_t* req);
|
||||
do { \
|
||||
(h)->loop = (loop_); \
|
||||
(h)->type = (type_); \
|
||||
(h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
|
||||
(h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
|
||||
QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
|
||||
uv__handle_platform_init(h); \
|
||||
} \
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
const char* uv_handle_type_name(uv_handle_type type) {
|
||||
switch (type) {
|
||||
#define XX(uc,lc) case UV_##uc: return #lc;
|
||||
UV_HANDLE_TYPE_MAP(XX)
|
||||
UV_HANDLE_TYPE_MAP(XX)
|
||||
#undef XX
|
||||
case UV_FILE: return "file";
|
||||
case UV_HANDLE_TYPE_MAX:
|
||||
case UV_UNKNOWN_HANDLE: return NULL;
|
||||
case UV_FILE: return "file";
|
||||
case UV_HANDLE_TYPE_MAX:
|
||||
case UV_UNKNOWN_HANDLE: return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -31,10 +31,12 @@ void uv_handle_set_data(uv_handle_t* handle, void* data) {
|
||||
const char* uv_req_type_name(uv_req_type type) {
|
||||
switch (type) {
|
||||
#define XX(uc,lc) case UV_##uc: return #lc;
|
||||
UV_REQ_TYPE_MAP(XX)
|
||||
UV_REQ_TYPE_MAP(XX)
|
||||
#undef XX
|
||||
case UV_REQ_TYPE_MAX:
|
||||
case UV_UNKNOWN_REQ: return NULL;
|
||||
case UV_REQ_TYPE_MAX:
|
||||
case UV_UNKNOWN_REQ:
|
||||
default: /* UV_REQ_TYPE_PRIVATE */
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
!handle->async_sent) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
@@ -71,9 +71,9 @@ int uv_async_send(uv_async_t* handle) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The user should make sure never to call uv_async_send to a closing */
|
||||
/* or closed handle. */
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
/* The user should make sure never to call uv_async_send to a closing or
|
||||
* closed handle. */
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
|
||||
if (!uv__atomic_exchange_set(&handle->async_sent)) {
|
||||
POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
|
||||
@@ -90,7 +90,7 @@ void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
|
||||
|
||||
handle->async_sent = 0;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
} else if (handle->async_cb != NULL) {
|
||||
handle->async_cb(handle);
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
/* Atomic set operation on char */
|
||||
#ifdef _MSC_VER /* MSVC */
|
||||
|
||||
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
|
||||
/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
|
||||
/* exist, and interlocked operations on larger targets might require the */
|
||||
/* target to be aligned. */
|
||||
/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less
|
||||
* efficient than InterlockedExchange, but InterlockedExchange8 does not exist,
|
||||
* and interlocked operations on larger targets might require the target to be
|
||||
* aligned. */
|
||||
#pragma intrinsic(_InterlockedOr8)
|
||||
|
||||
static char INLINE uv__atomic_exchange_set(char volatile* target) {
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "heap-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
/* uv_once initialization guards */
|
||||
@@ -221,6 +222,7 @@ static void uv_init(void) {
|
||||
|
||||
|
||||
int uv_loop_init(uv_loop_t* loop) {
|
||||
struct heap* timer_heap;
|
||||
int err;
|
||||
|
||||
/* Initialize libuv itself first */
|
||||
@@ -246,7 +248,13 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
|
||||
loop->endgame_handles = NULL;
|
||||
|
||||
RB_INIT(&loop->timers);
|
||||
loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
|
||||
if (timer_heap == NULL) {
|
||||
err = UV_ENOMEM;
|
||||
goto fail_timers_alloc;
|
||||
}
|
||||
|
||||
heap_init(timer_heap);
|
||||
|
||||
loop->check_handles = NULL;
|
||||
loop->prepare_handles = NULL;
|
||||
@@ -273,7 +281,7 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
goto fail_async_init;
|
||||
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
loop->wq_async.flags |= UV_HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
@@ -285,6 +293,10 @@ fail_async_init:
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
fail_mutex_init:
|
||||
uv__free(timer_heap);
|
||||
loop->timer_heap = NULL;
|
||||
|
||||
fail_timers_alloc:
|
||||
CloseHandle(loop->iocp);
|
||||
loop->iocp = INVALID_HANDLE_VALUE;
|
||||
|
||||
@@ -292,6 +304,13 @@ fail_mutex_init:
|
||||
}
|
||||
|
||||
|
||||
void uv_update_time(uv_loop_t* loop) {
|
||||
uint64_t new_time = uv__hrtime(1000);
|
||||
assert(new_time >= loop->time);
|
||||
loop->time = new_time;
|
||||
}
|
||||
|
||||
|
||||
void uv__once_init(void) {
|
||||
uv_once(&uv_init_guard_, uv_init);
|
||||
}
|
||||
@@ -320,6 +339,9 @@ void uv__loop_close(uv_loop_t* loop) {
|
||||
uv_mutex_unlock(&loop->wq_mutex);
|
||||
uv_mutex_destroy(&loop->wq_mutex);
|
||||
|
||||
uv__free(loop->timer_heap);
|
||||
loop->timer_heap = NULL;
|
||||
|
||||
CloseHandle(loop->iocp);
|
||||
}
|
||||
|
||||
@@ -359,7 +381,7 @@ int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_poll(uv_loop_t* loop, DWORD timeout) {
|
||||
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
DWORD bytes;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* overlapped;
|
||||
@@ -410,7 +432,7 @@ static void uv_poll(uv_loop_t* loop, DWORD timeout) {
|
||||
}
|
||||
|
||||
|
||||
static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
|
||||
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
BOOL success;
|
||||
uv_req_t* req;
|
||||
OVERLAPPED_ENTRY overlappeds[128];
|
||||
@@ -422,12 +444,12 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
success = GetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
&count,
|
||||
timeout,
|
||||
FALSE);
|
||||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
@@ -485,12 +507,6 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
DWORD timeout;
|
||||
int r;
|
||||
int ran_pending;
|
||||
void (*poll)(uv_loop_t* loop, DWORD timeout);
|
||||
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
poll = &uv_poll_ex;
|
||||
else
|
||||
poll = &uv_poll;
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (!r)
|
||||
@@ -498,7 +514,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
uv_update_time(loop);
|
||||
uv_process_timers(loop);
|
||||
uv__run_timers(loop);
|
||||
|
||||
ran_pending = uv_process_reqs(loop);
|
||||
uv_idle_invoke(loop);
|
||||
@@ -508,7 +524,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
|
||||
(*poll)(loop, timeout);
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
uv__poll(loop, timeout);
|
||||
else
|
||||
uv__poll_wine(loop, timeout);
|
||||
|
||||
|
||||
uv_check_invoke(loop);
|
||||
uv_process_endgames(loop);
|
||||
@@ -522,7 +542,7 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
|
||||
* the check.
|
||||
*/
|
||||
uv_process_timers(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
|
||||
@@ -64,7 +64,8 @@ void uv_dlclose(uv_lib_t* lib) {
|
||||
|
||||
|
||||
int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
|
||||
*ptr = (void*) GetProcAddress(lib->handle, name);
|
||||
/* Cast though integer to suppress pedantic warning about forbidden cast. */
|
||||
*ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
|
||||
return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
|
||||
}
|
||||
|
||||
@@ -75,8 +76,9 @@ const char* uv_dlerror(const uv_lib_t* lib) {
|
||||
|
||||
|
||||
static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
|
||||
DWORD_PTR args[1] = { (DWORD_PTR) errorno };
|
||||
LPSTR fallback_error = "error: %1!d!";
|
||||
static const CHAR fallback_error[] = "error: %1!d!";
|
||||
DWORD_PTR args[1];
|
||||
args[0] = (DWORD_PTR) errorno;
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY |
|
||||
@@ -107,7 +109,8 @@ static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
|
||||
(LPSTR) &lib->errmsg, 0, NULL);
|
||||
|
||||
if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
|
||||
if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
|
||||
GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
|
||||
res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
|
||||
|
||||
@@ -46,8 +46,8 @@ void uv_fatal_error(const int errorno, const char* syscall) {
|
||||
errmsg = "Unknown error";
|
||||
}
|
||||
|
||||
/* FormatMessage messages include a newline character already, */
|
||||
/* so don't add another. */
|
||||
/* FormatMessage messages include a newline character already, so don't add
|
||||
* another. */
|
||||
if (syscall) {
|
||||
fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
|
||||
} else {
|
||||
|
||||
@@ -83,7 +83,7 @@ static void uv_relative_path(const WCHAR* filename,
|
||||
static int uv_split_path(const WCHAR* filename, WCHAR** dir,
|
||||
WCHAR** file) {
|
||||
size_t len, i;
|
||||
|
||||
|
||||
if (filename == NULL) {
|
||||
if (dir != NULL)
|
||||
*dir = NULL;
|
||||
@@ -215,11 +215,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
uv__free(long_path);
|
||||
long_path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (long_path) {
|
||||
uv__free(pathw);
|
||||
pathw = long_path;
|
||||
if (long_path) {
|
||||
uv__free(pathw);
|
||||
pathw = long_path;
|
||||
}
|
||||
}
|
||||
|
||||
dir_to_watch = pathw;
|
||||
@@ -230,8 +230,11 @@ int uv_fs_event_start(uv_fs_event_t* handle,
|
||||
*/
|
||||
|
||||
/* Convert to short path. */
|
||||
short_path = short_path_buffer;
|
||||
if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
|
||||
if (GetShortPathNameW(pathw,
|
||||
short_path_buffer,
|
||||
ARRAY_SIZE(short_path_buffer))) {
|
||||
short_path = short_path_buffer;
|
||||
} else {
|
||||
short_path = NULL;
|
||||
}
|
||||
|
||||
@@ -419,7 +422,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
* - We are not active, just ignore the callback
|
||||
*/
|
||||
if (!uv__is_active(handle)) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
}
|
||||
return;
|
||||
@@ -543,7 +546,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
|
||||
offset = file_info->NextEntryOffset;
|
||||
} while (offset && !(handle->flags & UV__HANDLE_CLOSING));
|
||||
} while (offset && !(handle->flags & UV_HANDLE_CLOSING));
|
||||
} else {
|
||||
handle->cb(handle, NULL, UV_CHANGE, 0);
|
||||
}
|
||||
@@ -552,7 +555,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv_fs_event_queue_readdirchanges(loop, handle);
|
||||
} else {
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle);
|
||||
@@ -573,7 +576,7 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
|
||||
|
||||
void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
|
||||
if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
|
||||
if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
if (handle->buffer) {
|
||||
|
||||
@@ -55,7 +55,11 @@
|
||||
do { \
|
||||
if (cb != NULL) { \
|
||||
uv__req_register(loop, req); \
|
||||
uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
|
||||
uv__work_submit(loop, \
|
||||
&req->work_req, \
|
||||
UV__WORK_FAST_IO, \
|
||||
uv__fs_work, \
|
||||
uv__fs_done); \
|
||||
return 0; \
|
||||
} else { \
|
||||
uv__fs_work(&req->work_req); \
|
||||
@@ -92,14 +96,17 @@
|
||||
return; \
|
||||
}
|
||||
|
||||
#define MILLIONu (1000U * 1000U)
|
||||
#define BILLIONu (1000U * 1000U * 1000U)
|
||||
|
||||
#define FILETIME_TO_UINT(filetime) \
|
||||
(*((uint64_t*) &(filetime)) - 116444736000000000ULL)
|
||||
(*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
|
||||
|
||||
#define FILETIME_TO_TIME_T(filetime) \
|
||||
(FILETIME_TO_UINT(filetime) / 10000000ULL)
|
||||
(FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
|
||||
|
||||
#define FILETIME_TO_TIME_NS(filetime, secs) \
|
||||
((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
|
||||
((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
|
||||
|
||||
#define FILETIME_TO_TIMESPEC(ts, filetime) \
|
||||
do { \
|
||||
@@ -109,8 +116,8 @@
|
||||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
|
||||
116444736000000000ULL; \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
|
||||
(uint64_t) 116444736 * BILLIONu; \
|
||||
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
|
||||
} while(0)
|
||||
@@ -326,12 +333,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
|
||||
reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
|
||||
sizeof(WCHAR);
|
||||
|
||||
/* Real symlinks can contain pretty much everything, but the only thing */
|
||||
/* we really care about is undoing the implicit conversion to an NT */
|
||||
/* namespaced path that CreateSymbolicLink will perform on absolute */
|
||||
/* paths. If the path is win32-namespaced then the user must have */
|
||||
/* explicitly made it so, and we better just return the unmodified */
|
||||
/* reparse data. */
|
||||
/* Real symlinks can contain pretty much everything, but the only thing we
|
||||
* really care about is undoing the implicit conversion to an NT namespaced
|
||||
* path that CreateSymbolicLink will perform on absolute paths. If the path
|
||||
* is win32-namespaced then the user must have explicitly made it so, and
|
||||
* we better just return the unmodified reparse data. */
|
||||
if (w_target_len >= 4 &&
|
||||
w_target[0] == L'\\' &&
|
||||
w_target[1] == L'?' &&
|
||||
@@ -352,8 +358,8 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
|
||||
(w_target[5] == L'N' || w_target[5] == L'n') &&
|
||||
(w_target[6] == L'C' || w_target[6] == L'c') &&
|
||||
w_target[7] == L'\\') {
|
||||
/* \??\UNC\<server>\<share>\ - make sure the final path looks like */
|
||||
/* \\<server>\<share>\ */
|
||||
/* \??\UNC\<server>\<share>\ - make sure the final path looks like
|
||||
* \\<server>\<share>\ */
|
||||
w_target += 6;
|
||||
w_target[0] = L'\\';
|
||||
w_target_len -= 6;
|
||||
@@ -368,11 +374,11 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
|
||||
w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
|
||||
sizeof(WCHAR);
|
||||
|
||||
/* Only treat junctions that look like \??\<drive>:\ as symlink. */
|
||||
/* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
|
||||
/* but that's confusing for programs since they wouldn't be able to */
|
||||
/* actually understand such a path when returned by uv_readlink(). */
|
||||
/* UNC paths are never valid for junctions so we don't care about them. */
|
||||
/* Only treat junctions that look like \??\<drive>:\ as symlink. Junctions
|
||||
* can also be used as mount points, like \??\Volume{<guid>}, but that's
|
||||
* confusing for programs since they wouldn't be able to actually
|
||||
* understand such a path when returned by uv_readlink(). UNC paths are
|
||||
* never valid for junctions so we don't care about them. */
|
||||
if (!(w_target_len >= 6 &&
|
||||
w_target[0] == L'\\' &&
|
||||
w_target[1] == L'?' &&
|
||||
@@ -409,8 +415,8 @@ void fs__open(uv_fs_t* req) {
|
||||
int fd, current_umask;
|
||||
int flags = req->fs.info.file_flags;
|
||||
|
||||
/* Obtain the active umask. umask() never fails and returns the previous */
|
||||
/* umask. */
|
||||
/* Obtain the active umask. umask() never fails and returns the previous
|
||||
* umask. */
|
||||
current_umask = umask(0);
|
||||
umask(current_umask);
|
||||
|
||||
@@ -502,6 +508,33 @@ void fs__open(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
if (flags & UV_FS_O_DIRECT) {
|
||||
/*
|
||||
* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive.
|
||||
* Windows returns 87, ERROR_INVALID_PARAMETER if these are combined.
|
||||
*
|
||||
* FILE_APPEND_DATA is included in FILE_GENERIC_WRITE:
|
||||
*
|
||||
* FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
|
||||
* FILE_WRITE_DATA |
|
||||
* FILE_WRITE_ATTRIBUTES |
|
||||
* FILE_WRITE_EA |
|
||||
* FILE_APPEND_DATA |
|
||||
* SYNCHRONIZE
|
||||
*
|
||||
* Note: Appends are also permitted by FILE_WRITE_DATA.
|
||||
*
|
||||
* In order for direct writes and direct appends to succeed, we therefore
|
||||
* exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise
|
||||
* fail if the user's sole permission is a direct append, since this
|
||||
* particular combination is invalid.
|
||||
*/
|
||||
if (access & FILE_APPEND_DATA) {
|
||||
if (access & FILE_WRITE_DATA) {
|
||||
access &= ~FILE_APPEND_DATA;
|
||||
} else {
|
||||
goto einval;
|
||||
}
|
||||
}
|
||||
attributes |= FILE_FLAG_NO_BUFFERING;
|
||||
}
|
||||
|
||||
@@ -530,8 +563,8 @@ void fs__open(uv_fs_t* req) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
|
||||
!(flags & UV_FS_O_EXCL)) {
|
||||
/* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was */
|
||||
/* specified, it means the path referred to a directory. */
|
||||
/* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was
|
||||
* specified, it means the path referred to a directory. */
|
||||
SET_REQ_UV_ERROR(req, UV_EISDIR, error);
|
||||
} else {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
@@ -756,9 +789,9 @@ void fs__unlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
/* Do not allow deletion of directories, unless it is a symlink. When */
|
||||
/* the path refers to a non-symlink directory, report EPERM as mandated */
|
||||
/* by POSIX.1. */
|
||||
/* Do not allow deletion of directories, unless it is a symlink. When the
|
||||
* path refers to a non-symlink directory, report EPERM as mandated by
|
||||
* POSIX.1. */
|
||||
|
||||
/* Check if it is a reparse point. If it's not, it's a normal directory. */
|
||||
if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
|
||||
@@ -767,8 +800,8 @@ void fs__unlink(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read the reparse point and check if it is a valid symlink. */
|
||||
/* If not, don't unlink. */
|
||||
/* Read the reparse point and check if it is a valid symlink. If not, don't
|
||||
* unlink. */
|
||||
if (fs__readlink_handle(handle, NULL, NULL) < 0) {
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_SYMLINK_NOT_SUPPORTED)
|
||||
@@ -783,9 +816,8 @@ void fs__unlink(uv_fs_t* req) {
|
||||
/* Remove read-only attribute */
|
||||
FILE_BASIC_INFORMATION basic = { 0 };
|
||||
|
||||
basic.FileAttributes = info.dwFileAttributes
|
||||
& ~(FILE_ATTRIBUTE_READONLY)
|
||||
| FILE_ATTRIBUTE_ARCHIVE;
|
||||
basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
|
||||
FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
status = pNtSetInformationFile(handle,
|
||||
&iosb,
|
||||
@@ -1196,7 +1228,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
|
||||
/* st_blocks contains the on-disk allocation size in 512-byte units. */
|
||||
statbuf->st_blocks =
|
||||
file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
|
||||
(uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
|
||||
|
||||
statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
|
||||
|
||||
@@ -1490,6 +1522,7 @@ static void fs__chmod(uv_fs_t* req) {
|
||||
|
||||
static void fs__fchmod(uv_fs_t* req) {
|
||||
int fd = req->file.fd;
|
||||
int clear_archive_flag;
|
||||
HANDLE handle;
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
@@ -1497,7 +1530,11 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
VERIFY_FD(fd, req);
|
||||
|
||||
handle = uv__get_osfhandle(fd);
|
||||
handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
nt_status = pNtQueryInformationFile(handle,
|
||||
&io_status,
|
||||
@@ -1507,7 +1544,27 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
return;
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
|
||||
/* Test if the Archive attribute is cleared */
|
||||
if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
|
||||
/* Set Archive flag, otherwise setting or clearing the read-only
|
||||
flag will not work */
|
||||
file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
nt_status = pNtSetInformationFile(handle,
|
||||
&io_status,
|
||||
&file_info,
|
||||
sizeof file_info,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
/* Remeber to clear the flag later on */
|
||||
clear_archive_flag = 1;
|
||||
} else {
|
||||
clear_archive_flag = 0;
|
||||
}
|
||||
|
||||
if (req->fs.info.mode & _S_IWRITE) {
|
||||
@@ -1524,10 +1581,28 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
return;
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
|
||||
if (clear_archive_flag) {
|
||||
file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
|
||||
if (file_info.FileAttributes == 0) {
|
||||
file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
nt_status = pNtSetInformationFile(handle,
|
||||
&io_status,
|
||||
&file_info,
|
||||
sizeof file_info,
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(nt_status)) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
SET_REQ_SUCCESS(req);
|
||||
fchmod_cleanup:
|
||||
CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -1787,17 +1862,13 @@ static void fs__symlink(uv_fs_t* req) {
|
||||
fs__create_junction(req, pathw, new_pathw);
|
||||
return;
|
||||
}
|
||||
if (!pCreateSymbolicLinkW) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
|
||||
flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
|
||||
else
|
||||
flags = uv__file_symlink_usermode_flag;
|
||||
|
||||
if (pCreateSymbolicLinkW(new_pathw, pathw, flags)) {
|
||||
if (CreateSymbolicLinkW(new_pathw, pathw, flags)) {
|
||||
SET_REQ_RESULT(req, 0);
|
||||
return;
|
||||
}
|
||||
@@ -1848,13 +1919,13 @@ static void fs__readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
int r;
|
||||
DWORD w_realpath_len;
|
||||
WCHAR* w_realpath_ptr = NULL;
|
||||
WCHAR* w_realpath_buf;
|
||||
|
||||
w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
|
||||
w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
|
||||
if (w_realpath_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1866,10 +1937,8 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
}
|
||||
w_realpath_ptr = w_realpath_buf;
|
||||
|
||||
if (pGetFinalPathNameByHandleW(handle,
|
||||
w_realpath_ptr,
|
||||
w_realpath_len,
|
||||
VOLUME_NAME_DOS) == 0) {
|
||||
if (GetFinalPathNameByHandleW(
|
||||
handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) {
|
||||
uv__free(w_realpath_buf);
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return -1;
|
||||
@@ -1901,11 +1970,6 @@ static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
|
||||
static void fs__realpath(uv_fs_t* req) {
|
||||
HANDLE handle;
|
||||
|
||||
if (!pGetFinalPathNameByHandleW) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
handle = CreateFileW(req->file.pathw,
|
||||
0,
|
||||
0,
|
||||
@@ -1940,6 +2004,10 @@ static void fs__fchown(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static void fs__lchown(uv_fs_t* req) {
|
||||
req->result = 0;
|
||||
}
|
||||
|
||||
static void uv__fs_work(struct uv__work* w) {
|
||||
uv_fs_t* req;
|
||||
|
||||
@@ -1977,6 +2045,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(REALPATH, realpath)
|
||||
XX(CHOWN, chown)
|
||||
XX(FCHOWN, fchown);
|
||||
XX(LCHOWN, lchown);
|
||||
default:
|
||||
assert(!"bad uv_fs_type");
|
||||
}
|
||||
@@ -2262,6 +2331,19 @@ int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
|
||||
uv_gid_t gid, uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_LCHOWN);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err) {
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "req-inl.h"
|
||||
#include "idna.h"
|
||||
|
||||
/* EAI_* constants. */
|
||||
#include <winsock2.h>
|
||||
@@ -71,8 +72,8 @@ int uv__getaddrinfo_translate_error(int sys_err) {
|
||||
#endif
|
||||
|
||||
|
||||
/* adjust size value to be multiple of 4. Use to keep pointer aligned */
|
||||
/* Do we need different versions of this for different architectures? */
|
||||
/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
|
||||
* Do we need different versions of this for different architectures? */
|
||||
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
|
||||
|
||||
#ifndef NDIS_IF_MAX_STRING_SIZE
|
||||
@@ -124,8 +125,7 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) {
|
||||
}
|
||||
|
||||
if (req->retcode == 0) {
|
||||
/* convert addrinfoW to addrinfo */
|
||||
/* first calculate required length */
|
||||
/* Convert addrinfoW to addrinfo. First calculate required length. */
|
||||
addrinfow_ptr = req->addrinfow;
|
||||
while (addrinfow_ptr != NULL) {
|
||||
addrinfo_len += addrinfo_struct_len +
|
||||
@@ -260,11 +260,13 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
const char* node,
|
||||
const char* service,
|
||||
const struct addrinfo* hints) {
|
||||
char hostname_ascii[256];
|
||||
int nodesize = 0;
|
||||
int servicesize = 0;
|
||||
int hintssize = 0;
|
||||
char* alloc_ptr = NULL;
|
||||
int err;
|
||||
long rc;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
return UV_EINVAL;
|
||||
@@ -278,12 +280,19 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
|
||||
/* calculate required memory size for all input values */
|
||||
if (node != NULL) {
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
|
||||
sizeof(WCHAR));
|
||||
rc = uv__idna_toascii(node,
|
||||
node + strlen(node),
|
||||
hostname_ascii,
|
||||
hostname_ascii + sizeof(hostname_ascii));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
|
||||
-1, NULL, 0) * sizeof(WCHAR));
|
||||
if (nodesize == 0) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
node = hostname_ascii;
|
||||
}
|
||||
|
||||
if (service != NULL) {
|
||||
@@ -313,8 +322,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
/* save alloc_ptr now so we can free if error */
|
||||
req->alloc = (void*)alloc_ptr;
|
||||
|
||||
/* convert node string to UTF16 into allocated memory and save pointer in */
|
||||
/* the request. */
|
||||
/* Convert node string to UTF16 into allocated memory and save pointer in the
|
||||
* request. */
|
||||
if (node != NULL) {
|
||||
req->node = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
@@ -331,8 +340,8 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
req->node = NULL;
|
||||
}
|
||||
|
||||
/* convert service string to UTF16 into allocated memory and save pointer */
|
||||
/* in the req. */
|
||||
/* Convert service string to UTF16 into allocated memory and save pointer in
|
||||
* the req. */
|
||||
if (service != NULL) {
|
||||
req->service = (WCHAR*)alloc_ptr;
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
@@ -369,6 +378,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
if (getaddrinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getaddrinfo_work,
|
||||
uv__getaddrinfo_done);
|
||||
return 0;
|
||||
@@ -392,21 +402,15 @@ int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
|
||||
DWORD bufsize;
|
||||
int r;
|
||||
|
||||
uv__once_init();
|
||||
|
||||
if (buffer == NULL || size == NULL || *size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (pConvertInterfaceIndexToLuid == NULL)
|
||||
return UV_ENOSYS;
|
||||
r = pConvertInterfaceIndexToLuid(ifindex, &luid);
|
||||
r = ConvertInterfaceIndexToLuid(ifindex, &luid);
|
||||
|
||||
if (r != 0)
|
||||
return uv_translate_sys_error(r);
|
||||
|
||||
if (pConvertInterfaceLuidToNameW == NULL)
|
||||
return UV_ENOSYS;
|
||||
r = pConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
|
||||
r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
|
||||
|
||||
if (r != 0)
|
||||
return uv_translate_sys_error(r);
|
||||
|
||||
@@ -42,7 +42,7 @@ static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
uv_getnameinfo_t* req;
|
||||
WCHAR host[NI_MAXHOST];
|
||||
WCHAR service[NI_MAXSERV];
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
req = container_of(w, uv_getnameinfo_t, work_req);
|
||||
if (GetNameInfoW((struct sockaddr*)&req->storage,
|
||||
@@ -53,27 +53,34 @@ static void uv__getnameinfo_work(struct uv__work* w) {
|
||||
ARRAY_SIZE(service),
|
||||
req->flags)) {
|
||||
ret = WSAGetLastError();
|
||||
req->retcode = uv__getaddrinfo_translate_error(ret);
|
||||
return;
|
||||
}
|
||||
req->retcode = uv__getaddrinfo_translate_error(ret);
|
||||
|
||||
/* convert results to UTF-8 */
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
host,
|
||||
-1,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
NULL,
|
||||
NULL);
|
||||
ret = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
host,
|
||||
-1,
|
||||
req->host,
|
||||
sizeof(req->host),
|
||||
NULL,
|
||||
NULL);
|
||||
if (ret == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
NULL,
|
||||
NULL);
|
||||
ret = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
service,
|
||||
-1,
|
||||
req->service,
|
||||
sizeof(req->service),
|
||||
NULL,
|
||||
NULL);
|
||||
if (ret == 0) {
|
||||
req->retcode = uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +145,7 @@ int uv_getnameinfo(uv_loop_t* loop,
|
||||
if (getnameinfo_cb) {
|
||||
uv__work_submit(loop,
|
||||
&req->work_req,
|
||||
UV__WORK_SLOW_IO,
|
||||
uv__getnameinfo_work,
|
||||
uv__getnameinfo_done);
|
||||
return 0;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#define DECREASE_ACTIVE_COUNT(loop, handle) \
|
||||
do { \
|
||||
if (--(handle)->activecnt == 0 && \
|
||||
!((handle)->flags & UV__HANDLE_CLOSING)) { \
|
||||
!((handle)->flags & UV_HANDLE_CLOSING)) { \
|
||||
uv__handle_stop((handle)); \
|
||||
} \
|
||||
assert((handle)->activecnt >= 0); \
|
||||
@@ -53,7 +53,7 @@
|
||||
assert(handle->reqs_pending > 0); \
|
||||
handle->reqs_pending--; \
|
||||
\
|
||||
if (handle->flags & UV__HANDLE_CLOSING && \
|
||||
if (handle->flags & UV_HANDLE_CLOSING && \
|
||||
handle->reqs_pending == 0) { \
|
||||
uv_want_endgame(loop, (uv_handle_t*)handle); \
|
||||
} \
|
||||
@@ -62,14 +62,14 @@
|
||||
|
||||
#define uv__handle_closing(handle) \
|
||||
do { \
|
||||
assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
|
||||
assert(!((handle)->flags & UV_HANDLE_CLOSING)); \
|
||||
\
|
||||
if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
|
||||
((handle)->flags & UV__HANDLE_REF))) \
|
||||
if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \
|
||||
((handle)->flags & UV_HANDLE_REF))) \
|
||||
uv__active_handle_add((uv_handle_t*) (handle)); \
|
||||
\
|
||||
(handle)->flags |= UV__HANDLE_CLOSING; \
|
||||
(handle)->flags &= ~UV__HANDLE_ACTIVE; \
|
||||
(handle)->flags |= UV_HANDLE_CLOSING; \
|
||||
(handle)->flags &= ~UV_HANDLE_ACTIVE; \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -126,7 +126,8 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
break;
|
||||
|
||||
case UV_TIMER:
|
||||
uv_timer_endgame(loop, (uv_timer_t*) handle);
|
||||
uv__timer_close((uv_timer_t*) handle);
|
||||
uv__handle_close(handle);
|
||||
break;
|
||||
|
||||
case UV_PREPARE:
|
||||
@@ -164,10 +165,10 @@ INLINE static void uv_process_endgames(uv_loop_t* loop) {
|
||||
|
||||
INLINE static HANDLE uv__get_osfhandle(int fd)
|
||||
{
|
||||
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
|
||||
/* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
|
||||
/* for invalid FDs in release builds (or if you let the assert continue). */
|
||||
/* So this wrapper function disables asserts when calling _get_osfhandle. */
|
||||
/* _get_osfhandle() raises an assert in debug builds if the FD is invalid.
|
||||
* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for
|
||||
* invalid FDs in release builds (or if you let the assert continue). So this
|
||||
* wrapper function disables asserts when calling _get_osfhandle. */
|
||||
|
||||
HANDLE handle;
|
||||
UV_BEGIN_DISABLE_CRT_ASSERT();
|
||||
|
||||
@@ -59,15 +59,15 @@ uv_handle_type uv_guess_handle(uv_file file) {
|
||||
|
||||
|
||||
int uv_is_active(const uv_handle_t* handle) {
|
||||
return (handle->flags & UV__HANDLE_ACTIVE) &&
|
||||
!(handle->flags & UV__HANDLE_CLOSING);
|
||||
return (handle->flags & UV_HANDLE_ACTIVE) &&
|
||||
!(handle->flags & UV_HANDLE_CLOSING);
|
||||
}
|
||||
|
||||
|
||||
void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
@@ -150,10 +150,14 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) {
|
||||
|
||||
|
||||
int uv_is_closing(const uv_handle_t* handle) {
|
||||
return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
|
||||
return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
|
||||
}
|
||||
|
||||
|
||||
uv_os_fd_t uv_get_osfhandle(int fd) {
|
||||
return uv__get_osfhandle(fd);
|
||||
}
|
||||
|
||||
int uv_open_osfhandle(uv_os_fd_t os_fd) {
|
||||
return _open_osfhandle((intptr_t) os_fd, 0);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include "uv.h"
|
||||
#include "../uv-common.h"
|
||||
|
||||
#include "tree.h"
|
||||
#include "uv/tree.h"
|
||||
#include "winapi.h"
|
||||
#include "winsock.h"
|
||||
|
||||
@@ -61,78 +61,20 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
|
||||
#define UV_END_DISABLE_CRT_ASSERT()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handles
|
||||
* (also see handle-inl.h)
|
||||
*/
|
||||
|
||||
/* Used by all handles. */
|
||||
#define UV_HANDLE_CLOSED 0x00000002
|
||||
#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
|
||||
|
||||
/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
|
||||
/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
|
||||
/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
|
||||
/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
|
||||
|
||||
/* Used by streams and UDP handles. */
|
||||
#define UV_HANDLE_READING 0x00000100
|
||||
#define UV_HANDLE_BOUND 0x00000200
|
||||
#define UV_HANDLE_LISTENING 0x00000800
|
||||
#define UV_HANDLE_CONNECTION 0x00001000
|
||||
#define UV_HANDLE_READABLE 0x00008000
|
||||
#define UV_HANDLE_WRITABLE 0x00010000
|
||||
#define UV_HANDLE_READ_PENDING 0x00020000
|
||||
#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
|
||||
#define UV_HANDLE_ZERO_READ 0x00080000
|
||||
#define UV_HANDLE_EMULATE_IOCP 0x00100000
|
||||
#define UV_HANDLE_BLOCKING_WRITES 0x00200000
|
||||
#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
|
||||
|
||||
/* Used by uv_tcp_t and uv_udp_t handles */
|
||||
#define UV_HANDLE_IPV6 0x01000000
|
||||
|
||||
/* Only used by uv_tcp_t handles. */
|
||||
#define UV_HANDLE_TCP_NODELAY 0x02000000
|
||||
#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
|
||||
#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
|
||||
#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
|
||||
#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
|
||||
#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
|
||||
|
||||
/* Only used by uv_pipe_t handles. */
|
||||
#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
|
||||
#define UV_HANDLE_PIPESERVER 0x02000000
|
||||
#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
#define UV_HANDLE_TTY_READABLE 0x01000000
|
||||
#define UV_HANDLE_TTY_RAW 0x02000000
|
||||
#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
|
||||
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
#define UV_HANDLE_POLL_SLOW 0x02000000
|
||||
|
||||
|
||||
/*
|
||||
* Requests: see req-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Streams: see stream-inl.h
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TCP
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
UV__IPC_SOCKET_XFER_NONE = 0,
|
||||
UV__IPC_SOCKET_XFER_TCP_CONNECTION,
|
||||
UV__IPC_SOCKET_XFER_TCP_SERVER
|
||||
} uv__ipc_socket_xfer_type_t;
|
||||
|
||||
typedef struct {
|
||||
WSAPROTOCOL_INFOW socket_info;
|
||||
int delayed_error;
|
||||
} uv__ipc_socket_info_ex;
|
||||
uint32_t delayed_error;
|
||||
} uv__ipc_socket_xfer_info_t;
|
||||
|
||||
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
|
||||
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
|
||||
@@ -154,11 +96,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
|
||||
void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
|
||||
|
||||
int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
|
||||
int tcp_connection);
|
||||
|
||||
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
|
||||
LPWSAPROTOCOL_INFOW protocol_info);
|
||||
int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
int pid,
|
||||
uv__ipc_socket_xfer_type_t* xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info);
|
||||
|
||||
|
||||
/*
|
||||
@@ -182,14 +126,14 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
|
||||
int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
|
||||
int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb);
|
||||
int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
|
||||
int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
|
||||
uv_write_cb cb);
|
||||
void uv__pipe_pause_read(uv_pipe_t* handle);
|
||||
void uv__pipe_unpause_read(uv_pipe_t* handle);
|
||||
void uv__pipe_stop_read(uv_pipe_t* handle);
|
||||
void uv__pipe_read_stop(uv_pipe_t* handle);
|
||||
int uv__pipe_write(uv_loop_t* loop,
|
||||
uv_write_t* req,
|
||||
uv_pipe_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
size_t nbufs,
|
||||
uv_stream_t* send_handle,
|
||||
uv_write_cb cb);
|
||||
|
||||
void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv_req_t* req);
|
||||
@@ -251,15 +195,6 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
|
||||
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*/
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
|
||||
|
||||
DWORD uv__next_timeout(const uv_loop_t* loop);
|
||||
void uv_process_timers(uv_loop_t* loop);
|
||||
|
||||
|
||||
/*
|
||||
* Loop watchers
|
||||
*/
|
||||
@@ -336,7 +271,6 @@ void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
|
||||
void uv__util_init(void);
|
||||
|
||||
uint64_t uv__hrtime(double scale);
|
||||
int uv_current_pid(void);
|
||||
__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd);
|
||||
int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
|
||||
void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
handle->flags |= UV_HANDLE_CLOSED;
|
||||
uv__handle_close(handle);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -75,7 +75,7 @@ static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
|
||||
static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
uv_req_t* req;
|
||||
AFD_POLL_INFO* afd_poll_info;
|
||||
DWORD result;
|
||||
int result;
|
||||
|
||||
/* Find a yet unsubmitted req to submit. */
|
||||
if (handle->submitted_events_1 == 0) {
|
||||
@@ -91,16 +91,16 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
handle->mask_events_1 = handle->events;
|
||||
handle->mask_events_2 = 0;
|
||||
} else {
|
||||
/* Just wait until there's an unsubmitted req. */
|
||||
/* This will happen almost immediately as one of the 2 outstanding */
|
||||
/* requests is about to return. When this happens, */
|
||||
/* uv__fast_poll_process_poll_req will be called, and the pending */
|
||||
/* events, if needed, will be processed in a subsequent request. */
|
||||
/* Just wait until there's an unsubmitted req. This will happen almost
|
||||
* immediately as one of the 2 outstanding requests is about to return.
|
||||
* When this happens, uv__fast_poll_process_poll_req will be called, and
|
||||
* the pending events, if needed, will be processed in a subsequent
|
||||
* request. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Setting Exclusive to TRUE makes the other poll request return if there */
|
||||
/* is any. */
|
||||
/* Setting Exclusive to TRUE makes the other poll request return if there is
|
||||
* any. */
|
||||
afd_poll_info->Exclusive = TRUE;
|
||||
afd_poll_info->NumberOfHandles = 1;
|
||||
afd_poll_info->Timeout.QuadPart = INT64_MAX;
|
||||
@@ -136,7 +136,7 @@ static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
|
||||
static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
AFD_POLL_INFO afd_poll_info;
|
||||
DWORD result;
|
||||
int result;
|
||||
|
||||
afd_poll_info.Exclusive = TRUE;
|
||||
afd_poll_info.NumberOfHandles = 1;
|
||||
@@ -218,7 +218,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__fast_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -228,7 +228,7 @@ static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
|
||||
static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
@@ -257,8 +257,8 @@ static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return 0;
|
||||
} else {
|
||||
/* Cancel outstanding poll requests by executing another, unique poll */
|
||||
/* request that forces the outstanding ones to return. */
|
||||
/* Cancel outstanding poll requests by executing another, unique poll
|
||||
* request that forces the outstanding ones to return. */
|
||||
return uv__fast_poll_cancel_poll_req(loop, handle);
|
||||
}
|
||||
}
|
||||
@@ -316,9 +316,8 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
/* If we didn't (try) to create a peer socket yet, try to make one. Don't */
|
||||
/* try again if the peer socket creation failed earlier for the same */
|
||||
/* protocol. */
|
||||
/* If we didn't (try) to create a peer socket yet, try to make one. Don't try
|
||||
* again if the peer socket creation failed earlier for the same protocol. */
|
||||
peer_socket = loop->poll_peer_sockets[index];
|
||||
if (peer_socket == 0) {
|
||||
peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
|
||||
@@ -357,8 +356,8 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
|
||||
efds.fd_count = 0;
|
||||
}
|
||||
|
||||
/* Make the select() time out after 3 minutes. If select() hangs because */
|
||||
/* the user closed the socket, we will at least not hang indefinitely. */
|
||||
/* Make the select() time out after 3 minutes. If select() hangs because the
|
||||
* user closed the socket, we will at least not hang indefinitely. */
|
||||
timeout.tv_sec = 3 * 60;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
@@ -462,7 +461,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
if ((handle->events & ~(handle->submitted_events_1 |
|
||||
handle->submitted_events_2)) != 0) {
|
||||
uv__slow_poll_submit_poll_req(loop, handle);
|
||||
} else if ((handle->flags & UV__HANDLE_CLOSING) &&
|
||||
} else if ((handle->flags & UV_HANDLE_CLOSING) &&
|
||||
handle->submitted_events_1 == 0 &&
|
||||
handle->submitted_events_2 == 0) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -472,7 +471,7 @@ static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
|
||||
|
||||
static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
|
||||
assert(handle->type == UV_POLL);
|
||||
assert(!(handle->flags & UV__HANDLE_CLOSING));
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSING));
|
||||
assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
|
||||
|
||||
handle->events = events;
|
||||
@@ -522,10 +521,10 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
|
||||
/* Try to obtain a base handle for the socket. This increases this chances */
|
||||
/* that we find an AFD handle and are able to use the fast poll mechanism. */
|
||||
/* This will always fail on windows XP/2k3, since they don't support the */
|
||||
/* SIO_BASE_HANDLE ioctl. */
|
||||
/* Try to obtain a base handle for the socket. This increases this chances that
|
||||
* we find an AFD handle and are able to use the fast poll mechanism. This will
|
||||
* always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
|
||||
* ioctl. */
|
||||
#ifndef NDEBUG
|
||||
base_socket = INVALID_SOCKET;
|
||||
#endif
|
||||
@@ -557,9 +556,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
return uv_translate_sys_error(WSAGetLastError());
|
||||
}
|
||||
|
||||
/* Get the peer socket that is needed to enable fast poll. If the returned */
|
||||
/* value is NULL, the protocol is not implemented by MSAFD and we'll have */
|
||||
/* to use slow mode. */
|
||||
/* Get the peer socket that is needed to enable fast poll. If the returned
|
||||
* value is NULL, the protocol is not implemented by MSAFD and we'll have to
|
||||
* use slow mode. */
|
||||
peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
|
||||
|
||||
if (peer_socket != INVALID_SOCKET) {
|
||||
@@ -634,7 +633,7 @@ int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
|
||||
|
||||
void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->submitted_events_1 == 0);
|
||||
|
||||
@@ -103,12 +103,12 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
DWORD client_access = 0;
|
||||
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
||||
int err;
|
||||
int overlap;
|
||||
|
||||
if (flags & UV_READABLE_PIPE) {
|
||||
/* The server needs inbound access too, otherwise CreateNamedPipe() */
|
||||
/* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
|
||||
/* probe the state of the write buffer when we're trying to shutdown */
|
||||
/* the pipe. */
|
||||
/* The server needs inbound access too, otherwise CreateNamedPipe() won't
|
||||
* give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
|
||||
* state of the write buffer when we're trying to shutdown the pipe. */
|
||||
server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
|
||||
client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
|
||||
}
|
||||
@@ -131,12 +131,13 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
sa.lpSecurityDescriptor = NULL;
|
||||
sa.bInheritHandle = TRUE;
|
||||
|
||||
overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
|
||||
child_pipe = CreateFileA(pipe_name,
|
||||
client_access,
|
||||
0,
|
||||
&sa,
|
||||
OPEN_EXISTING,
|
||||
server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
|
||||
overlap ? FILE_FLAG_OVERLAPPED : 0,
|
||||
NULL);
|
||||
if (child_pipe == INVALID_HANDLE_VALUE) {
|
||||
err = GetLastError();
|
||||
@@ -159,8 +160,8 @@ static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Do a blocking ConnectNamedPipe. This should not block because we have */
|
||||
/* both ends of the pipe created. */
|
||||
/* Do a blocking ConnectNamedPipe. This should not block because we have both
|
||||
* ends of the pipe created. */
|
||||
if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
|
||||
if (GetLastError() != ERROR_PIPE_CONNECTED) {
|
||||
err = GetLastError();
|
||||
@@ -194,11 +195,11 @@ static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
|
||||
HANDLE current_process;
|
||||
|
||||
|
||||
/* _get_osfhandle will sometimes return -2 in case of an error. This seems */
|
||||
/* to happen when fd <= 2 and the process' corresponding stdio handle is */
|
||||
/* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
|
||||
/* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
|
||||
/* use the duplicate. Therefore we filter out known-invalid handles here. */
|
||||
/* _get_osfhandle will sometimes return -2 in case of an error. This seems to
|
||||
* happen when fd <= 2 and the process' corresponding stdio handle is set to
|
||||
* NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
|
||||
* this situation goes unnoticed until someone tries to use the duplicate.
|
||||
* Therefore we filter out known-invalid handles here. */
|
||||
if (handle == INVALID_HANDLE_VALUE ||
|
||||
handle == NULL ||
|
||||
handle == (HANDLE) -2) {
|
||||
@@ -284,8 +285,8 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
|
||||
/* clean up on failure. */
|
||||
/* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
|
||||
* up on failure. */
|
||||
CHILD_STDIO_COUNT(buffer) = count;
|
||||
for (i = 0; i < count; i++) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
@@ -303,12 +304,12 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
|
||||
UV_INHERIT_STREAM)) {
|
||||
case UV_IGNORE:
|
||||
/* Starting a process with no stdin/stout/stderr can confuse it. */
|
||||
/* So no matter what the user specified, we make sure the first */
|
||||
/* three FDs are always open in their typical modes, e.g. stdin */
|
||||
/* be readable and stdout/err should be writable. For FDs > 2, don't */
|
||||
/* do anything - all handles in the stdio buffer are initialized with */
|
||||
/* INVALID_HANDLE_VALUE, which should be okay. */
|
||||
/* Starting a process with no stdin/stout/stderr can confuse it. So no
|
||||
* matter what the user specified, we make sure the first three FDs are
|
||||
* always open in their typical modes, e. g. stdin be readable and
|
||||
* stdout/err should be writable. For FDs > 2, don't do anything - all
|
||||
* handles in the stdio buffer are initialized with.
|
||||
* INVALID_HANDLE_VALUE, which should be okay. */
|
||||
if (i <= 2) {
|
||||
DWORD access = (i == 0) ? FILE_GENERIC_READ :
|
||||
FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
|
||||
@@ -323,14 +324,14 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
break;
|
||||
|
||||
case UV_CREATE_PIPE: {
|
||||
/* Create a pair of two connected pipe ends; one end is turned into */
|
||||
/* an uv_pipe_t for use by the parent. The other one is given to */
|
||||
/* the child. */
|
||||
/* Create a pair of two connected pipe ends; one end is turned into an
|
||||
* uv_pipe_t for use by the parent. The other one is given to the
|
||||
* child. */
|
||||
uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
|
||||
HANDLE child_pipe = INVALID_HANDLE_VALUE;
|
||||
|
||||
/* Create a new, connected pipe pair. stdio[i].stream should point */
|
||||
/* to an uninitialized, but not connected pipe handle. */
|
||||
/* Create a new, connected pipe pair. stdio[i]. stream should point to
|
||||
* an uninitialized, but not connected pipe handle. */
|
||||
assert(fdopt.data.stream->type == UV_NAMED_PIPE);
|
||||
assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
|
||||
assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
|
||||
@@ -354,8 +355,8 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
/* Make an inheritable duplicate of the handle. */
|
||||
err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
|
||||
if (err) {
|
||||
/* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
|
||||
/* error. */
|
||||
/* If fdopt. data. fd is not valid and fd <= 2, then ignore the
|
||||
* error. */
|
||||
if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
|
||||
CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
|
||||
@@ -418,8 +419,8 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
|
||||
if (stream_handle == NULL ||
|
||||
stream_handle == INVALID_HANDLE_VALUE) {
|
||||
/* The handle is already closed, or not yet created, or the */
|
||||
/* stream type is not supported. */
|
||||
/* The handle is already closed, or not yet created, or the stream
|
||||
* type is not supported. */
|
||||
err = ERROR_NOT_SUPPORTED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -360,8 +360,8 @@ static WCHAR* search_path(const WCHAR *file,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the start of the filename so we can split the directory from the */
|
||||
/* name. */
|
||||
/* Find the start of the filename so we can split the directory from the
|
||||
* name. */
|
||||
for (file_name_start = (WCHAR*)file + file_len;
|
||||
file_name_start > file
|
||||
&& file_name_start[-1] != L'\\'
|
||||
@@ -556,8 +556,8 @@ int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
|
||||
arg_count++;
|
||||
}
|
||||
|
||||
/* Adjust for potential quotes. Also assume the worst-case scenario */
|
||||
/* that every character needs escaping, so we need twice as much space. */
|
||||
/* Adjust for potential quotes. Also assume the worst-case scenario that
|
||||
* every character needs escaping, so we need twice as much space. */
|
||||
dst_len = dst_len * 2 + arg_count * 2;
|
||||
|
||||
/* Allocate buffer for the final command line. */
|
||||
@@ -739,7 +739,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
}
|
||||
*ptr_copy = NULL;
|
||||
assert(env_len == ptr - dst_copy);
|
||||
assert(env_len == (size_t) (ptr - dst_copy));
|
||||
|
||||
/* sort our (UTF-16) copy */
|
||||
qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
|
||||
@@ -799,7 +799,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
var_size = GetEnvironmentVariableW(required_vars[i].wide,
|
||||
ptr,
|
||||
(int) (env_len - (ptr - dst)));
|
||||
if (var_size != len-1) { /* race condition? */
|
||||
if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
|
||||
uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
|
||||
}
|
||||
}
|
||||
@@ -815,7 +815,7 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
}
|
||||
|
||||
/* Terminate with an extra NULL. */
|
||||
assert(env_len == (ptr - dst));
|
||||
assert(env_len == (size_t) (ptr - dst));
|
||||
*ptr = L'\0';
|
||||
|
||||
uv__free(dst_copy);
|
||||
@@ -831,8 +831,13 @@ int make_program_env(char* env_block[], WCHAR** dst_ptr) {
|
||||
*/
|
||||
static WCHAR* find_path(WCHAR *env) {
|
||||
for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
|
||||
if (wcsncmp(env, L"PATH=", 5) == 0)
|
||||
if ((env[0] == L'P' || env[0] == L'p') &&
|
||||
(env[1] == L'A' || env[1] == L'a') &&
|
||||
(env[2] == L'T' || env[2] == L't') &&
|
||||
(env[3] == L'H' || env[3] == L'h') &&
|
||||
(env[4] == L'=')) {
|
||||
return &env[5];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -865,9 +870,9 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
assert(handle->exit_cb_pending);
|
||||
handle->exit_cb_pending = 0;
|
||||
|
||||
/* If we're closing, don't call the exit callback. Just schedule a close */
|
||||
/* callback now. */
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
/* If we're closing, don't call the exit callback. Just schedule a close
|
||||
* callback now. */
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
return;
|
||||
}
|
||||
@@ -878,14 +883,14 @@ void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
|
||||
handle->wait_handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
/* Set the handle to inactive: no callbacks will be made after the exit */
|
||||
/* callback.*/
|
||||
/* Set the handle to inactive: no callbacks will be made after the exit
|
||||
* callback. */
|
||||
uv__handle_stop(handle);
|
||||
|
||||
if (GetExitCodeProcess(handle->process_handle, &status)) {
|
||||
exit_code = status;
|
||||
} else {
|
||||
/* Unable to to obtain the exit code. This should never happen. */
|
||||
/* Unable to obtain the exit code. This should never happen. */
|
||||
exit_code = uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
@@ -900,8 +905,8 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
uv__handle_closing(handle);
|
||||
|
||||
if (handle->wait_handle != INVALID_HANDLE_VALUE) {
|
||||
/* This blocks until either the wait was cancelled, or the callback has */
|
||||
/* completed. */
|
||||
/* This blocks until either the wait was cancelled, or the callback has
|
||||
* completed. */
|
||||
BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
|
||||
if (!r) {
|
||||
/* This should never happen, and if it happens, we can't recover... */
|
||||
@@ -919,7 +924,7 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
|
||||
|
||||
void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
|
||||
assert(!handle->exit_cb_pending);
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
/* Clean-up the process handle. */
|
||||
@@ -965,6 +970,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
UV_PROCESS_SETGID |
|
||||
UV_PROCESS_SETUID |
|
||||
UV_PROCESS_WINDOWS_HIDE |
|
||||
UV_PROCESS_WINDOWS_HIDE_CONSOLE |
|
||||
UV_PROCESS_WINDOWS_HIDE_GUI |
|
||||
UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
|
||||
|
||||
err = uv_utf8_to_utf16_alloc(options->file, &application);
|
||||
@@ -1066,7 +1073,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
process_flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
|
||||
if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
|
||||
if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
|
||||
(options->flags & UV_PROCESS_WINDOWS_HIDE)) {
|
||||
/* Avoid creating console window if stdio is not inherited. */
|
||||
for (i = 0; i < options->stdio_count; i++) {
|
||||
if (options->stdio[i].flags & UV_INHERIT_FD)
|
||||
@@ -1074,7 +1082,9 @@ int uv_spawn(uv_loop_t* loop,
|
||||
if (i == options->stdio_count - 1)
|
||||
process_flags |= CREATE_NO_WINDOW;
|
||||
}
|
||||
|
||||
}
|
||||
if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
|
||||
(options->flags & UV_PROCESS_WINDOWS_HIDE)) {
|
||||
/* Use SW_HIDE to avoid any potential process window. */
|
||||
startup.wShowWindow = SW_HIDE;
|
||||
} else {
|
||||
@@ -1160,14 +1170,13 @@ int uv_spawn(uv_loop_t* loop,
|
||||
}
|
||||
}
|
||||
|
||||
/* Spawn succeeded */
|
||||
/* Beyond this point, failure is reported asynchronously. */
|
||||
/* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
|
||||
|
||||
process->process_handle = info.hProcess;
|
||||
process->pid = info.dwProcessId;
|
||||
|
||||
/* If the process isn't spawned as detached, assign to the global job */
|
||||
/* object so windows will kill it when the parent process dies. */
|
||||
/* If the process isn't spawned as detached, assign to the global job object
|
||||
* so windows will kill it when the parent process dies. */
|
||||
if (!(options->flags & UV_PROCESS_DETACHED)) {
|
||||
uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
|
||||
|
||||
@@ -1194,7 +1203,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
if (fdopt->flags & UV_CREATE_PIPE &&
|
||||
fdopt->data.stream->type == UV_NAMED_PIPE &&
|
||||
((uv_pipe_t*) fdopt->data.stream)->ipc) {
|
||||
((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
|
||||
((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid =
|
||||
info.dwProcessId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1210,8 +1220,8 @@ int uv_spawn(uv_loop_t* loop,
|
||||
|
||||
assert(!err);
|
||||
|
||||
/* Make the handle active. It will remain active until the exit callback */
|
||||
/* is made or the handle is closed, whichever happens first. */
|
||||
/* Make the handle active. It will remain active until the exit callback is
|
||||
* made or the handle is closed, whichever happens first. */
|
||||
uv__handle_start(process);
|
||||
|
||||
/* Cleanup, whether we succeeded or failed. */
|
||||
@@ -1242,16 +1252,16 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
case SIGTERM:
|
||||
case SIGKILL:
|
||||
case SIGINT: {
|
||||
/* Unconditionally terminate the process. On Windows, killed processes */
|
||||
/* normally return 1. */
|
||||
/* Unconditionally terminate the process. On Windows, killed processes
|
||||
* normally return 1. */
|
||||
DWORD status;
|
||||
int err;
|
||||
|
||||
if (TerminateProcess(process_handle, 1))
|
||||
return 0;
|
||||
|
||||
/* If the process already exited before TerminateProcess was called, */
|
||||
/* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
|
||||
/* If the process already exited before TerminateProcess was called,.
|
||||
* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
|
||||
err = GetLastError();
|
||||
if (err == ERROR_ACCESS_DENIED &&
|
||||
GetExitCodeProcess(process_handle, &status) &&
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
@@ -47,13 +47,13 @@ void uv_signals_init(void) {
|
||||
|
||||
|
||||
static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
|
||||
/* Compare signums first so all watchers with the same signnum end up */
|
||||
/* adjacent. */
|
||||
/* Compare signums first so all watchers with the same signnum end up
|
||||
* adjacent. */
|
||||
if (w1->signum < w2->signum) return -1;
|
||||
if (w1->signum > w2->signum) return 1;
|
||||
|
||||
/* Sort by loop pointer, so we can easily look up the first item after */
|
||||
/* { .signum = x, .loop = NULL } */
|
||||
/* Sort by loop pointer, so we can easily look up the first item after
|
||||
* { .signum = x, .loop = NULL }. */
|
||||
if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
|
||||
if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
|
||||
|
||||
@@ -90,7 +90,7 @@ int uv__signal_dispatch(int signum) {
|
||||
unsigned long previous = InterlockedExchange(
|
||||
(volatile LONG*) &handle->pending_signum, signum);
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
|
||||
continue;
|
||||
|
||||
if (!previous) {
|
||||
@@ -98,8 +98,8 @@ int uv__signal_dispatch(int signum) {
|
||||
}
|
||||
|
||||
dispatched = 1;
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED;
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
@@ -118,10 +118,10 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
|
||||
|
||||
case CTRL_CLOSE_EVENT:
|
||||
if (uv__signal_dispatch(SIGHUP)) {
|
||||
/* Windows will terminate the process after the control handler */
|
||||
/* returns. After that it will just terminate our process. Therefore */
|
||||
/* block the signal handler so the main loop has some time to pick */
|
||||
/* up the signal and do something for a few seconds. */
|
||||
/* Windows will terminate the process after the control handler
|
||||
* returns. After that it will just terminate our process. Therefore
|
||||
* block the signal handler so the main loop has some time to pick up
|
||||
* the signal and do something for a few seconds. */
|
||||
Sleep(INFINITE);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -129,8 +129,8 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
|
||||
|
||||
case CTRL_LOGOFF_EVENT:
|
||||
case CTRL_SHUTDOWN_EVENT:
|
||||
/* These signals are only sent to services. Services have their own */
|
||||
/* notification mechanism, so there's no point in handling these. */
|
||||
/* These signals are only sent to services. Services have their own
|
||||
* notification mechanism, so there's no point in handling these. */
|
||||
|
||||
default:
|
||||
/* We don't handle these. */
|
||||
@@ -190,13 +190,13 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
int signum,
|
||||
int oneshot) {
|
||||
/* Test for invalid signal values. */
|
||||
if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
|
||||
if (signum <= 0 || signum >= NSIG)
|
||||
return UV_EINVAL;
|
||||
|
||||
/* Short circuit: if the signal watcher is already watching {signum} don't */
|
||||
/* go through the process of deregistering and registering the handler. */
|
||||
/* Additionally, this avoids pending signals getting lost in the (small) */
|
||||
/* time frame that handle->signum == 0. */
|
||||
/* Short circuit: if the signal watcher is already watching {signum} don't go
|
||||
* through the process of deregistering and registering the handler.
|
||||
* Additionally, this avoids pending signals getting lost in the (small) time
|
||||
* frame that handle->signum == 0. */
|
||||
if (signum == handle->signum) {
|
||||
handle->signal_cb = signal_cb;
|
||||
return 0;
|
||||
@@ -213,7 +213,7 @@ int uv__signal_start(uv_signal_t* handle,
|
||||
|
||||
handle->signum = signum;
|
||||
if (oneshot)
|
||||
handle->flags |= UV__SIGNAL_ONE_SHOT;
|
||||
handle->flags |= UV_SIGNAL_ONE_SHOT;
|
||||
|
||||
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
@@ -237,16 +237,16 @@ void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
|
||||
(volatile LONG*) &handle->pending_signum, 0);
|
||||
assert(dispatched_signum != 0);
|
||||
|
||||
/* Check if the pending signal equals the signum that we are watching for. */
|
||||
/* These can get out of sync when the handler is stopped and restarted */
|
||||
/* while the signal_req is pending. */
|
||||
/* Check if the pending signal equals the signum that we are watching for.
|
||||
* These can get out of sync when the handler is stopped and restarted while
|
||||
* the signal_req is pending. */
|
||||
if (dispatched_signum == handle->signum)
|
||||
handle->signal_cb(handle, dispatched_signum);
|
||||
|
||||
if (handle->flags & UV__SIGNAL_ONE_SHOT)
|
||||
if (handle->flags & UV_SIGNAL_ONE_SHOT)
|
||||
uv_signal_stop(handle);
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* When it is closing, it must be stopped at this point. */
|
||||
assert(handle->signum == 0);
|
||||
uv_want_endgame(loop, (uv_handle_t*) handle);
|
||||
@@ -265,7 +265,7 @@ void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
|
||||
|
||||
void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
assert(handle->flags & UV__HANDLE_CLOSING);
|
||||
assert(handle->flags & UV_HANDLE_CLOSING);
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
assert(handle->signum == 0);
|
||||
|
||||
@@ -105,12 +105,10 @@ int uv_read_stop(uv_stream_t* handle) {
|
||||
err = 0;
|
||||
if (handle->type == UV_TTY) {
|
||||
err = uv_tty_read_stop((uv_tty_t*) handle);
|
||||
} else if (handle->type == UV_NAMED_PIPE) {
|
||||
uv__pipe_read_stop((uv_pipe_t*) handle);
|
||||
} else {
|
||||
if (handle->type == UV_NAMED_PIPE) {
|
||||
uv__pipe_stop_read((uv_pipe_t*) handle);
|
||||
} else {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
}
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(handle->loop, handle);
|
||||
}
|
||||
|
||||
@@ -136,7 +134,8 @@ int uv_write(uv_write_t* req,
|
||||
err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
|
||||
break;
|
||||
case UV_NAMED_PIPE:
|
||||
err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
|
||||
err = uv__pipe_write(
|
||||
loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
|
||||
break;
|
||||
case UV_TTY:
|
||||
err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
|
||||
@@ -158,25 +157,18 @@ int uv_write2(uv_write_t* req,
|
||||
uv_loop_t* loop = handle->loop;
|
||||
int err;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_WRITABLE)) {
|
||||
if (send_handle == NULL) {
|
||||
return uv_write(req, handle, bufs, nbufs, cb);
|
||||
}
|
||||
|
||||
if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) {
|
||||
return UV_EINVAL;
|
||||
} else if (!(handle->flags & UV_HANDLE_WRITABLE)) {
|
||||
return UV_EPIPE;
|
||||
}
|
||||
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
switch (handle->type) {
|
||||
case UV_NAMED_PIPE:
|
||||
err = uv_pipe_write2(loop,
|
||||
req,
|
||||
(uv_pipe_t*) handle,
|
||||
bufs,
|
||||
nbufs,
|
||||
send_handle,
|
||||
cb);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
err = uv__pipe_write(
|
||||
loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
@@ -184,7 +176,7 @@ int uv_write2(uv_write_t* req,
|
||||
int uv_try_write(uv_stream_t* stream,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs) {
|
||||
if (stream->flags & UV__HANDLE_CLOSING)
|
||||
if (stream->flags & UV_HANDLE_CLOSING)
|
||||
return UV_EBADF;
|
||||
if (!(stream->flags & UV_HANDLE_WRITABLE))
|
||||
return UV_EPIPE;
|
||||
|
||||
@@ -99,8 +99,8 @@ static int uv_tcp_set_socket(uv_loop_t* loop,
|
||||
if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
|
||||
return GetLastError();
|
||||
|
||||
/* Associate it with the I/O completion port. */
|
||||
/* Use uv_handle_t pointer as completion key. */
|
||||
/* Associate it with the I/O completion port. Use uv_handle_t pointer as
|
||||
* completion key. */
|
||||
if (CreateIoCompletionPort((HANDLE)socket,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)socket,
|
||||
@@ -118,15 +118,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop,
|
||||
non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
|
||||
}
|
||||
|
||||
if (pSetFileCompletionNotificationModes &&
|
||||
!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
|
||||
if (pSetFileCompletionNotificationModes((HANDLE) socket,
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
||||
if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
|
||||
UCHAR sfcnm_flags =
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
|
||||
if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags))
|
||||
return GetLastError();
|
||||
}
|
||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_TCP_NODELAY) {
|
||||
@@ -220,7 +217,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
|
||||
|
||||
err = 0;
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
} else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
|
||||
err = WSAGetLastError();
|
||||
@@ -236,7 +233,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
|
||||
@@ -326,9 +323,9 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
|
||||
|
||||
on = (flags & UV_TCP_IPV6ONLY) != 0;
|
||||
|
||||
/* TODO: how to handle errors? This may fail if there is no ipv4 stack */
|
||||
/* available, or when run on XP/2003 which have no support for dualstack */
|
||||
/* sockets. For now we're silently ignoring the error. */
|
||||
/* TODO: how to handle errors? This may fail if there is no ipv4 stack
|
||||
* available, or when run on XP/2003 which have no support for dualstack
|
||||
* sockets. For now we're silently ignoring the error. */
|
||||
setsockopt(handle->socket,
|
||||
IPPROTO_IPV6,
|
||||
IPV6_V6ONLY,
|
||||
@@ -626,9 +623,9 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
|
||||
uv_tcp_queue_accept(handle, req);
|
||||
}
|
||||
|
||||
/* Initialize other unused requests too, because uv_tcp_endgame */
|
||||
/* doesn't know how how many requests were initialized, so it will */
|
||||
/* try to clean up {uv_simultaneous_server_accepts} requests. */
|
||||
/* Initialize other unused requests too, because uv_tcp_endgame doesn't
|
||||
* know how many requests were initialized, so it will try to clean up
|
||||
* {uv_simultaneous_server_accepts} requests. */
|
||||
for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
|
||||
req = &handle->tcp.serv.accept_reqs[i];
|
||||
UV_REQ_INIT(req, UV_ACCEPT);
|
||||
@@ -683,7 +680,7 @@ int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
req->next_pending = NULL;
|
||||
req->accept_socket = INVALID_SOCKET;
|
||||
|
||||
if (!(server->flags & UV__HANDLE_CLOSING)) {
|
||||
if (!(server->flags & UV_HANDLE_CLOSING)) {
|
||||
/* Check if we're in a middle of changing the number of pending accepts. */
|
||||
if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
|
||||
uv_tcp_queue_accept(server, req);
|
||||
@@ -721,8 +718,8 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
|
||||
handle->alloc_cb = alloc_cb;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a */
|
||||
/* read request pending. */
|
||||
/* If reading was stopped and then started again, there could still be a read
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
|
||||
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
|
||||
!handle->read_req.event_handle) {
|
||||
@@ -948,6 +945,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
uv_req_t* req) {
|
||||
DWORD bytes, flags, err;
|
||||
uv_buf_t buf;
|
||||
int count;
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
@@ -965,8 +963,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
err = GET_REQ_SOCK_ERROR(req);
|
||||
|
||||
if (err == WSAECONNABORTED) {
|
||||
/*
|
||||
* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
|
||||
/* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
|
||||
*/
|
||||
err = WSAECONNRESET;
|
||||
}
|
||||
@@ -1003,7 +1000,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
/* Do nonblocking reads until the buffer is empty */
|
||||
while (handle->flags & UV_HANDLE_READING) {
|
||||
count = 32;
|
||||
while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
@@ -1046,8 +1044,8 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
|
||||
if (err == WSAECONNABORTED) {
|
||||
/* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
|
||||
/* Unix. */
|
||||
/* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with
|
||||
* Unix. */
|
||||
err = WSAECONNRESET;
|
||||
}
|
||||
|
||||
@@ -1119,10 +1117,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
assert(handle->type == UV_TCP);
|
||||
|
||||
/* If handle->accepted_socket is not a valid socket, then */
|
||||
/* uv_queue_accept must have failed. This is a serious error. We stop */
|
||||
/* accepting connections and report this error to the connection */
|
||||
/* callback. */
|
||||
/* If handle->accepted_socket is not a valid socket, then uv_queue_accept
|
||||
* must have failed. This is a serious error. We stop accepting connections
|
||||
* and report this error to the connection callback. */
|
||||
if (req->accept_socket == INVALID_SOCKET) {
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
handle->flags &= ~UV_HANDLE_LISTENING;
|
||||
@@ -1147,9 +1144,9 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
|
||||
}
|
||||
} else {
|
||||
/* Error related to accepted socket is ignored because the server */
|
||||
/* socket may still be healthy. If the server socket is broken */
|
||||
/* uv_queue_accept will detect it. */
|
||||
/* Error related to accepted socket is ignored because the server socket
|
||||
* may still be healthy. If the server socket is broken uv_queue_accept
|
||||
* will detect it. */
|
||||
closesocket(req->accept_socket);
|
||||
req->accept_socket = INVALID_SOCKET;
|
||||
if (handle->flags & UV_HANDLE_LISTENING) {
|
||||
@@ -1171,7 +1168,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
|
||||
err = 0;
|
||||
if (REQ_SUCCESS(req)) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
/* use UV_ECANCELED for consistency with Unix */
|
||||
err = ERROR_OPERATION_ABORTED;
|
||||
} else if (setsockopt(handle->socket,
|
||||
@@ -1194,40 +1191,76 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
|
||||
int tcp_connection) {
|
||||
int uv__tcp_xfer_export(uv_tcp_t* handle,
|
||||
int target_pid,
|
||||
uv__ipc_socket_xfer_type_t* xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
*xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION;
|
||||
} else {
|
||||
*xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER;
|
||||
/* We're about to share the socket with another process. Because this is a
|
||||
* listening socket, we assume that the other process will be accepting
|
||||
* connections on it. Thus, before sharing the socket with another process,
|
||||
* we call listen here in the parent process. */
|
||||
if (!(handle->flags & UV_HANDLE_LISTENING)) {
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
if (handle->delayed_error == 0 &&
|
||||
listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
|
||||
handle->delayed_error = WSAGetLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info))
|
||||
return WSAGetLastError();
|
||||
xfer_info->delayed_error = handle->delayed_error;
|
||||
|
||||
/* Mark the local copy of the handle as 'shared' so we behave in a way that's
|
||||
* friendly to the process(es) that we share the socket with. */
|
||||
handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
uv__ipc_socket_xfer_type_t xfer_type,
|
||||
uv__ipc_socket_xfer_info_t* xfer_info) {
|
||||
int err;
|
||||
SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&socket_info_ex->socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
SOCKET socket;
|
||||
|
||||
assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER ||
|
||||
xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION);
|
||||
|
||||
socket = WSASocketW(FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
FROM_PROTOCOL_INFO,
|
||||
&xfer_info->socket_info,
|
||||
0,
|
||||
WSA_FLAG_OVERLAPPED);
|
||||
|
||||
if (socket == INVALID_SOCKET) {
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
err = uv_tcp_set_socket(tcp->loop,
|
||||
tcp,
|
||||
socket,
|
||||
socket_info_ex->socket_info.iAddressFamily,
|
||||
1);
|
||||
err = uv_tcp_set_socket(
|
||||
tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
|
||||
if (err) {
|
||||
closesocket(socket);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (tcp_connection) {
|
||||
tcp->delayed_error = xfer_info->delayed_error;
|
||||
tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
|
||||
uv_connection_init((uv_stream_t*)tcp);
|
||||
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
|
||||
tcp->flags |= UV_HANDLE_BOUND;
|
||||
tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
tcp->delayed_error = socket_info_ex->delayed_error;
|
||||
|
||||
tcp->loop->active_tcp_streams++;
|
||||
return 0;
|
||||
}
|
||||
@@ -1273,39 +1306,6 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
|
||||
LPWSAPROTOCOL_INFOW protocol_info) {
|
||||
if (!(handle->flags & UV_HANDLE_CONNECTION)) {
|
||||
/*
|
||||
* We're about to share the socket with another process. Because
|
||||
* this is a listening socket, we assume that the other process will
|
||||
* be accepting connections on it. So, before sharing the socket
|
||||
* with another process, we call listen here in the parent process.
|
||||
*/
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_LISTENING)) {
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!(handle->delayed_error)) {
|
||||
if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
|
||||
handle->delayed_error = WSAGetLastError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
|
||||
return WSAGetLastError();
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
||||
if (handle->flags & UV_HANDLE_CONNECTION) {
|
||||
return UV_EINVAL;
|
||||
@@ -1346,8 +1346,8 @@ static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
|
||||
non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
|
||||
uv_tcp_non_ifs_lsp_ipv4;
|
||||
|
||||
/* If there are non-ifs LSPs then try to obtain a base handle for the */
|
||||
/* socket. This will always fail on Windows XP/3k. */
|
||||
/* If there are non-ifs LSPs then try to obtain a base handle for the socket.
|
||||
* This will always fail on Windows XP/3k. */
|
||||
if (non_ifs_lsp) {
|
||||
DWORD bytes;
|
||||
if (WSAIoctl(socket,
|
||||
@@ -1379,38 +1379,37 @@ void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
|
||||
int close_socket = 1;
|
||||
|
||||
if (tcp->flags & UV_HANDLE_READ_PENDING) {
|
||||
/* In order for winsock to do a graceful close there must not be any */
|
||||
/* any pending reads, or the socket must be shut down for writing */
|
||||
/* In order for winsock to do a graceful close there must not be any any
|
||||
* pending reads, or the socket must be shut down for writing */
|
||||
if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
|
||||
/* Just do shutdown on non-shared sockets, which ensures graceful close. */
|
||||
shutdown(tcp->socket, SD_SEND);
|
||||
|
||||
} else if (uv_tcp_try_cancel_io(tcp) == 0) {
|
||||
/* In case of a shared socket, we try to cancel all outstanding I/O, */
|
||||
/* If that works, don't close the socket yet - wait for the read req to */
|
||||
/* return and close the socket in uv_tcp_endgame. */
|
||||
/* In case of a shared socket, we try to cancel all outstanding I/O,. If
|
||||
* that works, don't close the socket yet - wait for the read req to
|
||||
* return and close the socket in uv_tcp_endgame. */
|
||||
close_socket = 0;
|
||||
|
||||
} else {
|
||||
/* When cancelling isn't possible - which could happen when an LSP is */
|
||||
/* present on an old Windows version, we will have to close the socket */
|
||||
/* with a read pending. That is not nice because trailing sent bytes */
|
||||
/* may not make it to the other side. */
|
||||
/* When cancelling isn't possible - which could happen when an LSP is
|
||||
* present on an old Windows version, we will have to close the socket
|
||||
* with a read pending. That is not nice because trailing sent bytes may
|
||||
* not make it to the other side. */
|
||||
}
|
||||
|
||||
} else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
|
||||
tcp->tcp.serv.accept_reqs != NULL) {
|
||||
/* Under normal circumstances closesocket() will ensure that all pending */
|
||||
/* accept reqs are canceled. However, when the socket is shared the */
|
||||
/* presence of another reference to the socket in another process will */
|
||||
/* keep the accept reqs going, so we have to ensure that these are */
|
||||
/* canceled. */
|
||||
/* Under normal circumstances closesocket() will ensure that all pending
|
||||
* accept reqs are canceled. However, when the socket is shared the
|
||||
* presence of another reference to the socket in another process will keep
|
||||
* the accept reqs going, so we have to ensure that these are canceled. */
|
||||
if (uv_tcp_try_cancel_io(tcp) != 0) {
|
||||
/* When cancellation is not possible, there is another option: we can */
|
||||
/* close the incoming sockets, which will also cancel the accept */
|
||||
/* operations. However this is not cool because we might inadvertently */
|
||||
/* close a socket that just accepted a new connection, which will */
|
||||
/* cause the connection to be aborted. */
|
||||
/* When cancellation is not possible, there is another option: we can
|
||||
* close the incoming sockets, which will also cancel the accept
|
||||
* operations. However this is not cool because we might inadvertently
|
||||
* close a socket that just accepted a new connection, which will cause
|
||||
* the connection to be aborted. */
|
||||
unsigned int i;
|
||||
for (i = 0; i < uv_simultaneous_server_accepts; i++) {
|
||||
uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
|
||||
|
||||
@@ -23,29 +23,15 @@
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(__MINGW64_VERSION_MAJOR)
|
||||
/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
|
||||
* require this header in some versions of mingw64. */
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
|
||||
|
||||
#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
|
||||
|
||||
static int uv_cond_fallback_init(uv_cond_t* cond);
|
||||
static void uv_cond_fallback_destroy(uv_cond_t* cond);
|
||||
static void uv_cond_fallback_signal(uv_cond_t* cond);
|
||||
static void uv_cond_fallback_broadcast(uv_cond_t* cond);
|
||||
static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
|
||||
static int uv_cond_fallback_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex, uint64_t timeout);
|
||||
|
||||
static int uv_cond_condvar_init(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_destroy(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_signal(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_broadcast(uv_cond_t* cond);
|
||||
static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
|
||||
static int uv_cond_condvar_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex, uint64_t timeout);
|
||||
|
||||
|
||||
static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
|
||||
DWORD result;
|
||||
HANDLE existing_event, created_event;
|
||||
@@ -69,8 +55,8 @@ static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
|
||||
guard->ran = 1;
|
||||
|
||||
} else {
|
||||
/* We lost the race. Destroy the event we created and wait for the */
|
||||
/* existing one to become signaled. */
|
||||
/* We lost the race. Destroy the event we created and wait for the existing
|
||||
* one to become signaled. */
|
||||
CloseHandle(created_event);
|
||||
result = WaitForSingleObject(existing_event, INFINITE);
|
||||
assert(result == WAIT_OBJECT_0);
|
||||
@@ -138,7 +124,7 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
|
||||
ctx->arg = arg;
|
||||
|
||||
/* Create the thread in suspended state so we have a chance to pass
|
||||
* its own creation handle to it */
|
||||
* its own creation handle to it */
|
||||
thread = (HANDLE) _beginthreadex(NULL,
|
||||
0,
|
||||
uv__thread_start,
|
||||
@@ -377,220 +363,35 @@ int uv_sem_trywait(uv_sem_t* sem) {
|
||||
}
|
||||
|
||||
|
||||
/* This condition variable implementation is based on the SetEvent solution
|
||||
* (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||
* We could not use the SignalObjectAndWait solution (section 3.4) because
|
||||
* it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
|
||||
* uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
|
||||
*/
|
||||
|
||||
static int uv_cond_fallback_init(uv_cond_t* cond) {
|
||||
int err;
|
||||
|
||||
/* Initialize the count to 0. */
|
||||
cond->fallback.waiters_count = 0;
|
||||
|
||||
InitializeCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
|
||||
/* Create an auto-reset event. */
|
||||
cond->fallback.signal_event = CreateEvent(NULL, /* no security */
|
||||
FALSE, /* auto-reset event */
|
||||
FALSE, /* non-signaled initially */
|
||||
NULL); /* unnamed */
|
||||
if (!cond->fallback.signal_event) {
|
||||
err = GetLastError();
|
||||
goto error2;
|
||||
}
|
||||
|
||||
/* Create a manual-reset event. */
|
||||
cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */
|
||||
TRUE, /* manual-reset */
|
||||
FALSE, /* non-signaled */
|
||||
NULL); /* unnamed */
|
||||
if (!cond->fallback.broadcast_event) {
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
CloseHandle(cond->fallback.signal_event);
|
||||
error2:
|
||||
DeleteCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
|
||||
static int uv_cond_condvar_init(uv_cond_t* cond) {
|
||||
pInitializeConditionVariable(&cond->cond_var);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cond_init(uv_cond_t* cond) {
|
||||
uv__once_init();
|
||||
|
||||
if (HAVE_CONDVAR_API())
|
||||
return uv_cond_condvar_init(cond);
|
||||
else
|
||||
return uv_cond_fallback_init(cond);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_fallback_destroy(uv_cond_t* cond) {
|
||||
if (!CloseHandle(cond->fallback.broadcast_event))
|
||||
abort();
|
||||
if (!CloseHandle(cond->fallback.signal_event))
|
||||
abort();
|
||||
DeleteCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_condvar_destroy(uv_cond_t* cond) {
|
||||
/* nothing to do */
|
||||
InitializeConditionVariable(&cond->cond_var);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_cond_destroy(uv_cond_t* cond) {
|
||||
if (HAVE_CONDVAR_API())
|
||||
uv_cond_condvar_destroy(cond);
|
||||
else
|
||||
uv_cond_fallback_destroy(cond);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_fallback_signal(uv_cond_t* cond) {
|
||||
int have_waiters;
|
||||
|
||||
/* Avoid race conditions. */
|
||||
EnterCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
have_waiters = cond->fallback.waiters_count > 0;
|
||||
LeaveCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
|
||||
if (have_waiters)
|
||||
SetEvent(cond->fallback.signal_event);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_condvar_signal(uv_cond_t* cond) {
|
||||
pWakeConditionVariable(&cond->cond_var);
|
||||
/* nothing to do */
|
||||
(void) &cond;
|
||||
}
|
||||
|
||||
|
||||
void uv_cond_signal(uv_cond_t* cond) {
|
||||
if (HAVE_CONDVAR_API())
|
||||
uv_cond_condvar_signal(cond);
|
||||
else
|
||||
uv_cond_fallback_signal(cond);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
|
||||
int have_waiters;
|
||||
|
||||
/* Avoid race conditions. */
|
||||
EnterCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
have_waiters = cond->fallback.waiters_count > 0;
|
||||
LeaveCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
|
||||
if (have_waiters)
|
||||
SetEvent(cond->fallback.broadcast_event);
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
|
||||
pWakeAllConditionVariable(&cond->cond_var);
|
||||
WakeConditionVariable(&cond->cond_var);
|
||||
}
|
||||
|
||||
|
||||
void uv_cond_broadcast(uv_cond_t* cond) {
|
||||
if (HAVE_CONDVAR_API())
|
||||
uv_cond_condvar_broadcast(cond);
|
||||
else
|
||||
uv_cond_fallback_broadcast(cond);
|
||||
}
|
||||
|
||||
|
||||
static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
|
||||
DWORD dwMilliseconds) {
|
||||
DWORD result;
|
||||
int last_waiter;
|
||||
HANDLE handles[2] = {
|
||||
cond->fallback.signal_event,
|
||||
cond->fallback.broadcast_event
|
||||
};
|
||||
|
||||
/* Avoid race conditions. */
|
||||
EnterCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
cond->fallback.waiters_count++;
|
||||
LeaveCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
|
||||
/* It's ok to release the <mutex> here since Win32 manual-reset events */
|
||||
/* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
|
||||
/* bug. */
|
||||
uv_mutex_unlock(mutex);
|
||||
|
||||
/* Wait for either event to become signaled due to <uv_cond_signal> being */
|
||||
/* called or <uv_cond_broadcast> being called. */
|
||||
result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
|
||||
|
||||
EnterCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
cond->fallback.waiters_count--;
|
||||
last_waiter = result == WAIT_OBJECT_0 + 1
|
||||
&& cond->fallback.waiters_count == 0;
|
||||
LeaveCriticalSection(&cond->fallback.waiters_count_lock);
|
||||
|
||||
/* Some thread called <pthread_cond_broadcast>. */
|
||||
if (last_waiter) {
|
||||
/* We're the last waiter to be notified or to stop waiting, so reset the */
|
||||
/* the manual-reset event. */
|
||||
ResetEvent(cond->fallback.broadcast_event);
|
||||
}
|
||||
|
||||
/* Reacquire the <mutex>. */
|
||||
uv_mutex_lock(mutex);
|
||||
|
||||
if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
|
||||
return 0;
|
||||
|
||||
if (result == WAIT_TIMEOUT)
|
||||
return UV_ETIMEDOUT;
|
||||
|
||||
abort();
|
||||
return -1; /* Satisfy the compiler. */
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (uv_cond_wait_helper(cond, mutex, INFINITE))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
|
||||
abort();
|
||||
WakeAllConditionVariable(&cond->cond_var);
|
||||
}
|
||||
|
||||
|
||||
void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
if (HAVE_CONDVAR_API())
|
||||
uv_cond_condvar_wait(cond, mutex);
|
||||
else
|
||||
uv_cond_fallback_wait(cond, mutex);
|
||||
if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
static int uv_cond_fallback_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex, uint64_t timeout) {
|
||||
return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
|
||||
}
|
||||
|
||||
|
||||
static int uv_cond_condvar_timedwait(uv_cond_t* cond,
|
||||
uv_mutex_t* mutex, uint64_t timeout) {
|
||||
if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
|
||||
if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
|
||||
return 0;
|
||||
if (GetLastError() != ERROR_TIMEOUT)
|
||||
abort();
|
||||
@@ -598,15 +399,6 @@ static int uv_cond_condvar_timedwait(uv_cond_t* cond,
|
||||
}
|
||||
|
||||
|
||||
int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
|
||||
uint64_t timeout) {
|
||||
if (HAVE_CONDVAR_API())
|
||||
return uv_cond_condvar_timedwait(cond, mutex, timeout);
|
||||
else
|
||||
return uv_cond_fallback_timedwait(cond, mutex, timeout);
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
|
||||
int err;
|
||||
|
||||
|
||||
@@ -1,195 +0,0 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "tree.h"
|
||||
#include "handle-inl.h"
|
||||
|
||||
|
||||
/* The number of milliseconds in one second. */
|
||||
#define UV__MILLISEC 1000
|
||||
|
||||
|
||||
void uv_update_time(uv_loop_t* loop) {
|
||||
uint64_t new_time = uv__hrtime(UV__MILLISEC);
|
||||
assert(new_time >= loop->time);
|
||||
loop->time = new_time;
|
||||
}
|
||||
|
||||
|
||||
static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
|
||||
if (a->due < b->due)
|
||||
return -1;
|
||||
if (a->due > b->due)
|
||||
return 1;
|
||||
/*
|
||||
* compare start_id when both has the same due. start_id is
|
||||
* allocated with loop->timer_counter in uv_timer_start().
|
||||
*/
|
||||
if (a->start_id < b->start_id)
|
||||
return -1;
|
||||
if (a->start_id > b->start_id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare)
|
||||
|
||||
|
||||
int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
|
||||
handle->timer_cb = NULL;
|
||||
handle->repeat = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
|
||||
uint64_t clamped_timeout;
|
||||
|
||||
clamped_timeout = loop_time + timeout;
|
||||
if (clamped_timeout < timeout)
|
||||
clamped_timeout = (uint64_t) -1;
|
||||
|
||||
return clamped_timeout;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
|
||||
uint64_t repeat) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
uv_timer_t* old;
|
||||
|
||||
if (timer_cb == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
if (uv__is_active(handle))
|
||||
uv_timer_stop(handle);
|
||||
|
||||
handle->timer_cb = timer_cb;
|
||||
handle->due = get_clamped_due_time(loop->time, timeout);
|
||||
handle->repeat = repeat;
|
||||
uv__handle_start(handle);
|
||||
|
||||
/* start_id is the second index to be compared in uv__timer_cmp() */
|
||||
handle->start_id = handle->loop->timer_counter++;
|
||||
|
||||
old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
|
||||
assert(old == NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_stop(uv_timer_t* handle) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (!uv__is_active(handle))
|
||||
return 0;
|
||||
|
||||
RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
|
||||
uv__handle_stop(handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_timer_again(uv_timer_t* handle) {
|
||||
/* If timer_cb is NULL that means that the timer was never started. */
|
||||
if (!handle->timer_cb) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (handle->repeat) {
|
||||
uv_timer_stop(handle);
|
||||
uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
handle->repeat = repeat;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
|
||||
assert(handle->type == UV_TIMER);
|
||||
return handle->repeat;
|
||||
}
|
||||
|
||||
|
||||
DWORD uv__next_timeout(const uv_loop_t* loop) {
|
||||
uv_timer_t* timer;
|
||||
int64_t delta;
|
||||
|
||||
/* Check if there are any running timers
|
||||
* Need to cast away const first, since RB_MIN doesn't know what we are
|
||||
* going to do with this return value, it can't be marked const
|
||||
*/
|
||||
timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
|
||||
if (timer) {
|
||||
delta = timer->due - loop->time;
|
||||
if (delta >= UINT_MAX - 1) {
|
||||
/* A timeout value of UINT_MAX means infinite, so that's no good. */
|
||||
return UINT_MAX - 1;
|
||||
} else if (delta < 0) {
|
||||
/* Negative timeout values are not allowed */
|
||||
return 0;
|
||||
} else {
|
||||
return (DWORD)delta;
|
||||
}
|
||||
} else {
|
||||
/* No timers */
|
||||
return INFINITE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void uv_process_timers(uv_loop_t* loop) {
|
||||
uv_timer_t* timer;
|
||||
|
||||
/* Call timer callbacks */
|
||||
for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
|
||||
timer != NULL && timer->due <= loop->time;
|
||||
timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
|
||||
|
||||
uv_timer_stop(timer);
|
||||
uv_timer_again(timer);
|
||||
timer->timer_cb((uv_timer_t*) timer);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "stdint-msvc2008.h"
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
@@ -164,7 +164,7 @@ void uv_console_init(void) {
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
0);
|
||||
if (uv__tty_console_handle != NULL) {
|
||||
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
||||
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
@@ -172,9 +172,12 @@ void uv_console_init(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
|
||||
BOOL readable;
|
||||
DWORD NumberOfEvents;
|
||||
HANDLE handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
(void)unused;
|
||||
|
||||
uv__once_init();
|
||||
handle = (HANDLE) uv__get_osfhandle(fd);
|
||||
@@ -199,14 +202,15 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
|
||||
if (!readable) {
|
||||
/* Obtain the screen buffer info with the output handle. */
|
||||
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Obtain the the tty_output_lock because the virtual window state is */
|
||||
/* shared between all uv_tty_t handles. */
|
||||
/* Obtain the tty_output_lock because the virtual window state is shared
|
||||
* between all uv_tty_t handles. */
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
if (uv__vterm_state == UV_UNCHECKED)
|
||||
@@ -356,6 +360,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
} else {
|
||||
was_reading = 0;
|
||||
alloc_cb = NULL;
|
||||
read_cb = NULL;
|
||||
}
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
@@ -382,12 +388,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
}
|
||||
|
||||
|
||||
int uv_is_tty(uv_file file) {
|
||||
DWORD result;
|
||||
return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
|
||||
@@ -484,8 +484,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
||||
bytes = MAX_INPUT_BUFFER_LENGTH;
|
||||
}
|
||||
|
||||
/* At last, unicode! */
|
||||
/* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
|
||||
/* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
|
||||
* codeunits to encode. */
|
||||
chars = bytes / 3;
|
||||
|
||||
status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
|
||||
@@ -620,10 +620,10 @@ static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
/* These mappings are the same as Cygwin's. Unmodified and alt-modified */
|
||||
/* keypad keys comply with linux console, modifiers comply with xterm */
|
||||
/* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
|
||||
/* f6..f12 with and without modifiers comply with rxvt. */
|
||||
/* These mappings are the same as Cygwin's. Unmodified and alt-modified
|
||||
* keypad keys comply with linux console, modifiers comply with xterm
|
||||
* modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
|
||||
* f12 with and without modifiers comply with rxvt. */
|
||||
VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
|
||||
VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
|
||||
VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
|
||||
@@ -706,8 +706,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Windows sends a lot of events that we're not interested in, so buf */
|
||||
/* will be allocated on demand, when there's actually something to emit. */
|
||||
/* Windows sends a lot of events that we're not interested in, so buf will be
|
||||
* allocated on demand, when there's actually something to emit. */
|
||||
buf = uv_null_buf_;
|
||||
buf_used = 0;
|
||||
|
||||
@@ -733,16 +733,17 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore keyup events, unless the left alt key was held and a valid */
|
||||
/* unicode character was emitted. */
|
||||
if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
|
||||
KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
|
||||
/* Ignore keyup events, unless the left alt key was held and a valid
|
||||
* unicode character was emitted. */
|
||||
if (!KEV.bKeyDown &&
|
||||
KEV.wVirtualKeyCode != VK_MENU &&
|
||||
KEV.uChar.UnicodeChar != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ignore keypresses to numpad number keys if the left alt is held */
|
||||
/* because the user is composing a character, or windows simulating */
|
||||
/* this. */
|
||||
/* Ignore keypresses to numpad number keys if the left alt is held
|
||||
* because the user is composing a character, or windows simulating this.
|
||||
*/
|
||||
if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
|
||||
!(KEV.dwControlKeyState & ENHANCED_KEY) &&
|
||||
(KEV.wVirtualKeyCode == VK_INSERT ||
|
||||
@@ -779,8 +780,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Prefix with \u033 if alt was held, but alt was not used as part */
|
||||
/* a compose sequence. */
|
||||
/* Prefix with \u033 if alt was held, but alt was not used as part a
|
||||
* compose sequence. */
|
||||
if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
||||
&& !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
|
||||
RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
|
||||
@@ -793,8 +794,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
if (KEV.uChar.UnicodeChar >= 0xDC00 &&
|
||||
KEV.uChar.UnicodeChar < 0xE000) {
|
||||
/* UTF-16 surrogate pair */
|
||||
WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
|
||||
KEV.uChar.UnicodeChar};
|
||||
WCHAR utf16_buffer[2];
|
||||
utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
|
||||
utf16_buffer[1] = KEV.uChar.UnicodeChar;
|
||||
char_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
utf16_buffer,
|
||||
@@ -818,8 +820,8 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
/* Whatever happened, the last character wasn't a high surrogate. */
|
||||
handle->tty.rd.last_utf16_high_surrogate = 0;
|
||||
|
||||
/* If the utf16 character(s) couldn't be converted something must */
|
||||
/* be wrong. */
|
||||
/* If the utf16 character(s) couldn't be converted something must be
|
||||
* wrong. */
|
||||
if (!char_len) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
@@ -943,21 +945,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
handle->read_cb((uv_stream_t*) handle,
|
||||
uv_translate_sys_error(GET_REQ_ERROR(req)),
|
||||
&buf);
|
||||
} else {
|
||||
/* The read was cancelled, or whatever we don't care */
|
||||
handle->read_cb((uv_stream_t*) handle, 0, &buf);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
|
||||
/* Read successful */
|
||||
/* TODO: read unicode, convert to utf-8 */
|
||||
if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
|
||||
req->u.io.overlapped.InternalHigh != 0) {
|
||||
/* Read successful. TODO: read unicode, convert to utf-8 */
|
||||
DWORD bytes = req->u.io.overlapped.InternalHigh;
|
||||
handle->read_cb((uv_stream_t*) handle, bytes, &buf);
|
||||
} else {
|
||||
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
|
||||
handle->read_cb((uv_stream_t*) handle, 0, &buf);
|
||||
}
|
||||
handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
|
||||
}
|
||||
|
||||
/* Wait for more input events. */
|
||||
@@ -975,9 +971,9 @@ void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
assert(handle->type == UV_TTY);
|
||||
assert(handle->flags & UV_HANDLE_TTY_READABLE);
|
||||
|
||||
/* If the read_line_buffer member is zero, it must have been an raw read. */
|
||||
/* Otherwise it was a line-buffered read. */
|
||||
/* FIXME: This is quite obscure. Use a flag or something. */
|
||||
/* If the read_line_buffer member is zero, it must have been an raw read.
|
||||
* Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
|
||||
* flag or something. */
|
||||
if (handle->tty.rd.read_line_buffer.len == 0) {
|
||||
uv_process_tty_read_raw_req(loop, handle, req);
|
||||
} else {
|
||||
@@ -999,14 +995,14 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
handle->read_cb = read_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a */
|
||||
/* read request pending. */
|
||||
/* If reading was stopped and then started again, there could still be a read
|
||||
* request pending. */
|
||||
if (handle->flags & UV_HANDLE_READ_PENDING) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Maybe the user stopped reading half-way while processing key events. */
|
||||
/* Short-circuit if this could be the case. */
|
||||
/* Maybe the user stopped reading half-way while processing key events.
|
||||
* Short-circuit if this could be the case. */
|
||||
if (handle->tty.rd.last_key_len > 0) {
|
||||
SET_REQ_SUCCESS(&handle->read_req);
|
||||
uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
|
||||
@@ -1033,9 +1029,10 @@ int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
return 0;
|
||||
|
||||
if (handle->flags & UV_HANDLE_TTY_RAW) {
|
||||
/* Cancel raw read */
|
||||
/* Write some bullshit event to force the console wait to return. */
|
||||
/* Cancel raw read. Write some bullshit event to force the console wait to
|
||||
* return. */
|
||||
memset(&record, 0, sizeof record);
|
||||
record.EventType = FOCUS_EVENT;
|
||||
if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
|
||||
return GetLastError();
|
||||
}
|
||||
@@ -1116,8 +1113,8 @@ static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
|
||||
uv_tty_virtual_offset = info->dwCursorPosition.Y;
|
||||
} else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
|
||||
uv_tty_virtual_height + 1) {
|
||||
/* If suddenly find the cursor outside of the virtual window, it must */
|
||||
/* have somehow scrolled. Update the virtual window offset. */
|
||||
/* If suddenly find the cursor outside of the virtual window, it must have
|
||||
* somehow scrolled. Update the virtual window offset. */
|
||||
uv_tty_virtual_offset = info->dwCursorPosition.Y -
|
||||
uv_tty_virtual_height + 1;
|
||||
}
|
||||
@@ -1304,8 +1301,8 @@ static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
|
||||
x2 = 0;
|
||||
x2r = 1;
|
||||
} else {
|
||||
/* Clear to end of row. We pretend the console is 65536 characters wide, */
|
||||
/* uv_tty_make_real_coord will clip it to the actual console width. */
|
||||
/* Clear to end of row. We pretend the console is 65536 characters wide,
|
||||
* uv_tty_make_real_coord will clip it to the actual console width. */
|
||||
x2 = 0xffff;
|
||||
x2r = 0;
|
||||
}
|
||||
@@ -1613,8 +1610,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
const uv_buf_t bufs[],
|
||||
unsigned int nbufs,
|
||||
DWORD* error) {
|
||||
/* We can only write 8k characters at a time. Windows can't handle */
|
||||
/* much more characters in a single console write anyway. */
|
||||
/* We can only write 8k characters at a time. Windows can't handle much more
|
||||
* characters in a single console write anyway. */
|
||||
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
|
||||
WCHAR* utf16_buffer;
|
||||
DWORD utf16_buf_used = 0;
|
||||
@@ -1650,9 +1647,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
unsigned char previous_eol = handle->tty.wr.previous_eol;
|
||||
unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
|
||||
|
||||
/* Store the error here. If we encounter an error, stop trying to do i/o */
|
||||
/* but keep parsing the buffer so we leave the parser in a consistent */
|
||||
/* state. */
|
||||
/* Store the error here. If we encounter an error, stop trying to do i/o but
|
||||
* keep parsing the buffer so we leave the parser in a consistent state. */
|
||||
*error = ERROR_SUCCESS;
|
||||
|
||||
utf16_buffer = utf16_buf;
|
||||
@@ -1700,9 +1696,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
for (j = 0; j < buf.len; j++) {
|
||||
unsigned char c = buf.base[j];
|
||||
|
||||
/* Run the character through the utf8 decoder We happily accept non */
|
||||
/* shortest form encodings and invalid code points - there's no real */
|
||||
/* harm that can be done. */
|
||||
/* Run the character through the utf8 decoder We happily accept non
|
||||
* shortest form encodings and invalid code points - there's no real harm
|
||||
* that can be done. */
|
||||
if (utf8_bytes_left == 0) {
|
||||
/* Read utf-8 start byte */
|
||||
DWORD first_zero_bit;
|
||||
@@ -1742,8 +1738,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
/* Start byte where continuation was expected. */
|
||||
utf8_bytes_left = 0;
|
||||
utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
|
||||
/* Patch buf offset so this character will be parsed again as a */
|
||||
/* start byte. */
|
||||
/* Patch buf offset so this character will be parsed again as a start
|
||||
* byte. */
|
||||
j--;
|
||||
}
|
||||
|
||||
@@ -1776,8 +1772,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
case '_':
|
||||
case 'P':
|
||||
case ']':
|
||||
/* Not supported, but we'll have to parse until we see a stop */
|
||||
/* code, e.g. ESC \ or BEL. */
|
||||
/* Not supported, but we'll have to parse until we see a stop code,
|
||||
* e. g. ESC \ or BEL. */
|
||||
ansi_parser_state = ANSI_ST_CONTROL;
|
||||
continue;
|
||||
|
||||
@@ -1859,8 +1855,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* If ANSI_IN_ARG is not set, add another argument and */
|
||||
/* default it to 0. */
|
||||
/* If ANSI_IN_ARG is not set, add another argument and default it
|
||||
* to 0. */
|
||||
|
||||
/* Check for too many arguments */
|
||||
if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
@@ -1874,9 +1871,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
|
||||
} else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
|
||||
handle->tty.wr.ansi_csi_argc == 0) {
|
||||
/* Ignores '?' if it is the first character after CSI[ */
|
||||
/* This is an extension character from the VT100 codeset */
|
||||
/* that is supported and used by most ANSI terminals today. */
|
||||
/* Ignores '?' if it is the first character after CSI[. This is an
|
||||
* extension character from the VT100 codeset that is supported and
|
||||
* used by most ANSI terminals today. */
|
||||
continue;
|
||||
|
||||
} else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
|
||||
@@ -2006,8 +2003,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
continue;
|
||||
|
||||
} else {
|
||||
/* We don't support commands that use private mode characters or */
|
||||
/* intermediaries. Ignore the rest of the sequence. */
|
||||
/* We don't support commands that use private mode characters or
|
||||
* intermediaries. Ignore the rest of the sequence. */
|
||||
ansi_parser_state |= ANSI_IGNORE;
|
||||
continue;
|
||||
}
|
||||
@@ -2020,8 +2017,8 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
}
|
||||
|
||||
} else if (ansi_parser_state & ANSI_ST_CONTROL) {
|
||||
/* Unsupported control code */
|
||||
/* Ignore everything until we see BEL or ESC \ */
|
||||
/* Unsupported control code.
|
||||
* Ignore everything until we see `BEL` or `ESC \`. */
|
||||
if (ansi_parser_state & ANSI_IN_STRING) {
|
||||
if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
|
||||
if (utf8_codepoint == '"') {
|
||||
@@ -2055,9 +2052,9 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
abort();
|
||||
}
|
||||
|
||||
/* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
|
||||
/* windows console doesn't really support UTF-16, so just emit the */
|
||||
/* replacement character. */
|
||||
/* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
|
||||
* console doesn't really support UTF-16, so just emit the replacement
|
||||
* character. */
|
||||
if (utf8_codepoint > 0xffff) {
|
||||
utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
|
||||
}
|
||||
@@ -2071,10 +2068,10 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
utf16_buf[utf16_buf_used++] = L'\r';
|
||||
utf16_buf[utf16_buf_used++] = L'\n';
|
||||
} else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
|
||||
/* \n was followed by \r; do not print the \r, since */
|
||||
/* the source was either \r\n\r (so the second \r is */
|
||||
/* redundant) or was \n\r (so the \n was processed */
|
||||
/* by the last case and an \r automatically inserted). */
|
||||
/* \n was followed by \r; do not print the \r, since the source was
|
||||
* either \r\n\r (so the second \r is redundant) or was \n\r (so the
|
||||
* \n was processed by the last case and an \r automatically
|
||||
* inserted). */
|
||||
} else {
|
||||
/* \r without \n; print \r as-is. */
|
||||
ENSURE_BUFFER_SPACE(1);
|
||||
@@ -2182,14 +2179,14 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
void uv_tty_close(uv_tty_t* handle) {
|
||||
assert(handle->u.fd == -1 || handle->u.fd > 2);
|
||||
if (handle->flags & UV_HANDLE_READING)
|
||||
uv_tty_read_stop(handle);
|
||||
|
||||
if (handle->u.fd == -1)
|
||||
CloseHandle(handle->handle);
|
||||
else
|
||||
close(handle->u.fd);
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING)
|
||||
uv_tty_read_stop(handle);
|
||||
|
||||
handle->u.fd = -1;
|
||||
handle->handle = INVALID_HANDLE_VALUE;
|
||||
handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
||||
@@ -2209,7 +2206,7 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
if (handle->stream.conn.shutdown_req->cb) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING) {
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
|
||||
} else {
|
||||
handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
|
||||
@@ -2222,10 +2219,10 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
/* The wait handle used for raw reading should be unregistered when the */
|
||||
/* wait callback runs. */
|
||||
/* The wait handle used for raw reading should be unregistered when the
|
||||
* wait callback runs. */
|
||||
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
|
||||
handle->tty.rd.read_raw_wait == NULL);
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
/* Associate it with the I/O completion port. */
|
||||
/* Use uv_handle_t pointer as completion key. */
|
||||
/* Associate it with the I/O completion port. Use uv_handle_t pointer as
|
||||
* completion key. */
|
||||
if (CreateIoCompletionPort((HANDLE)socket,
|
||||
loop->iocp,
|
||||
(ULONG_PTR)socket,
|
||||
@@ -83,31 +83,28 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
if (pSetFileCompletionNotificationModes) {
|
||||
/* All known Windows that support SetFileCompletionNotificationModes */
|
||||
/* have a bug that makes it impossible to use this function in */
|
||||
/* conjunction with datagram sockets. We can work around that but only */
|
||||
/* if the user is using the default UDP driver (AFD) and has no other */
|
||||
/* LSPs stacked on top. Here we check whether that is the case. */
|
||||
opt_len = (int) sizeof info;
|
||||
if (getsockopt(socket,
|
||||
SOL_SOCKET,
|
||||
SO_PROTOCOL_INFOW,
|
||||
(char*) &info,
|
||||
&opt_len) == SOCKET_ERROR) {
|
||||
return GetLastError();
|
||||
}
|
||||
/* All known Windows that support SetFileCompletionNotificationModes have a
|
||||
* bug that makes it impossible to use this function in conjunction with
|
||||
* datagram sockets. We can work around that but only if the user is using
|
||||
* the default UDP driver (AFD) and has no other. LSPs stacked on top. Here
|
||||
* we check whether that is the case. */
|
||||
opt_len = (int) sizeof info;
|
||||
if (getsockopt(
|
||||
socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) ==
|
||||
SOCKET_ERROR) {
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
if (info.ProtocolChain.ChainLen == 1) {
|
||||
if (pSetFileCompletionNotificationModes((HANDLE)socket,
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||
handle->func_wsarecv = uv_wsarecv_workaround;
|
||||
handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
|
||||
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
||||
return GetLastError();
|
||||
}
|
||||
if (info.ProtocolChain.ChainLen == 1) {
|
||||
if (SetFileCompletionNotificationModes(
|
||||
(HANDLE) socket,
|
||||
FILE_SKIP_SET_EVENT_ON_HANDLE |
|
||||
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
|
||||
handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
|
||||
handle->func_wsarecv = uv_wsarecv_workaround;
|
||||
handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
|
||||
} else if (GetLastError() != ERROR_INVALID_FUNCTION) {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +188,7 @@ void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
|
||||
|
||||
void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (handle->flags & UV__HANDLE_CLOSING &&
|
||||
if (handle->flags & UV_HANDLE_CLOSING &&
|
||||
handle->reqs_pending == 0) {
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_close(handle);
|
||||
@@ -245,12 +242,12 @@ static int uv_udp_maybe_bind(uv_udp_t* handle,
|
||||
handle->flags |= UV_HANDLE_IPV6;
|
||||
|
||||
if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
|
||||
/* On windows IPV6ONLY is on by default. */
|
||||
/* If the user doesn't specify it libuv turns it off. */
|
||||
/* On windows IPV6ONLY is on by default. If the user doesn't specify it
|
||||
* libuv turns it off. */
|
||||
|
||||
/* TODO: how to handle errors? This may fail if there is no ipv4 stack */
|
||||
/* available, or when run on XP/2003 which have no support for dualstack */
|
||||
/* sockets. For now we're silently ignoring the error. */
|
||||
/* TODO: how to handle errors? This may fail if there is no ipv4 stack
|
||||
* available, or when run on XP/2003 which have no support for dualstack
|
||||
* sockets. For now we're silently ignoring the error. */
|
||||
setsockopt(handle->socket,
|
||||
IPPROTO_IPV6,
|
||||
IPV6_V6ONLY,
|
||||
@@ -369,7 +366,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
int err;
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
return WSAEALREADY;
|
||||
return UV_EALREADY;
|
||||
}
|
||||
|
||||
err = uv_udp_maybe_bind(handle,
|
||||
@@ -377,7 +374,7 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
sizeof(uv_addr_ip4_any_),
|
||||
0);
|
||||
if (err)
|
||||
return err;
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
@@ -386,8 +383,8 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
handle->recv_cb = recv_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
|
||||
/* If reading was stopped and then started again, there could still be a */
|
||||
/* recv request pending. */
|
||||
/* If reading was stopped and then started again, there could still be a recv
|
||||
* request pending. */
|
||||
if (!(handle->flags & UV_HANDLE_READ_PENDING))
|
||||
uv_udp_queue_recv(loop, handle);
|
||||
|
||||
@@ -467,19 +464,19 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
if (!REQ_SUCCESS(req)) {
|
||||
DWORD err = GET_REQ_SOCK_ERROR(req);
|
||||
if (err == WSAEMSGSIZE) {
|
||||
/* Not a real error, it just indicates that the received packet */
|
||||
/* was bigger than the receive buffer. */
|
||||
/* Not a real error, it just indicates that the received packet was
|
||||
* bigger than the receive buffer. */
|
||||
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
|
||||
/* A previous sendto operation failed; ignore this error. If */
|
||||
/* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
|
||||
/* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
|
||||
/* immediately queue a new receive. */
|
||||
/* A previous sendto operation failed; ignore this error. If zero-reading
|
||||
* we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to
|
||||
* clear out the error queue. For nonzero reads, immediately queue a new
|
||||
* receive. */
|
||||
if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
/* A real error occurred. Report the error to the user only if we're */
|
||||
/* currently reading. */
|
||||
/* A real error occurred. Report the error to the user only if we're
|
||||
* currently reading. */
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
uv_udp_recv_stop(handle);
|
||||
buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
|
||||
@@ -503,8 +500,8 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
struct sockaddr_storage from;
|
||||
int from_len;
|
||||
|
||||
/* Do a nonblocking receive */
|
||||
/* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
/* Do a nonblocking receive.
|
||||
* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
@@ -741,7 +738,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND))
|
||||
if (handle->socket == INVALID_SOCKET)
|
||||
return UV_EBADF;
|
||||
|
||||
if (addr_st.ss_family == AF_INET) {
|
||||
@@ -772,7 +769,7 @@ int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr)
|
||||
int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
|
||||
BOOL optval = (BOOL) value;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_BOUND))
|
||||
if (handle->socket == INVALID_SOCKET)
|
||||
return UV_EBADF;
|
||||
|
||||
if (setsockopt(handle->socket,
|
||||
@@ -818,7 +815,7 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
|
||||
return UV_EINVAL; \
|
||||
} \
|
||||
\
|
||||
if (!(handle->flags & UV_HANDLE_BOUND)) \
|
||||
if (handle->socket == INVALID_SOCKET) \
|
||||
return UV_EBADF; \
|
||||
\
|
||||
if (!(handle->flags & UV_HANDLE_IPV6)) { \
|
||||
|
||||
@@ -74,10 +74,6 @@
|
||||
static char *process_title;
|
||||
static CRITICAL_SECTION process_title_lock;
|
||||
|
||||
/* Cached copy of the process id, written once. */
|
||||
static DWORD current_pid = 0;
|
||||
|
||||
|
||||
/* Interval (in seconds) of the high-resolution clock. */
|
||||
static double hrtime_interval_ = 0;
|
||||
|
||||
@@ -149,8 +145,8 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
|
||||
|
||||
uv__free(utf16_buffer);
|
||||
|
||||
/* utf8_len *does* include the terminating null at this point, but the */
|
||||
/* returned size shouldn't. */
|
||||
/* utf8_len *does* include the terminating null at this point, but the
|
||||
* returned size shouldn't. */
|
||||
*size_ptr = utf8_len - 1;
|
||||
return 0;
|
||||
|
||||
@@ -173,16 +169,16 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
} else if (utf16_len > MAX_PATH) {
|
||||
/* This should be impossible; however the CRT has a code path to deal */
|
||||
/* with this scenario, so I added a check anyway. */
|
||||
/* This should be impossible; however the CRT has a code path to deal with
|
||||
* this scenario, so I added a check anyway. */
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
/* utf16_len contains the length, *not* including the terminating null. */
|
||||
utf16_buffer[utf16_len] = L'\0';
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it */
|
||||
/* points at a drive root, like c:\. Remove it if needed.*/
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
* at a drive root, like c:\. Remove it if needed. */
|
||||
if (utf16_buffer[utf16_len - 1] == L'\\' &&
|
||||
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
|
||||
utf16_len--;
|
||||
@@ -239,9 +235,9 @@ int uv_chdir(const char* dir) {
|
||||
utf16_buffer,
|
||||
MAX_PATH) == 0) {
|
||||
DWORD error = GetLastError();
|
||||
/* The maximum length of the current working directory is 260 chars, */
|
||||
/* including terminating null. If it doesn't fit, the path name must be */
|
||||
/* too long. */
|
||||
/* The maximum length of the current working directory is 260 chars,
|
||||
* including terminating null. If it doesn't fit, the path name must be too
|
||||
* long. */
|
||||
if (error == ERROR_INSUFFICIENT_BUFFER) {
|
||||
return UV_ENAMETOOLONG;
|
||||
} else {
|
||||
@@ -253,9 +249,9 @@ int uv_chdir(const char* dir) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* Windows stores the drive-local path in an "hidden" environment variable, */
|
||||
/* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
|
||||
/* update this, so we'll have to do it. */
|
||||
/* Windows stores the drive-local path in an "hidden" environment variable,
|
||||
* which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
|
||||
* this, so we'll have to do it. */
|
||||
utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
@@ -263,8 +259,8 @@ int uv_chdir(const char* dir) {
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it */
|
||||
/* points at a drive root, like c:\. Remove it if needed. */
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
* at a drive root, like c:\. Remove it if needed. */
|
||||
if (utf16_buffer[utf16_len - 1] == L'\\' &&
|
||||
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
|
||||
utf16_len--;
|
||||
@@ -272,8 +268,8 @@ int uv_chdir(const char* dir) {
|
||||
}
|
||||
|
||||
if (utf16_len < 2 || utf16_buffer[1] != L':') {
|
||||
/* Doesn't look like a drive letter could be there - probably an UNC */
|
||||
/* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
|
||||
/* Doesn't look like a drive letter could be there - probably an UNC path.
|
||||
* TODO: Need to handle win32 namespaces like \\?\C:\ ? */
|
||||
drive_letter = 0;
|
||||
} else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
|
||||
drive_letter = utf16_buffer[0];
|
||||
@@ -359,14 +355,6 @@ uv_pid_t uv_os_getppid(void) {
|
||||
}
|
||||
|
||||
|
||||
int uv_current_pid(void) {
|
||||
if (current_pid == 0) {
|
||||
current_pid = GetCurrentProcessId();
|
||||
}
|
||||
return current_pid;
|
||||
}
|
||||
|
||||
|
||||
char** uv_setup_args(int argc, char** argv) {
|
||||
return argv;
|
||||
}
|
||||
@@ -828,6 +816,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
int is_vista_or_greater;
|
||||
ULONG flags;
|
||||
|
||||
*addresses_ptr = NULL;
|
||||
*count_ptr = 0;
|
||||
|
||||
is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
|
||||
if (is_vista_or_greater) {
|
||||
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
|
||||
@@ -842,17 +833,17 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
}
|
||||
|
||||
|
||||
/* Fetch the size of the adapters reported by windows, and then get the */
|
||||
/* list itself. */
|
||||
/* Fetch the size of the adapters reported by windows, and then get the list
|
||||
* itself. */
|
||||
win_address_buf_size = 0;
|
||||
win_address_buf = NULL;
|
||||
|
||||
for (;;) {
|
||||
ULONG r;
|
||||
|
||||
/* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
|
||||
/* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
|
||||
/* win_address_buf_size. */
|
||||
/* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
|
||||
* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
|
||||
* win_address_buf_size. */
|
||||
r = GetAdaptersAddresses(AF_UNSPEC,
|
||||
flags,
|
||||
NULL,
|
||||
@@ -866,8 +857,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
|
||||
switch (r) {
|
||||
case ERROR_BUFFER_OVERFLOW:
|
||||
/* This happens when win_address_buf is NULL or too small to hold */
|
||||
/* all adapters. */
|
||||
/* This happens when win_address_buf is NULL or too small to hold all
|
||||
* adapters. */
|
||||
win_address_buf = uv__malloc(win_address_buf_size);
|
||||
if (win_address_buf == NULL)
|
||||
return UV_ENOMEM;
|
||||
@@ -901,15 +892,15 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
return UV_ENOBUFS;
|
||||
|
||||
default:
|
||||
/* Other (unspecified) errors can happen, but we don't have any */
|
||||
/* special meaning for them. */
|
||||
/* Other (unspecified) errors can happen, but we don't have any special
|
||||
* meaning for them. */
|
||||
assert(r != ERROR_SUCCESS);
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
}
|
||||
|
||||
/* Count the number of enabled interfaces and compute how much space is */
|
||||
/* needed to store their info. */
|
||||
/* Count the number of enabled interfaces and compute how much space is
|
||||
* needed to store their info. */
|
||||
count = 0;
|
||||
uv_address_buf_size = 0;
|
||||
|
||||
@@ -919,9 +910,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
|
||||
int name_size;
|
||||
|
||||
/* Interfaces that are not 'up' should not be reported. Also skip */
|
||||
/* interfaces that have no associated unicast address, as to avoid */
|
||||
/* allocating space for the name for this interface. */
|
||||
/* Interfaces that are not 'up' should not be reported. Also skip
|
||||
* interfaces that have no associated unicast address, as to avoid
|
||||
* allocating space for the name for this interface. */
|
||||
if (adapter->OperStatus != IfOperStatusUp ||
|
||||
adapter->FirstUnicastAddress == NULL)
|
||||
continue;
|
||||
@@ -941,8 +932,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
}
|
||||
uv_address_buf_size += name_size;
|
||||
|
||||
/* Count the number of addresses associated with this interface, and */
|
||||
/* compute the size. */
|
||||
/* Count the number of addresses associated with this interface, and
|
||||
* compute the size. */
|
||||
for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
|
||||
adapter->FirstUnicastAddress;
|
||||
unicast_address != NULL;
|
||||
@@ -959,8 +950,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
/* Compute the start of the uv_interface_address_t array, and the place in */
|
||||
/* the buffer where the interface names will be stored. */
|
||||
/* Compute the start of the uv_interface_address_t array, and the place in
|
||||
* the buffer where the interface names will be stored. */
|
||||
uv_address = uv_address_buf;
|
||||
name_buf = (char*) (uv_address_buf + count);
|
||||
|
||||
@@ -1199,8 +1190,8 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it */
|
||||
/* points at a drive root, like c:\. Remove it if needed.*/
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
* at a drive root, like c:\. Remove it if needed. */
|
||||
if (path[len - 1] == L'\\' &&
|
||||
!(len == 3 && path[1] == L':')) {
|
||||
len--;
|
||||
@@ -1542,3 +1533,214 @@ int uv_os_gethostname(char* buffer, size_t* size) {
|
||||
*size = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
|
||||
int r;
|
||||
|
||||
if (pid == 0)
|
||||
*handle = GetCurrentProcess();
|
||||
else
|
||||
*handle = OpenProcess(access, FALSE, pid);
|
||||
|
||||
if (*handle == NULL) {
|
||||
r = GetLastError();
|
||||
|
||||
if (r == ERROR_INVALID_PARAMETER)
|
||||
return UV_ESRCH;
|
||||
else
|
||||
return uv_translate_sys_error(r);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_getpriority(uv_pid_t pid, int* priority) {
|
||||
HANDLE handle;
|
||||
int r;
|
||||
|
||||
if (priority == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = GetPriorityClass(handle);
|
||||
|
||||
if (r == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
} else {
|
||||
/* Map Windows priority classes to Unix nice values. */
|
||||
if (r == REALTIME_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_HIGHEST;
|
||||
else if (r == HIGH_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_HIGH;
|
||||
else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_ABOVE_NORMAL;
|
||||
else if (r == NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_NORMAL;
|
||||
else if (r == BELOW_NORMAL_PRIORITY_CLASS)
|
||||
*priority = UV_PRIORITY_BELOW_NORMAL;
|
||||
else /* IDLE_PRIORITY_CLASS */
|
||||
*priority = UV_PRIORITY_LOW;
|
||||
|
||||
r = 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_setpriority(uv_pid_t pid, int priority) {
|
||||
HANDLE handle;
|
||||
int priority_class;
|
||||
int r;
|
||||
|
||||
/* Map Unix nice values to Windows priority classes. */
|
||||
if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
|
||||
return UV_EINVAL;
|
||||
else if (priority < UV_PRIORITY_HIGH)
|
||||
priority_class = REALTIME_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_ABOVE_NORMAL)
|
||||
priority_class = HIGH_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_NORMAL)
|
||||
priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_BELOW_NORMAL)
|
||||
priority_class = NORMAL_PRIORITY_CLASS;
|
||||
else if (priority < UV_PRIORITY_LOW)
|
||||
priority_class = BELOW_NORMAL_PRIORITY_CLASS;
|
||||
else
|
||||
priority_class = IDLE_PRIORITY_CLASS;
|
||||
|
||||
r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
|
||||
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (SetPriorityClass(handle, priority_class) == 0)
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
|
||||
CloseHandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_uname(uv_utsname_t* buffer) {
|
||||
/* Implementation loosely based on
|
||||
https://github.com/gagern/gnulib/blob/master/lib/uname.c */
|
||||
OSVERSIONINFOW os_info;
|
||||
SYSTEM_INFO system_info;
|
||||
int processor_level;
|
||||
int r;
|
||||
|
||||
if (buffer == NULL)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
os_info.dwOSVersionInfoSize = sizeof(os_info);
|
||||
os_info.szCSDVersion[0] = L'\0';
|
||||
|
||||
/* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
|
||||
if RtlGetVersion() is not available. */
|
||||
if (pRtlGetVersion) {
|
||||
pRtlGetVersion(&os_info);
|
||||
} else {
|
||||
/* Silence GetVersionEx() deprecation warning. */
|
||||
#pragma warning(suppress : 4996)
|
||||
if (GetVersionExW(&os_info) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Populate the version field. */
|
||||
if (WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
os_info.szCSDVersion,
|
||||
-1,
|
||||
buffer->version,
|
||||
sizeof(buffer->version),
|
||||
NULL,
|
||||
NULL) == 0) {
|
||||
r = uv_translate_sys_error(GetLastError());
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Populate the sysname field. */
|
||||
#ifdef __MINGW32__
|
||||
r = snprintf(buffer->sysname,
|
||||
sizeof(buffer->sysname),
|
||||
"MINGW32_NT-%u.%u",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion);
|
||||
assert(r < sizeof(buffer->sysname));
|
||||
#else
|
||||
uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
|
||||
#endif
|
||||
|
||||
/* Populate the release field. */
|
||||
r = snprintf(buffer->release,
|
||||
sizeof(buffer->release),
|
||||
"%d.%d.%d",
|
||||
(unsigned int) os_info.dwMajorVersion,
|
||||
(unsigned int) os_info.dwMinorVersion,
|
||||
(unsigned int) os_info.dwBuildNumber);
|
||||
assert(r < sizeof(buffer->release));
|
||||
|
||||
/* Populate the machine field. */
|
||||
GetSystemInfo(&system_info);
|
||||
|
||||
switch (system_info.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
|
||||
|
||||
if (system_info.wProcessorLevel > 3) {
|
||||
processor_level = system_info.wProcessorLevel < 6 ?
|
||||
system_info.wProcessorLevel : 6;
|
||||
buffer->machine[1] = '0' + processor_level;
|
||||
}
|
||||
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
|
||||
uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_MIPS:
|
||||
uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA:
|
||||
case PROCESSOR_ARCHITECTURE_ALPHA64:
|
||||
uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_PPC:
|
||||
uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_SHX:
|
||||
uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_ARM:
|
||||
uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
|
||||
break;
|
||||
default:
|
||||
uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
buffer->sysname[0] = '\0';
|
||||
buffer->release[0] = '\0';
|
||||
buffer->version[0] = '\0';
|
||||
buffer->machine[0] = '\0';
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
sRtlGetVersion pRtlGetVersion;
|
||||
sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
sNtQueryInformationFile pNtQueryInformationFile;
|
||||
@@ -34,20 +35,8 @@ sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
|
||||
sCreateSymbolicLinkW pCreateSymbolicLinkW;
|
||||
sCancelIoEx pCancelIoEx;
|
||||
sInitializeConditionVariable pInitializeConditionVariable;
|
||||
sSleepConditionVariableCS pSleepConditionVariableCS;
|
||||
sSleepConditionVariableSRW pSleepConditionVariableSRW;
|
||||
sWakeAllConditionVariable pWakeAllConditionVariable;
|
||||
sWakeConditionVariable pWakeConditionVariable;
|
||||
sCancelSynchronousIo pCancelSynchronousIo;
|
||||
sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
@@ -55,22 +44,21 @@ sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
/* User32.dll function pointer */
|
||||
sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
/* iphlpapi.dll function pointer */
|
||||
sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid = NULL;
|
||||
sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW = NULL;
|
||||
|
||||
void uv_winapi_init(void) {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE powrprof_module;
|
||||
HMODULE user32_module;
|
||||
HMODULE iphlpapi_module;
|
||||
HMODULE kernel32_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
uv_fatal_error(GetLastError(), "GetModuleHandleA");
|
||||
}
|
||||
|
||||
pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
|
||||
"RtlGetVersion");
|
||||
|
||||
pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
|
||||
ntdll_module,
|
||||
"RtlNtStatusToDosError");
|
||||
@@ -127,37 +115,6 @@ void uv_winapi_init(void) {
|
||||
kernel32_module,
|
||||
"GetQueuedCompletionStatusEx");
|
||||
|
||||
pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
|
||||
GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
|
||||
|
||||
pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
|
||||
GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
|
||||
|
||||
pCancelIoEx = (sCancelIoEx)
|
||||
GetProcAddress(kernel32_module, "CancelIoEx");
|
||||
|
||||
pInitializeConditionVariable = (sInitializeConditionVariable)
|
||||
GetProcAddress(kernel32_module, "InitializeConditionVariable");
|
||||
|
||||
pSleepConditionVariableCS = (sSleepConditionVariableCS)
|
||||
GetProcAddress(kernel32_module, "SleepConditionVariableCS");
|
||||
|
||||
pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
|
||||
GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
|
||||
|
||||
pWakeAllConditionVariable = (sWakeAllConditionVariable)
|
||||
GetProcAddress(kernel32_module, "WakeAllConditionVariable");
|
||||
|
||||
pWakeConditionVariable = (sWakeConditionVariable)
|
||||
GetProcAddress(kernel32_module, "WakeConditionVariable");
|
||||
|
||||
pCancelSynchronousIo = (sCancelSynchronousIo)
|
||||
GetProcAddress(kernel32_module, "CancelSynchronousIo");
|
||||
|
||||
pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
|
||||
GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
|
||||
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
@@ -170,11 +127,4 @@ void uv_winapi_init(void) {
|
||||
GetProcAddress(user32_module, "SetWinEventHook");
|
||||
}
|
||||
|
||||
iphlpapi_module = LoadLibraryA("iphlpapi.dll");
|
||||
if (iphlpapi_module != NULL) {
|
||||
pConvertInterfaceIndexToLuid = (sConvertInterfaceIndexToLuid)
|
||||
GetProcAddress(iphlpapi_module, "ConvertInterfaceIndexToLuid");
|
||||
pConvertInterfaceLuidToNameW = (sConvertInterfaceLuidToNameW)
|
||||
GetProcAddress(iphlpapi_module, "ConvertInterfaceLuidToNameW");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4076,8 +4076,8 @@
|
||||
# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
|
||||
#endif
|
||||
|
||||
/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
|
||||
/* DDK got it wrong! */
|
||||
/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the DDK
|
||||
* got it wrong! */
|
||||
#ifdef NTSTATUS_FROM_WIN32
|
||||
# undef NTSTATUS_FROM_WIN32
|
||||
#endif
|
||||
@@ -4109,6 +4109,9 @@
|
||||
#endif
|
||||
|
||||
/* from winternl.h */
|
||||
#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
|
||||
#define __UNICODE_STRING_DEFINED
|
||||
#endif
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
@@ -4524,6 +4527,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE)
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG Reserved);
|
||||
|
||||
typedef NTSTATUS (NTAPI *sRtlGetVersion)
|
||||
(PRTL_OSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
typedef ULONG (NTAPI *sRtlNtStatusToDosError)
|
||||
(NTSTATUS Status);
|
||||
|
||||
@@ -4659,48 +4665,6 @@ typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
|
||||
DWORD dwMilliseconds,
|
||||
BOOL fAlertable);
|
||||
|
||||
typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
|
||||
(HANDLE FileHandle,
|
||||
UCHAR Flags);
|
||||
|
||||
typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
|
||||
(LPCWSTR lpSymlinkFileName,
|
||||
LPCWSTR lpTargetFileName,
|
||||
DWORD dwFlags);
|
||||
|
||||
typedef BOOL (WINAPI* sCancelIoEx)
|
||||
(HANDLE hFile,
|
||||
LPOVERLAPPED lpOverlapped);
|
||||
|
||||
typedef VOID (WINAPI* sInitializeConditionVariable)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef BOOL (WINAPI* sSleepConditionVariableCS)
|
||||
(PCONDITION_VARIABLE ConditionVariable,
|
||||
PCRITICAL_SECTION CriticalSection,
|
||||
DWORD dwMilliseconds);
|
||||
|
||||
typedef BOOL (WINAPI* sSleepConditionVariableSRW)
|
||||
(PCONDITION_VARIABLE ConditionVariable,
|
||||
PSRWLOCK SRWLock,
|
||||
DWORD dwMilliseconds,
|
||||
ULONG Flags);
|
||||
|
||||
typedef VOID (WINAPI* sWakeAllConditionVariable)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef VOID (WINAPI* sWakeConditionVariable)
|
||||
(PCONDITION_VARIABLE ConditionVariable);
|
||||
|
||||
typedef BOOL (WINAPI* sCancelSynchronousIo)
|
||||
(HANDLE hThread);
|
||||
|
||||
typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
|
||||
(HANDLE hFile,
|
||||
LPWSTR lpszFilePath,
|
||||
DWORD cchFilePath,
|
||||
DWORD dwFlags);
|
||||
|
||||
/* from powerbase.h */
|
||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||
# define DEVICE_NOTIFY_CALLBACK 2
|
||||
@@ -4755,6 +4719,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlGetVersion pRtlGetVersion;
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
extern sNtQueryInformationFile pNtQueryInformationFile;
|
||||
@@ -4763,20 +4728,8 @@ extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
|
||||
extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
|
||||
extern sNtQuerySystemInformation pNtQuerySystemInformation;
|
||||
|
||||
|
||||
/* Kernel32 function pointers */
|
||||
extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
|
||||
extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
|
||||
extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
|
||||
extern sCancelIoEx pCancelIoEx;
|
||||
extern sInitializeConditionVariable pInitializeConditionVariable;
|
||||
extern sSleepConditionVariableCS pSleepConditionVariableCS;
|
||||
extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
|
||||
extern sWakeAllConditionVariable pWakeAllConditionVariable;
|
||||
extern sWakeConditionVariable pWakeConditionVariable;
|
||||
extern sCancelSynchronousIo pCancelSynchronousIo;
|
||||
extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
@@ -4784,19 +4737,4 @@ extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotifi
|
||||
/* User32.dll function pointer */
|
||||
extern sSetWinEventHook pSetWinEventHook;
|
||||
|
||||
/* iphlpapi.dll function pointer */
|
||||
union _NET_LUID_LH;
|
||||
typedef DWORD (WINAPI *sConvertInterfaceIndexToLuid)(
|
||||
ULONG InterfaceIndex,
|
||||
union _NET_LUID_LH *InterfaceLuid);
|
||||
|
||||
typedef DWORD (WINAPI *sConvertInterfaceLuidToNameW)(
|
||||
const union _NET_LUID_LH *InterfaceLuid,
|
||||
PWSTR InterfaceName,
|
||||
size_t Length);
|
||||
|
||||
extern sConvertInterfaceIndexToLuid pConvertInterfaceIndexToLuid;
|
||||
extern sConvertInterfaceLuidToNameW pConvertInterfaceLuidToNameW;
|
||||
|
||||
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
|
||||
@@ -256,8 +256,8 @@ int uv_ntstatus_to_winsock_error(NTSTATUS status) {
|
||||
default:
|
||||
if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
|
||||
(status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
|
||||
/* It's a windows error that has been previously mapped to an */
|
||||
/* ntstatus code. */
|
||||
/* It's a windows error that has been previously mapped to an ntstatus
|
||||
* code. */
|
||||
return (DWORD) (status & 0xffff);
|
||||
} else {
|
||||
/* The default fallback for unmappable ntstatus codes. */
|
||||
@@ -519,8 +519,8 @@ int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
|
||||
sizeof *info_out);
|
||||
|
||||
if (overlapped == NULL) {
|
||||
/* If this is a blocking operation, wait for the event to become */
|
||||
/* signaled, and then grab the real status from the io status block. */
|
||||
/* If this is a blocking operation, wait for the event to become signaled,
|
||||
* and then grab the real status from the io status block. */
|
||||
if (status == STATUS_PENDING) {
|
||||
DWORD r = WaitForSingleObject(event, INFINITE);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user