mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-19 16:58:20 +00:00
Update libuv
This commit is contained in:
+112
-7
@@ -31,13 +31,10 @@
|
||||
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "queue.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
static uv_loop_t default_loop_struct;
|
||||
static uv_loop_t* default_loop_ptr;
|
||||
|
||||
/* uv_once initialization guards */
|
||||
static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
|
||||
|
||||
@@ -80,6 +77,98 @@ static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
|
||||
}
|
||||
#endif
|
||||
|
||||
static uv_loop_t** uv__loops;
|
||||
static int uv__loops_size;
|
||||
static int uv__loops_capacity;
|
||||
#define UV__LOOPS_CHUNK_SIZE 8
|
||||
static uv_mutex_t uv__loops_lock;
|
||||
|
||||
static void uv__loops_init() {
|
||||
uv_mutex_init(&uv__loops_lock);
|
||||
uv__loops = uv__calloc(UV__LOOPS_CHUNK_SIZE, sizeof(uv_loop_t*));
|
||||
if (!uv__loops)
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
uv__loops_size = 0;
|
||||
uv__loops_capacity = UV__LOOPS_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static int uv__loops_add(uv_loop_t* loop) {
|
||||
uv_loop_t** new_loops;
|
||||
int new_capacity, i;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
if (uv__loops_size == uv__loops_capacity) {
|
||||
new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
|
||||
if (!new_loops)
|
||||
goto failed_loops_realloc;
|
||||
uv__loops = new_loops;
|
||||
for (i = uv__loops_capacity; i < new_capacity; ++i)
|
||||
uv__loops[i] = NULL;
|
||||
uv__loops_capacity = new_capacity;
|
||||
}
|
||||
uv__loops[uv__loops_size] = loop;
|
||||
++uv__loops_size;
|
||||
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return 0;
|
||||
|
||||
failed_loops_realloc:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
static void uv__loops_remove(uv_loop_t* loop) {
|
||||
int loop_index;
|
||||
int smaller_capacity;
|
||||
uv_loop_t** new_loops;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
|
||||
for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
|
||||
if (uv__loops[loop_index] == loop)
|
||||
break;
|
||||
}
|
||||
/* If loop was not found, ignore */
|
||||
if (loop_index == uv__loops_size)
|
||||
goto loop_removed;
|
||||
|
||||
uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
|
||||
uv__loops[uv__loops_size - 1] = NULL;
|
||||
--uv__loops_size;
|
||||
|
||||
/* If we didn't grow to big skip downsizing */
|
||||
if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
|
||||
goto loop_removed;
|
||||
|
||||
/* Downsize only if more than half of buffer is free */
|
||||
smaller_capacity = uv__loops_capacity / 2;
|
||||
if (uv__loops_size >= smaller_capacity)
|
||||
goto loop_removed;
|
||||
new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
|
||||
if (!new_loops)
|
||||
goto loop_removed;
|
||||
uv__loops = new_loops;
|
||||
uv__loops_capacity = smaller_capacity;
|
||||
|
||||
loop_removed:
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
void uv__wake_all_loops() {
|
||||
int i;
|
||||
uv_loop_t* loop;
|
||||
|
||||
uv_mutex_lock(&uv__loops_lock);
|
||||
for (i = 0; i < uv__loops_size; ++i) {
|
||||
loop = uv__loops[i];
|
||||
assert(loop);
|
||||
if (loop->iocp != INVALID_HANDLE_VALUE)
|
||||
PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
|
||||
}
|
||||
uv_mutex_unlock(&uv__loops_lock);
|
||||
}
|
||||
|
||||
static void uv_init(void) {
|
||||
/* Tell Windows that we will handle critical errors. */
|
||||
@@ -101,6 +190,9 @@ static void uv_init(void) {
|
||||
_CrtSetReportHook(uv__crt_dbg_report_handler);
|
||||
#endif
|
||||
|
||||
/* Initialize tracking of all uv loops */
|
||||
uv__loops_init();
|
||||
|
||||
/* Fetch winapi function pointers. This must be done first because other
|
||||
* initialization code might need these function pointers to be loaded.
|
||||
*/
|
||||
@@ -120,6 +212,9 @@ static void uv_init(void) {
|
||||
|
||||
/* Initialize utilities */
|
||||
uv__util_init();
|
||||
|
||||
/* Initialize system wakeup detection */
|
||||
uv__init_detect_system_wakeup();
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +273,10 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
uv__handle_unref(&loop->wq_async);
|
||||
loop->wq_async.flags |= UV__HANDLE_INTERNAL;
|
||||
|
||||
err = uv__loops_add(loop);
|
||||
if (err)
|
||||
goto fail_async_init;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_async_init:
|
||||
@@ -199,6 +298,8 @@ void uv__once_init(void) {
|
||||
void uv__loop_close(uv_loop_t* loop) {
|
||||
size_t i;
|
||||
|
||||
uv__loops_remove(loop);
|
||||
|
||||
/* close the async handle without needing an extra loop iteration */
|
||||
assert(!loop->wq_async.async_sent);
|
||||
loop->wq_async.close_cb = NULL;
|
||||
@@ -323,9 +424,13 @@ static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
|
||||
|
||||
if (success) {
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Package was dequeued */
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
/* Package was dequeued, but see if it is not a empty package
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv_insert_pending_req(loop, req);
|
||||
}
|
||||
}
|
||||
|
||||
/* Some time might have passed waiting for I/O,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "uv.h"
|
||||
#include "internal.h"
|
||||
#include "winapi.h"
|
||||
|
||||
static void uv__register_system_resume_callback();
|
||||
|
||||
void uv__init_detect_system_wakeup() {
|
||||
/* Try registering system power event callback. This is the cleanest
|
||||
* method, but it will only work on Win8 and above.
|
||||
*/
|
||||
uv__register_system_resume_callback();
|
||||
}
|
||||
|
||||
static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting) {
|
||||
if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
|
||||
uv__wake_all_loops();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uv__register_system_resume_callback() {
|
||||
_DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
|
||||
_HPOWERNOTIFY registration_handle;
|
||||
|
||||
if (pPowerRegisterSuspendResumeNotification == NULL)
|
||||
return;
|
||||
|
||||
recipient.Callback = uv__system_resume_callback;
|
||||
recipient.Context = NULL;
|
||||
(*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
|
||||
&recipient,
|
||||
®istration_handle);
|
||||
}
|
||||
@@ -71,6 +71,7 @@ int uv_translate_sys_error(int sys_errno) {
|
||||
switch (sys_errno) {
|
||||
case ERROR_NOACCESS: return UV_EACCES;
|
||||
case WSAEACCES: return UV_EACCES;
|
||||
case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
|
||||
case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
|
||||
case WSAEADDRINUSE: return UV_EADDRINUSE;
|
||||
case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
|
||||
|
||||
@@ -344,6 +344,22 @@ int uv_fs_event_stop(uv_fs_event_t* handle) {
|
||||
}
|
||||
|
||||
|
||||
static int file_info_cmp(WCHAR* str, WCHAR* file_name, int file_name_len) {
|
||||
int str_len;
|
||||
|
||||
str_len = wcslen(str);
|
||||
|
||||
/*
|
||||
Since we only care about equality, return early if the strings
|
||||
aren't the same length
|
||||
*/
|
||||
if (str_len != (file_name_len / sizeof(WCHAR)))
|
||||
return -1;
|
||||
|
||||
return _wcsnicmp(str, file_name, str_len);
|
||||
}
|
||||
|
||||
|
||||
void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
uv_fs_event_t* handle) {
|
||||
FILE_NOTIFY_INFORMATION* file_info;
|
||||
@@ -383,10 +399,12 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
* or if the filename filter matches.
|
||||
*/
|
||||
if (handle->dirw ||
|
||||
_wcsnicmp(handle->filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0 ||
|
||||
_wcsnicmp(handle->short_filew, file_info->FileName,
|
||||
file_info->FileNameLength / sizeof(WCHAR)) == 0) {
|
||||
file_info_cmp(handle->filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0 ||
|
||||
file_info_cmp(handle->short_filew,
|
||||
file_info->FileName,
|
||||
file_info->FileNameLength) == 0) {
|
||||
|
||||
if (handle->dirw) {
|
||||
/*
|
||||
@@ -407,7 +425,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
|
||||
}
|
||||
|
||||
_snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
|
||||
file_info->FileNameLength / sizeof(WCHAR),
|
||||
file_info->FileNameLength / (DWORD)sizeof(WCHAR),
|
||||
file_info->FileName);
|
||||
|
||||
filenamew[size - 1] = L'\0';
|
||||
|
||||
+31
-20
@@ -94,7 +94,7 @@
|
||||
|
||||
#define TIME_T_TO_FILETIME(time, filetime_ptr) \
|
||||
do { \
|
||||
uint64_t bigtime = ((int64_t) (time) * 10000000LL) + \
|
||||
uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
|
||||
116444736000000000ULL; \
|
||||
(filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
|
||||
(filetime_ptr)->dwHighDateTime = bigtime >> 32; \
|
||||
@@ -123,7 +123,7 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
||||
const char* new_path, const int copy_path) {
|
||||
char* buf;
|
||||
char* pos;
|
||||
ssize_t buf_sz = 0, path_len, pathw_len = 0, new_pathw_len = 0;
|
||||
ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
|
||||
|
||||
/* new_path can only be set if path is also set. */
|
||||
assert(new_path == NULL || path != NULL);
|
||||
@@ -204,14 +204,11 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
|
||||
req->fs.info.new_pathw = NULL;
|
||||
}
|
||||
|
||||
if (!copy_path) {
|
||||
req->path = path;
|
||||
} else if (path) {
|
||||
req->path = path;
|
||||
if (path != NULL && copy_path) {
|
||||
memcpy(pos, path, path_len);
|
||||
assert(path_len == buf_sz - (pos - buf));
|
||||
req->path = pos;
|
||||
} else {
|
||||
req->path = NULL;
|
||||
}
|
||||
|
||||
req->flags |= UV_FS_FREE_PATHS;
|
||||
@@ -233,6 +230,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
|
||||
req->ptr = NULL;
|
||||
req->path = NULL;
|
||||
req->cb = cb;
|
||||
memset(&req->fs, 0, sizeof(req->fs));
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +403,6 @@ void fs__open(uv_fs_t* req) {
|
||||
switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
|
||||
case _O_RDONLY:
|
||||
access = FILE_GENERIC_READ;
|
||||
attributes |= FILE_FLAG_BACKUP_SEMANTICS;
|
||||
break;
|
||||
case _O_WRONLY:
|
||||
access = FILE_GENERIC_WRITE;
|
||||
@@ -420,7 +417,6 @@ void fs__open(uv_fs_t* req) {
|
||||
if (flags & _O_APPEND) {
|
||||
access &= ~FILE_WRITE_DATA;
|
||||
access |= FILE_APPEND_DATA;
|
||||
attributes &= ~FILE_FLAG_BACKUP_SEMANTICS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1091,17 +1087,28 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
|
||||
statbuf->st_mode = 0;
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
|
||||
/*
|
||||
* It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
|
||||
* any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
|
||||
* the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
|
||||
* calculated below will indicate a normal directory or file, as if
|
||||
* FILE_ATTRIBUTE_REPARSE_POINT was not present.
|
||||
*/
|
||||
if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
|
||||
statbuf->st_mode |= S_IFLNK;
|
||||
} else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
if (statbuf->st_mode == 0) {
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
statbuf->st_mode |= _S_IFDIR;
|
||||
statbuf->st_size = 0;
|
||||
} else {
|
||||
statbuf->st_mode |= _S_IFREG;
|
||||
statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
@@ -1429,8 +1436,8 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
|
||||
FILETIME filetime_a, filetime_m;
|
||||
|
||||
TIME_T_TO_FILETIME((time_t) atime, &filetime_a);
|
||||
TIME_T_TO_FILETIME((time_t) mtime, &filetime_m);
|
||||
TIME_T_TO_FILETIME(atime, &filetime_a);
|
||||
TIME_T_TO_FILETIME(mtime, &filetime_m);
|
||||
|
||||
if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
|
||||
return -1;
|
||||
@@ -1885,9 +1892,13 @@ void uv_fs_req_cleanup(uv_fs_t* req) {
|
||||
uv__free(req->ptr);
|
||||
}
|
||||
|
||||
if (req->fs.info.bufs != req->fs.info.bufsml)
|
||||
uv__free(req->fs.info.bufs);
|
||||
|
||||
req->path = NULL;
|
||||
req->file.pathw = NULL;
|
||||
req->fs.info.new_pathw = NULL;
|
||||
req->fs.info.bufs = NULL;
|
||||
req->ptr = NULL;
|
||||
|
||||
req->flags |= UV_FS_CLEANEDUP;
|
||||
|
||||
@@ -262,8 +262,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
|
||||
int err;
|
||||
|
||||
if (req == NULL || (node == NULL && service == NULL)) {
|
||||
err = WSAEINVAL;
|
||||
goto error;
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
uv_req_init(loop, (uv_req_t*)req);
|
||||
|
||||
@@ -381,4 +381,14 @@ extern int uv_tcp_non_ifs_lsp_ipv6;
|
||||
extern struct sockaddr_in uv_addr_ip4_any_;
|
||||
extern struct sockaddr_in6 uv_addr_ip6_any_;
|
||||
|
||||
/*
|
||||
* Wake all loops with fake message
|
||||
*/
|
||||
void uv__wake_all_loops();
|
||||
|
||||
/*
|
||||
* Init system wake-up detection
|
||||
*/
|
||||
void uv__init_detect_system_wakeup();
|
||||
|
||||
#endif /* UV_WIN_INTERNAL_H_ */
|
||||
|
||||
@@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle);
|
||||
|
||||
|
||||
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId());
|
||||
snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
|
||||
}
|
||||
|
||||
|
||||
@@ -1634,8 +1634,9 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
}
|
||||
}
|
||||
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -372,6 +372,7 @@ int uv__stdio_create(uv_loop_t* loop,
|
||||
|
||||
case FILE_TYPE_PIPE:
|
||||
CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
|
||||
break;
|
||||
|
||||
case FILE_TYPE_CHAR:
|
||||
case FILE_TYPE_REMOTE:
|
||||
|
||||
@@ -492,7 +492,7 @@ WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
|
||||
* input : hello\\"world
|
||||
* output: "hello\\\\\"world"
|
||||
* input : hello world\
|
||||
* output: "hello world\"
|
||||
* output: "hello world\\"
|
||||
*/
|
||||
|
||||
*(target++) = L'"';
|
||||
|
||||
+5
-113
@@ -30,12 +30,14 @@
|
||||
RB_HEAD(uv_signal_tree_s, uv_signal_s);
|
||||
|
||||
static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
|
||||
static ssize_t volatile uv__signal_control_handler_refs = 0;
|
||||
static CRITICAL_SECTION uv__signal_lock;
|
||||
|
||||
static BOOL WINAPI uv__signal_control_handler(DWORD type);
|
||||
|
||||
void uv_signals_init() {
|
||||
InitializeCriticalSection(&uv__signal_lock);
|
||||
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -125,102 +127,6 @@ static BOOL WINAPI uv__signal_control_handler(DWORD type) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register_control_handler() {
|
||||
/* When this function is called, the uv__signal_lock must be held. */
|
||||
|
||||
/* If the console control handler has already been hooked, just add a */
|
||||
/* reference. */
|
||||
if (uv__signal_control_handler_refs > 0) {
|
||||
uv__signal_control_handler_refs++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
|
||||
return GetLastError();
|
||||
|
||||
uv__signal_control_handler_refs++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister_control_handler() {
|
||||
/* When this function is called, the uv__signal_lock must be held. */
|
||||
BOOL r;
|
||||
|
||||
/* Don't unregister if the number of console control handlers exceeds one. */
|
||||
/* Just remove a reference in that case. */
|
||||
if (uv__signal_control_handler_refs > 1) {
|
||||
uv__signal_control_handler_refs--;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(uv__signal_control_handler_refs == 1);
|
||||
|
||||
r = SetConsoleCtrlHandler(uv__signal_control_handler, FALSE);
|
||||
/* This should never fail; if it does it is probably a bug in libuv. */
|
||||
assert(r);
|
||||
|
||||
uv__signal_control_handler_refs--;
|
||||
}
|
||||
|
||||
|
||||
static int uv__signal_register(int signum) {
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGBREAK:
|
||||
case SIGHUP:
|
||||
return uv__signal_register_control_handler();
|
||||
|
||||
case SIGWINCH:
|
||||
/* SIGWINCH is generated in tty.c. No need to register anything. */
|
||||
return 0;
|
||||
|
||||
case SIGILL:
|
||||
case SIGABRT_COMPAT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGTERM:
|
||||
case SIGABRT:
|
||||
/* Signal is never raised. */
|
||||
return 0;
|
||||
|
||||
default:
|
||||
/* Invalid signal. */
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void uv__signal_unregister(int signum) {
|
||||
switch (signum) {
|
||||
case SIGINT:
|
||||
case SIGBREAK:
|
||||
case SIGHUP:
|
||||
uv__signal_unregister_control_handler();
|
||||
return;
|
||||
|
||||
case SIGWINCH:
|
||||
/* SIGWINCH is generated in tty.c. No need to unregister anything. */
|
||||
return;
|
||||
|
||||
case SIGILL:
|
||||
case SIGABRT_COMPAT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGTERM:
|
||||
case SIGABRT:
|
||||
/* Nothing is registered for this signal. */
|
||||
return;
|
||||
|
||||
default:
|
||||
/* Libuv bug. */
|
||||
assert(0 && "Invalid signum");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
|
||||
uv_req_t* req;
|
||||
|
||||
@@ -247,8 +153,6 @@ int uv_signal_stop(uv_signal_t* handle) {
|
||||
|
||||
EnterCriticalSection(&uv__signal_lock);
|
||||
|
||||
uv__signal_unregister(handle->signum);
|
||||
|
||||
removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
assert(removed_handle == handle);
|
||||
|
||||
@@ -262,14 +166,9 @@ int uv_signal_stop(uv_signal_t* handle) {
|
||||
|
||||
|
||||
int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
|
||||
int err;
|
||||
|
||||
/* If the user supplies signum == 0, then return an error already. If the */
|
||||
/* signum is otherwise invalid then uv__signal_register will find out */
|
||||
/* eventually. */
|
||||
if (signum == 0) {
|
||||
/* Test for invalid signal values. */
|
||||
if (signum != SIGWINCH && (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. */
|
||||
@@ -289,13 +188,6 @@ int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
|
||||
|
||||
EnterCriticalSection(&uv__signal_lock);
|
||||
|
||||
err = uv__signal_register(signum);
|
||||
if (err) {
|
||||
/* Uh-oh, didn't work. */
|
||||
LeaveCriticalSection(&uv__signal_lock);
|
||||
return uv_translate_sys_error(err);
|
||||
}
|
||||
|
||||
handle->signum = signum;
|
||||
RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
|
||||
|
||||
|
||||
@@ -496,8 +496,10 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
*/
|
||||
if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
|
||||
if (handle->tcp.conn.read_buffer.len == 0) {
|
||||
if (handle->tcp.conn.read_buffer.base == NULL ||
|
||||
handle->tcp.conn.read_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
|
||||
return;
|
||||
}
|
||||
@@ -1004,8 +1006,9 @@ 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) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
break;
|
||||
}
|
||||
|
||||
+161
-46
@@ -40,6 +40,9 @@
|
||||
#include "stream-inl.h"
|
||||
#include "req-inl.h"
|
||||
|
||||
#ifndef InterlockedOr
|
||||
# define InterlockedOr _InterlockedOr
|
||||
#endif
|
||||
|
||||
#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
|
||||
|
||||
@@ -53,7 +56,11 @@
|
||||
#define ANSI_BACKSLASH_SEEN 0x80
|
||||
|
||||
#define MAX_INPUT_BUFFER_LENGTH 8192
|
||||
#define MAX_CONSOLE_CHAR 8192
|
||||
|
||||
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
||||
#endif
|
||||
|
||||
static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
|
||||
@@ -105,7 +112,11 @@ static int uv_tty_virtual_offset = -1;
|
||||
static int uv_tty_virtual_height = -1;
|
||||
static int uv_tty_virtual_width = -1;
|
||||
|
||||
static CRITICAL_SECTION uv_tty_output_lock;
|
||||
/* We use a semaphore rather than a mutex or critical section because in some
|
||||
cases (uv__cancel_read_console) we need take the lock in the main thread and
|
||||
release it in another thread. Using a semaphore ensures that in such
|
||||
scenario the main thread will still block when trying to acquire the lock. */
|
||||
static uv_sem_t uv_tty_output_lock;
|
||||
|
||||
static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
@@ -118,9 +129,18 @@ static char uv_tty_default_fg_bright = 0;
|
||||
static char uv_tty_default_bg_bright = 0;
|
||||
static char uv_tty_default_inverse = 0;
|
||||
|
||||
typedef enum {
|
||||
UV_SUPPORTED,
|
||||
UV_UNCHECKED,
|
||||
UV_UNSUPPORTED
|
||||
} uv_vtermstate_t;
|
||||
/* Determine whether or not ANSI support is enabled. */
|
||||
static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
|
||||
static void uv__determine_vterm_state(HANDLE handle);
|
||||
|
||||
void uv_console_init() {
|
||||
InitializeCriticalSection(&uv_tty_output_lock);
|
||||
if (uv_sem_init(&uv_tty_output_lock, 1))
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -158,7 +178,10 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
|
||||
/* Obtain the the tty_output_lock because the virtual window state is */
|
||||
/* shared between all uv_tty_t handles. */
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
if (uv__vterm_state == UV_UNCHECKED)
|
||||
uv__determine_vterm_state(handle);
|
||||
|
||||
/* Store the global tty output handle. This handle is used by TTY read */
|
||||
/* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
|
||||
@@ -170,7 +193,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -294,10 +317,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
break;
|
||||
case UV_TTY_MODE_IO:
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
if (!SetConsoleMode(tty->handle, flags)) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
default:
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
/* If currently reading, stop, and restart reading. */
|
||||
@@ -313,6 +334,14 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
|
||||
was_reading = 0;
|
||||
}
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
if (!SetConsoleMode(tty->handle, flags)) {
|
||||
err = uv_translate_sys_error(GetLastError());
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
return err;
|
||||
}
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
/* Update flag. */
|
||||
tty->flags &= ~UV_HANDLE_TTY_RAW;
|
||||
tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
|
||||
@@ -342,9 +371,9 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
uv_tty_update_virtual_window(&info);
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
*width = uv_tty_virtual_width;
|
||||
*height = uv_tty_virtual_height;
|
||||
@@ -413,6 +442,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
||||
DWORD chars, read_chars;
|
||||
LONG status;
|
||||
COORD pos;
|
||||
BOOL read_console_success;
|
||||
|
||||
assert(data);
|
||||
|
||||
@@ -442,11 +472,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ReadConsoleW(handle->handle,
|
||||
(void*) utf16,
|
||||
chars,
|
||||
&read_chars,
|
||||
NULL)) {
|
||||
read_console_success = ReadConsoleW(handle->handle,
|
||||
(void*) utf16,
|
||||
chars,
|
||||
&read_chars,
|
||||
NULL);
|
||||
|
||||
if (read_console_success) {
|
||||
read_bytes = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
utf16,
|
||||
@@ -461,33 +493,36 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
|
||||
SET_REQ_ERROR(req, GetLastError());
|
||||
}
|
||||
|
||||
InterlockedExchange(&uv__read_console_status, COMPLETED);
|
||||
status = InterlockedExchange(&uv__read_console_status, COMPLETED);
|
||||
|
||||
/* If we canceled the read by sending a VK_RETURN event, restore the screen
|
||||
state to undo the visual effect of the VK_RETURN*/
|
||||
if (InterlockedOr(&uv__restore_screen_state, 0)) {
|
||||
HANDLE active_screen_buffer = CreateFileA("conout$",
|
||||
if (status == TRAP_REQUESTED) {
|
||||
/* If we canceled the read by sending a VK_RETURN event, restore the
|
||||
screen state to undo the visual effect of the VK_RETURN */
|
||||
if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
|
||||
HANDLE active_screen_buffer;
|
||||
active_screen_buffer = CreateFileA("conout$",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (active_screen_buffer != INVALID_HANDLE_VALUE) {
|
||||
pos = uv__saved_screen_state.dwCursorPosition;
|
||||
if (active_screen_buffer != INVALID_HANDLE_VALUE) {
|
||||
pos = uv__saved_screen_state.dwCursorPosition;
|
||||
|
||||
/* If the cursor was at the bottom line of the screen buffer, the
|
||||
VK_RETURN would have caused the buffer contents to scroll up by
|
||||
one line. The right position to reset the cursor to is therefore one
|
||||
line higher */
|
||||
if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
|
||||
pos.Y--;
|
||||
/* If the cursor was at the bottom line of the screen buffer, the
|
||||
VK_RETURN would have caused the buffer contents to scroll up by one
|
||||
line. The right position to reset the cursor to is therefore one line
|
||||
higher */
|
||||
if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
|
||||
pos.Y--;
|
||||
|
||||
SetConsoleCursorPosition(active_screen_buffer, pos);
|
||||
CloseHandle(active_screen_buffer);
|
||||
SetConsoleCursorPosition(active_screen_buffer, pos);
|
||||
CloseHandle(active_screen_buffer);
|
||||
}
|
||||
}
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
POST_COMPLETION_FOR_REQ(loop, req);
|
||||
return 0;
|
||||
}
|
||||
@@ -504,8 +539,10 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
|
||||
if (handle->tty.rd.read_line_buffer.len == 0) {
|
||||
if (handle->tty.rd.read_line_buffer.base == NULL ||
|
||||
handle->tty.rd.read_line_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle,
|
||||
UV_ENOBUFS,
|
||||
&handle->tty.rd.read_line_buffer);
|
||||
@@ -673,14 +710,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
|
||||
GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
|
||||
uv_tty_update_virtual_window(&info);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -828,8 +865,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
|
||||
/* Allocate a buffer if needed */
|
||||
if (buf_used == 0) {
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
|
||||
if (buf.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
|
||||
goto out;
|
||||
}
|
||||
@@ -966,6 +1004,9 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
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);
|
||||
/* Make sure no attempt is made to insert it again until it's handled. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1013,11 +1054,16 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
|
||||
|
||||
assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
|
||||
|
||||
/* Hold the output lock during the cancellation, to ensure that further
|
||||
writes don't interfere with the screen state. It will be the ReadConsole
|
||||
thread's responsibility to release the lock. */
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
|
||||
if (status != IN_PROGRESS) {
|
||||
/* Either we have managed to set a trap for the other thread before
|
||||
ReadConsole is called, or ReadConsole has returned because the user
|
||||
has pressed ENTER. In either case, there is nothing else to do. */
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1574,17 +1620,29 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
DWORD* error) {
|
||||
/* 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[8192];
|
||||
WCHAR utf16_buf[MAX_CONSOLE_CHAR];
|
||||
WCHAR* utf16_buffer;
|
||||
DWORD utf16_buf_used = 0;
|
||||
unsigned int i;
|
||||
unsigned int i, len, max_len, pos;
|
||||
int allocate = 0;
|
||||
|
||||
#define FLUSH_TEXT() \
|
||||
do { \
|
||||
if (utf16_buf_used > 0) { \
|
||||
uv_tty_emit_text(handle, utf16_buf, utf16_buf_used, error); \
|
||||
utf16_buf_used = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#define FLUSH_TEXT() \
|
||||
do { \
|
||||
pos = 0; \
|
||||
do { \
|
||||
len = utf16_buf_used - pos; \
|
||||
if (len > MAX_CONSOLE_CHAR) \
|
||||
len = MAX_CONSOLE_CHAR; \
|
||||
uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
|
||||
pos += len; \
|
||||
} while (pos < utf16_buf_used); \
|
||||
if (allocate) { \
|
||||
uv__free(utf16_buffer); \
|
||||
allocate = 0; \
|
||||
utf16_buffer = utf16_buf; \
|
||||
} \
|
||||
utf16_buf_used = 0; \
|
||||
} while (0)
|
||||
|
||||
#define ENSURE_BUFFER_SPACE(wchars_needed) \
|
||||
if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
|
||||
@@ -1602,12 +1660,48 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
/* state. */
|
||||
*error = ERROR_SUCCESS;
|
||||
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
utf16_buffer = utf16_buf;
|
||||
|
||||
uv_sem_wait(&uv_tty_output_lock);
|
||||
|
||||
for (i = 0; i < nbufs; i++) {
|
||||
uv_buf_t buf = bufs[i];
|
||||
unsigned int j;
|
||||
|
||||
if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
|
||||
utf16_buf_used = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (utf16_buf_used == 0) {
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
|
||||
allocate = max_len > MAX_CONSOLE_CHAR;
|
||||
if (allocate)
|
||||
utf16_buffer = uv__malloc(max_len);
|
||||
if (!MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
buf.base,
|
||||
buf.len,
|
||||
utf16_buffer,
|
||||
utf16_buf_used)) {
|
||||
if (allocate)
|
||||
uv__free(utf16_buffer);
|
||||
*error = GetLastError();
|
||||
break;
|
||||
}
|
||||
|
||||
FLUSH_TEXT();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j = 0; j < buf.len; j++) {
|
||||
unsigned char c = buf.base[j];
|
||||
|
||||
@@ -2012,7 +2106,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
|
||||
handle->tty.wr.previous_eol = previous_eol;
|
||||
handle->tty.wr.ansi_parser_state = ansi_parser_state;
|
||||
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
uv_sem_post(&uv_tty_output_lock);
|
||||
|
||||
if (*error == STATUS_SUCCESS) {
|
||||
return 0;
|
||||
@@ -2165,3 +2259,24 @@ int uv_tty_reset_mode(void) {
|
||||
/* Not necessary to do anything. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Determine whether or not this version of windows supports
|
||||
* proper ANSI color codes. Should be supported as of windows
|
||||
* 10 version 1511, build number 10.0.10586.
|
||||
*/
|
||||
static void uv__determine_vterm_state(HANDLE handle) {
|
||||
DWORD dwMode = 0;
|
||||
|
||||
if (!GetConsoleMode(handle, &dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(handle, dwMode)) {
|
||||
uv__vterm_state = UV_UNSUPPORTED;
|
||||
return;
|
||||
}
|
||||
|
||||
uv__vterm_state = UV_SUPPORTED;
|
||||
}
|
||||
|
||||
@@ -289,8 +289,9 @@ static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
|
||||
handle->recv_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
|
||||
if (handle->recv_buffer.len == 0) {
|
||||
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
|
||||
return;
|
||||
}
|
||||
@@ -506,8 +507,9 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
|
||||
/* 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.len == 0) {
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
/* The number of nanoseconds in one second. */
|
||||
#define UV__NANOSEC 1000000000
|
||||
|
||||
/* Max user name length, from iphlpapi.h */
|
||||
#ifndef UNLEN
|
||||
# define UNLEN 256
|
||||
#endif
|
||||
|
||||
/* Cached copy of the process title, plus a mutex guarding it. */
|
||||
static char *process_title;
|
||||
@@ -416,6 +420,11 @@ static int uv__get_process_title() {
|
||||
|
||||
|
||||
int uv_get_process_title(char* buffer, size_t size) {
|
||||
size_t len;
|
||||
|
||||
if (buffer == NULL || size == 0)
|
||||
return UV_EINVAL;
|
||||
|
||||
uv__once_init();
|
||||
|
||||
EnterCriticalSection(&process_title_lock);
|
||||
@@ -429,7 +438,14 @@ int uv_get_process_title(char* buffer, size_t size) {
|
||||
}
|
||||
|
||||
assert(process_title);
|
||||
strncpy(buffer, process_title, size);
|
||||
len = strlen(process_title) + 1;
|
||||
|
||||
if (size < len) {
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
return UV_ENOBUFS;
|
||||
}
|
||||
|
||||
memcpy(buffer, process_title, len);
|
||||
LeaveCriticalSection(&process_title_lock);
|
||||
|
||||
return 0;
|
||||
@@ -1062,6 +1078,7 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
FILETIME createTime, exitTime, kernelTime, userTime;
|
||||
SYSTEMTIME kernelSystemTime, userSystemTime;
|
||||
PROCESS_MEMORY_COUNTERS memCounters;
|
||||
IO_COUNTERS ioCounters;
|
||||
int ret;
|
||||
|
||||
ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
|
||||
@@ -1086,6 +1103,11 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
|
||||
if (ret == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
memset(uv_rusage, 0, sizeof(*uv_rusage));
|
||||
|
||||
uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
|
||||
@@ -1101,6 +1123,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) {
|
||||
uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
|
||||
uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
|
||||
|
||||
uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
|
||||
uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,14 @@ sCancelSynchronousIo pCancelSynchronousIo;
|
||||
sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
|
||||
void uv_winapi_init() {
|
||||
HMODULE ntdll_module;
|
||||
HMODULE kernel32_module;
|
||||
HMODULE powrprof_module;
|
||||
|
||||
ntdll_module = GetModuleHandleA("ntdll.dll");
|
||||
if (ntdll_module == NULL) {
|
||||
@@ -143,4 +148,12 @@ void uv_winapi_init() {
|
||||
|
||||
pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
|
||||
GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
|
||||
|
||||
|
||||
powrprof_module = LoadLibraryA("powrprof.dll");
|
||||
if (powrprof_module != NULL) {
|
||||
pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
|
||||
GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4145,7 +4145,7 @@ typedef const UNICODE_STRING *PCUNICODE_STRING;
|
||||
struct {
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
} DUMMYUNIONNAME;
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
#endif
|
||||
|
||||
@@ -4153,7 +4153,7 @@ typedef struct _IO_STATUS_BLOCK {
|
||||
union {
|
||||
NTSTATUS Status;
|
||||
PVOID Pointer;
|
||||
} DUMMYUNIONNAME;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
@@ -4606,6 +4606,10 @@ typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
|
||||
#endif
|
||||
|
||||
/* from winerror.h */
|
||||
#ifndef ERROR_ELEVATION_REQUIRED
|
||||
# define ERROR_ELEVATION_REQUIRED 740
|
||||
#endif
|
||||
|
||||
#ifndef ERROR_SYMLINK_NOT_SUPPORTED
|
||||
# define ERROR_SYMLINK_NOT_SUPPORTED 1464
|
||||
#endif
|
||||
@@ -4684,6 +4688,40 @@ typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
|
||||
DWORD cchFilePath,
|
||||
DWORD dwFlags);
|
||||
|
||||
/* from powerbase.h */
|
||||
#ifndef DEVICE_NOTIFY_CALLBACK
|
||||
# define DEVICE_NOTIFY_CALLBACK 2
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMEAUTOMATIC
|
||||
# define PBT_APMRESUMEAUTOMATIC 18
|
||||
#endif
|
||||
|
||||
#ifndef PBT_APMRESUMESUSPEND
|
||||
# define PBT_APMRESUMESUSPEND 7
|
||||
#endif
|
||||
|
||||
typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
|
||||
PVOID Context,
|
||||
ULONG Type,
|
||||
PVOID Setting
|
||||
);
|
||||
typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
|
||||
|
||||
typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
|
||||
_PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
|
||||
PVOID Context;
|
||||
} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
|
||||
|
||||
typedef PVOID _HPOWERNOTIFY;
|
||||
typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
|
||||
|
||||
typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
|
||||
(DWORD Flags,
|
||||
HANDLE Recipient,
|
||||
_PHPOWERNOTIFY RegistrationHandle);
|
||||
|
||||
|
||||
/* Ntdll function pointers */
|
||||
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
|
||||
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
|
||||
@@ -4707,4 +4745,8 @@ extern sWakeConditionVariable pWakeConditionVariable;
|
||||
extern sCancelSynchronousIo pCancelSynchronousIo;
|
||||
extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
|
||||
|
||||
|
||||
/* Powrprof.dll function pointer */
|
||||
extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
|
||||
|
||||
#endif /* UV_WIN_WINAPI_H_ */
|
||||
|
||||
Reference in New Issue
Block a user