forked from cory/tildefriends
libuv 1.45.0, #include cleanup, probably something else.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@4308 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
70
deps/libuv/src/win/core.c
vendored
70
deps/libuv/src/win/core.c
vendored
@ -245,6 +245,9 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
err = uv_mutex_init(&lfields->loop_metrics.lock);
|
||||
if (err)
|
||||
goto fail_metrics_mutex_init;
|
||||
memset(&lfields->loop_metrics.metrics,
|
||||
0,
|
||||
sizeof(lfields->loop_metrics.metrics));
|
||||
|
||||
/* To prevent uninitialized memory access, loop->time must be initialized
|
||||
* to zero before calling uv_update_time for the first time.
|
||||
@ -279,9 +282,6 @@ int uv_loop_init(uv_loop_t* loop) {
|
||||
|
||||
memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
|
||||
|
||||
loop->active_tcp_streams = 0;
|
||||
loop->active_udp_streams = 0;
|
||||
|
||||
loop->timer_counter = 0;
|
||||
loop->stop_flag = 0;
|
||||
|
||||
@ -424,6 +424,7 @@ int uv_backend_timeout(const uv_loop_t* loop) {
|
||||
|
||||
|
||||
static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
DWORD bytes;
|
||||
ULONG_PTR key;
|
||||
OVERLAPPED* overlapped;
|
||||
@ -433,9 +434,10 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
uint64_t user_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
if (lfields->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
@ -450,6 +452,12 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
/* Store the current timeout in a location that's globally accessible so
|
||||
* other locations like uv__work_done() can determine whether the queue
|
||||
* of events in the callback were waiting when poll was called.
|
||||
*/
|
||||
lfields->current_timeout = timeout;
|
||||
|
||||
GetQueuedCompletionStatus(loop->iocp,
|
||||
&bytes,
|
||||
&key,
|
||||
@ -457,6 +465,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
timeout);
|
||||
|
||||
if (reset_timeout != 0) {
|
||||
if (overlapped && timeout == 0)
|
||||
uv__metrics_inc_events_waiting(loop, 1);
|
||||
timeout = user_timeout;
|
||||
reset_timeout = 0;
|
||||
}
|
||||
@ -469,6 +479,8 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
uv__metrics_update_idle_time(loop);
|
||||
|
||||
if (overlapped) {
|
||||
uv__metrics_inc_events(loop, 1);
|
||||
|
||||
/* Package was dequeued */
|
||||
req = uv__overlapped_to_req(overlapped);
|
||||
uv__insert_pending_req(loop, req);
|
||||
@ -503,6 +515,7 @@ static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
|
||||
|
||||
|
||||
static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
uv__loop_internal_fields_t* lfields;
|
||||
BOOL success;
|
||||
uv_req_t* req;
|
||||
OVERLAPPED_ENTRY overlappeds[128];
|
||||
@ -511,11 +524,13 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
int repeat;
|
||||
uint64_t timeout_time;
|
||||
uint64_t user_timeout;
|
||||
uint64_t actual_timeout;
|
||||
int reset_timeout;
|
||||
|
||||
lfields = uv__get_internal_fields(loop);
|
||||
timeout_time = loop->time + timeout;
|
||||
|
||||
if (uv__get_internal_fields(loop)->flags & UV_METRICS_IDLE_TIME) {
|
||||
if (lfields->flags & UV_METRICS_IDLE_TIME) {
|
||||
reset_timeout = 1;
|
||||
user_timeout = timeout;
|
||||
timeout = 0;
|
||||
@ -524,12 +539,20 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
}
|
||||
|
||||
for (repeat = 0; ; repeat++) {
|
||||
actual_timeout = timeout;
|
||||
|
||||
/* Only need to set the provider_entry_time if timeout != 0. The function
|
||||
* will return early if the loop isn't configured with UV_METRICS_IDLE_TIME.
|
||||
*/
|
||||
if (timeout != 0)
|
||||
uv__metrics_set_provider_entry_time(loop);
|
||||
|
||||
/* Store the current timeout in a location that's globally accessible so
|
||||
* other locations like uv__work_done() can determine whether the queue
|
||||
* of events in the callback were waiting when poll was called.
|
||||
*/
|
||||
lfields->current_timeout = timeout;
|
||||
|
||||
success = pGetQueuedCompletionStatusEx(loop->iocp,
|
||||
overlappeds,
|
||||
ARRAY_SIZE(overlappeds),
|
||||
@ -543,9 +566,9 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
}
|
||||
|
||||
/* Placed here because on success the loop will break whether there is an
|
||||
* empty package or not, or if GetQueuedCompletionStatus returned early then
|
||||
* the timeout will be updated and the loop will run again. In either case
|
||||
* the idle time will need to be updated.
|
||||
* empty package or not, or if pGetQueuedCompletionStatusEx returned early
|
||||
* then the timeout will be updated and the loop will run again. In either
|
||||
* case the idle time will need to be updated.
|
||||
*/
|
||||
uv__metrics_update_idle_time(loop);
|
||||
|
||||
@ -555,6 +578,10 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) {
|
||||
* meant only to wake us up.
|
||||
*/
|
||||
if (overlappeds[i].lpOverlapped) {
|
||||
uv__metrics_inc_events(loop, 1);
|
||||
if (actual_timeout == 0)
|
||||
uv__metrics_inc_events_waiting(loop, 1);
|
||||
|
||||
req = uv__overlapped_to_req(overlappeds[i].lpOverlapped);
|
||||
uv__insert_pending_req(loop, req);
|
||||
}
|
||||
@ -598,10 +625,17 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
if (!r)
|
||||
uv_update_time(loop);
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
uv_update_time(loop);
|
||||
/* Maintain backwards compatibility by processing timers before entering the
|
||||
* while loop for UV_RUN_DEFAULT. Otherwise timers only need to be executed
|
||||
* once, which should be done after polling in order to maintain proper
|
||||
* execution order of the conceptual event loop. */
|
||||
if (mode == UV_RUN_DEFAULT) {
|
||||
if (r)
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
|
||||
while (r != 0 && loop->stop_flag == 0) {
|
||||
can_sleep = loop->pending_reqs_tail == NULL && loop->idle_handles == NULL;
|
||||
|
||||
uv__process_reqs(loop);
|
||||
@ -612,6 +646,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
if ((mode == UV_RUN_ONCE && can_sleep) || mode == UV_RUN_DEFAULT)
|
||||
timeout = uv_backend_timeout(loop);
|
||||
|
||||
uv__metrics_inc_loop_count(loop);
|
||||
|
||||
if (pGetQueuedCompletionStatusEx)
|
||||
uv__poll(loop, timeout);
|
||||
else
|
||||
@ -632,18 +668,8 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
|
||||
uv__check_invoke(loop);
|
||||
uv__process_endgames(loop);
|
||||
|
||||
if (mode == UV_RUN_ONCE) {
|
||||
/* UV_RUN_ONCE implies forward progress: at least one callback must have
|
||||
* been invoked when it returns. uv__io_poll() can return without doing
|
||||
* I/O (meaning: no callbacks) when its timeout expires - which means we
|
||||
* have pending timers that satisfy the forward progress constraint.
|
||||
*
|
||||
* UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
|
||||
* the check.
|
||||
*/
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
}
|
||||
uv_update_time(loop);
|
||||
uv__run_timers(loop);
|
||||
|
||||
r = uv__loop_alive(loop);
|
||||
if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
|
||||
|
67
deps/libuv/src/win/fs.c
vendored
67
deps/libuv/src/win/fs.c
vendored
@ -36,6 +36,8 @@
|
||||
#include "handle-inl.h"
|
||||
#include "fs-fd-hash-inl.h"
|
||||
|
||||
#include <winioctl.h>
|
||||
|
||||
|
||||
#define UV_FS_FREE_PATHS 0x0002
|
||||
#define UV_FS_FREE_PTR 0x0008
|
||||
@ -1706,11 +1708,36 @@ void fs__closedir(uv_fs_t* req) {
|
||||
|
||||
INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
|
||||
int do_lstat) {
|
||||
FILE_FS_DEVICE_INFORMATION device_info;
|
||||
FILE_ALL_INFORMATION file_info;
|
||||
FILE_FS_VOLUME_INFORMATION volume_info;
|
||||
NTSTATUS nt_status;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
|
||||
nt_status = pNtQueryVolumeInformationFile(handle,
|
||||
&io_status,
|
||||
&device_info,
|
||||
sizeof device_info,
|
||||
FileFsDeviceInformation);
|
||||
|
||||
/* Buffer overflow (a warning status code) is expected here. */
|
||||
if (NT_ERROR(nt_status)) {
|
||||
SetLastError(pRtlNtStatusToDosError(nt_status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If it's NUL device set fields as reasonable as possible and return. */
|
||||
if (device_info.DeviceType == FILE_DEVICE_NULL) {
|
||||
memset(statbuf, 0, sizeof(uv_stat_t));
|
||||
statbuf->st_mode = _S_IFCHR;
|
||||
statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
|
||||
((_S_IREAD | _S_IWRITE) >> 6);
|
||||
statbuf->st_nlink = 1;
|
||||
statbuf->st_blksize = 4096;
|
||||
statbuf->st_rdev = FILE_DEVICE_NULL << 16;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nt_status = pNtQueryInformationFile(handle,
|
||||
&io_status,
|
||||
&file_info,
|
||||
@ -1915,6 +1942,37 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
|
||||
}
|
||||
|
||||
|
||||
INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) {
|
||||
DWORD file_type;
|
||||
|
||||
/* Each file type is processed differently. */
|
||||
file_type = uv_guess_handle(fd);
|
||||
switch (file_type) {
|
||||
/* Disk files use the existing logic from fs__stat_handle. */
|
||||
case UV_FILE:
|
||||
return fs__stat_handle(handle, statbuf, 0);
|
||||
|
||||
/* Devices and pipes are processed identically. There is no more information
|
||||
* for them from any API. Fields are set as reasonably as possible and the
|
||||
* function returns. */
|
||||
case UV_TTY:
|
||||
case UV_NAMED_PIPE:
|
||||
memset(statbuf, 0, sizeof(uv_stat_t));
|
||||
statbuf->st_mode = file_type == UV_TTY ? _S_IFCHR : _S_IFIFO;
|
||||
statbuf->st_nlink = 1;
|
||||
statbuf->st_rdev = (file_type == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE) << 16;
|
||||
statbuf->st_ino = (uint64_t) handle;
|
||||
return 0;
|
||||
|
||||
/* If file type is unknown it is an error. */
|
||||
case UV_UNKNOWN_HANDLE:
|
||||
default:
|
||||
SetLastError(ERROR_INVALID_HANDLE);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void fs__stat(uv_fs_t* req) {
|
||||
fs__stat_prepare_path(req->file.pathw);
|
||||
fs__stat_impl(req, 0);
|
||||
@ -1940,7 +1998,7 @@ static void fs__fstat(uv_fs_t* req) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs__stat_handle(handle, &req->statbuf, 0) != 0) {
|
||||
if (fs__fstat_handle(fd, handle, &req->statbuf) != 0) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
@ -2221,7 +2279,7 @@ static void fs__fchmod(uv_fs_t* req) {
|
||||
SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
|
||||
goto fchmod_cleanup;
|
||||
}
|
||||
/* Remeber to clear the flag later on */
|
||||
/* Remember to clear the flag later on */
|
||||
clear_archive_flag = 1;
|
||||
} else {
|
||||
clear_archive_flag = 0;
|
||||
@ -2604,7 +2662,10 @@ static void fs__readlink(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
DWORD error = GetLastError();
|
||||
SET_REQ_WIN32_ERROR(req, error);
|
||||
if (error == ERROR_NOT_A_REPARSE_POINT)
|
||||
req->result = UV_EINVAL;
|
||||
CloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
1
deps/libuv/src/win/internal.h
vendored
1
deps/libuv/src/win/internal.h
vendored
@ -267,7 +267,6 @@ void uv__util_init(void);
|
||||
|
||||
uint64_t uv__hrtime(unsigned int scale);
|
||||
__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);
|
||||
int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
|
||||
|
||||
|
48
deps/libuv/src/win/pipe.c
vendored
48
deps/libuv/src/win/pipe.c
vendored
@ -792,15 +792,17 @@ static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
|
||||
|
||||
/* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait
|
||||
* up to 30 seconds for the pipe to become available with WaitNamedPipe. */
|
||||
while (WaitNamedPipeW(handle->name, 30000)) {
|
||||
while (WaitNamedPipeW(req->u.connect.name, 30000)) {
|
||||
/* The pipe is now available, try to connect. */
|
||||
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
|
||||
pipeHandle = open_named_pipe(req->u.connect.name, &duplex_flags);
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE)
|
||||
break;
|
||||
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
uv__free(req->u.connect.name);
|
||||
req->u.connect.name = NULL;
|
||||
if (pipeHandle != INVALID_HANDLE_VALUE) {
|
||||
SET_REQ_SUCCESS(req);
|
||||
req->u.connect.pipeHandle = pipeHandle;
|
||||
@ -828,6 +830,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
req->cb = cb;
|
||||
req->u.connect.pipeHandle = INVALID_HANDLE_VALUE;
|
||||
req->u.connect.duplex_flags = 0;
|
||||
req->u.connect.name = NULL;
|
||||
|
||||
if (handle->flags & UV_HANDLE_PIPESERVER) {
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
@ -859,10 +862,19 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
|
||||
pipeHandle = open_named_pipe(handle->name, &duplex_flags);
|
||||
if (pipeHandle == INVALID_HANDLE_VALUE) {
|
||||
if (GetLastError() == ERROR_PIPE_BUSY) {
|
||||
req->u.connect.name = uv__malloc(nameSize);
|
||||
if (!req->u.connect.name) {
|
||||
uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
|
||||
}
|
||||
|
||||
memcpy(req->u.connect.name, handle->name, nameSize);
|
||||
|
||||
/* Wait for the server to make a pipe instance available. */
|
||||
if (!QueueUserWorkItem(&pipe_connect_thread_proc,
|
||||
req,
|
||||
WT_EXECUTELONGFUNCTION)) {
|
||||
uv__free(req->u.connect.name);
|
||||
req->u.connect.name = NULL;
|
||||
err = GetLastError();
|
||||
goto error;
|
||||
}
|
||||
@ -1067,11 +1079,12 @@ int uv__pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
|
||||
|
||||
err = uv__tcp_xfer_import(
|
||||
(uv_tcp_t*) client, item->xfer_type, &item->xfer_info);
|
||||
|
||||
uv__free(item);
|
||||
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
uv__free(item);
|
||||
|
||||
} else {
|
||||
pipe_client = (uv_pipe_t*) client;
|
||||
uv__pipe_connection_init(pipe_client);
|
||||
@ -1638,9 +1651,13 @@ static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) {
|
||||
/* If the both ends of the IPC pipe are owned by the same process,
|
||||
* the remote end pid may not yet be set. If so, do it here.
|
||||
* TODO: this is weird; it'd probably better to use a handshake. */
|
||||
if (*pid == 0)
|
||||
*pid = GetCurrentProcessId();
|
||||
|
||||
if (*pid == 0) {
|
||||
GetNamedPipeClientProcessId(handle->handle, pid);
|
||||
if (*pid == GetCurrentProcessId()) {
|
||||
GetNamedPipeServerProcessId(handle->handle, pid);
|
||||
}
|
||||
}
|
||||
|
||||
return *pid;
|
||||
}
|
||||
|
||||
@ -2069,9 +2086,9 @@ void uv__process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
uv__queue_non_overlapped_write(handle);
|
||||
}
|
||||
|
||||
if (handle->stream.conn.write_reqs_pending == 0)
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
|
||||
if (handle->stream.conn.write_reqs_pending == 0 &&
|
||||
uv__is_stream_shutting(handle))
|
||||
uv__pipe_shutdown(loop, handle, handle->stream.conn.shutdown_req);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
@ -2126,7 +2143,10 @@ void uv__process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
if (REQ_SUCCESS(req)) {
|
||||
pipeHandle = req->u.connect.pipeHandle;
|
||||
duplex_flags = req->u.connect.duplex_flags;
|
||||
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
|
||||
if (handle->flags & UV_HANDLE_CLOSING)
|
||||
err = UV_ECANCELED;
|
||||
else
|
||||
err = uv__set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags);
|
||||
if (err)
|
||||
CloseHandle(pipeHandle);
|
||||
} else {
|
||||
@ -2149,7 +2169,6 @@ void uv__process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
|
||||
|
||||
/* Clear the shutdown_req field so we don't go here again. */
|
||||
handle->stream.conn.shutdown_req = NULL;
|
||||
handle->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
||||
if (handle->flags & UV_HANDLE_CLOSING) {
|
||||
@ -2342,7 +2361,10 @@ int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
|
||||
|
||||
if (pipe->ipc) {
|
||||
assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
|
||||
pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
|
||||
GetNamedPipeClientProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid);
|
||||
if (pipe->pipe.conn.ipc_remote_pid == GetCurrentProcessId()) {
|
||||
GetNamedPipeServerProcessId(os_handle, &pipe->pipe.conn.ipc_remote_pid);
|
||||
}
|
||||
assert(pipe->pipe.conn.ipc_remote_pid != (DWORD)(uv_pid_t) -1);
|
||||
}
|
||||
return 0;
|
||||
|
5
deps/libuv/src/win/poll.c
vendored
5
deps/libuv/src/win/poll.c
vendored
@ -425,9 +425,8 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
|
||||
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. */
|
||||
* we find an AFD handle and are able to use the fast poll mechanism.
|
||||
*/
|
||||
#ifndef NDEBUG
|
||||
base_socket = INVALID_SOCKET;
|
||||
#endif
|
||||
|
137
deps/libuv/src/win/process.c
vendored
137
deps/libuv/src/win/process.c
vendored
@ -32,6 +32,9 @@
|
||||
#include "internal.h"
|
||||
#include "handle-inl.h"
|
||||
#include "req-inl.h"
|
||||
#include <dbghelp.h>
|
||||
#include <shlobj.h>
|
||||
#include <psapi.h> /* GetModuleBaseNameW */
|
||||
|
||||
|
||||
#define SIGKILL 9
|
||||
@ -144,7 +147,6 @@ static void uv__process_init(uv_loop_t* loop, uv_process_t* handle) {
|
||||
handle->exit_signal = 0;
|
||||
handle->wait_handle = INVALID_HANDLE_VALUE;
|
||||
handle->process_handle = INVALID_HANDLE_VALUE;
|
||||
handle->child_stdio_buffer = NULL;
|
||||
handle->exit_cb_pending = 0;
|
||||
|
||||
UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
|
||||
@ -947,9 +949,11 @@ int uv_spawn(uv_loop_t* loop,
|
||||
STARTUPINFOW startup;
|
||||
PROCESS_INFORMATION info;
|
||||
DWORD process_flags;
|
||||
BYTE* child_stdio_buffer;
|
||||
|
||||
uv__process_init(loop, process);
|
||||
process->exit_cb = options->exit_cb;
|
||||
child_stdio_buffer = NULL;
|
||||
|
||||
if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
|
||||
return UV_ENOTSUP;
|
||||
@ -1040,7 +1044,7 @@ int uv_spawn(uv_loop_t* loop,
|
||||
}
|
||||
}
|
||||
|
||||
err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
|
||||
err = uv__stdio_create(loop, options, &child_stdio_buffer);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
@ -1059,12 +1063,12 @@ int uv_spawn(uv_loop_t* loop,
|
||||
startup.lpTitle = NULL;
|
||||
startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
|
||||
|
||||
startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
|
||||
startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
|
||||
startup.cbReserved2 = uv__stdio_size(child_stdio_buffer);
|
||||
startup.lpReserved2 = (BYTE*) child_stdio_buffer;
|
||||
|
||||
startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
|
||||
startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
|
||||
startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
|
||||
startup.hStdInput = uv__stdio_handle(child_stdio_buffer, 0);
|
||||
startup.hStdOutput = uv__stdio_handle(child_stdio_buffer, 1);
|
||||
startup.hStdError = uv__stdio_handle(child_stdio_buffer, 2);
|
||||
|
||||
process_flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
|
||||
@ -1178,10 +1182,10 @@ int uv_spawn(uv_loop_t* loop,
|
||||
uv__free(env);
|
||||
uv__free(alloc_path);
|
||||
|
||||
if (process->child_stdio_buffer != NULL) {
|
||||
if (child_stdio_buffer != NULL) {
|
||||
/* Clean up child stdio handles. */
|
||||
uv__stdio_destroy(process->child_stdio_buffer);
|
||||
process->child_stdio_buffer = NULL;
|
||||
uv__stdio_destroy(child_stdio_buffer);
|
||||
child_stdio_buffer = NULL;
|
||||
}
|
||||
|
||||
return uv_translate_sys_error(err);
|
||||
@ -1193,7 +1197,120 @@ static int uv__kill(HANDLE process_handle, int signum) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
/* Create a dump file for the targeted process, if the registry key
|
||||
* `HKLM:Software\Microsoft\Windows\Windows Error Reporting\LocalDumps`
|
||||
* exists. The location of the dumps can be influenced by the `DumpFolder`
|
||||
* sub-key, which has a default value of `%LOCALAPPDATA%\CrashDumps`, see [0]
|
||||
* for more detail. Note that if the dump folder does not exist, we attempt
|
||||
* to create it, to match behavior with WER itself.
|
||||
* [0]: https://learn.microsoft.com/en-us/windows/win32/wer/collecting-user-mode-dumps */
|
||||
if (signum == SIGQUIT) {
|
||||
HKEY registry_key;
|
||||
DWORD pid, ret;
|
||||
WCHAR basename[MAX_PATH];
|
||||
|
||||
/* Get target process name. */
|
||||
GetModuleBaseNameW(process_handle, NULL, &basename[0], sizeof(basename));
|
||||
|
||||
/* Get PID of target process. */
|
||||
pid = GetProcessId(process_handle);
|
||||
|
||||
/* Get LocalDumps directory path. */
|
||||
ret = RegOpenKeyExW(
|
||||
HKEY_LOCAL_MACHINE,
|
||||
L"SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\LocalDumps",
|
||||
0,
|
||||
KEY_QUERY_VALUE,
|
||||
®istry_key);
|
||||
if (ret == ERROR_SUCCESS) {
|
||||
HANDLE hDumpFile = NULL;
|
||||
WCHAR dump_folder[MAX_PATH], dump_name[MAX_PATH];
|
||||
DWORD dump_folder_len = sizeof(dump_folder), key_type = 0;
|
||||
ret = RegGetValueW(registry_key,
|
||||
NULL,
|
||||
L"DumpFolder",
|
||||
RRF_RT_ANY,
|
||||
&key_type,
|
||||
(PVOID) dump_folder,
|
||||
&dump_folder_len);
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
/* Default value for `dump_folder` is `%LOCALAPPDATA%\CrashDumps`. */
|
||||
WCHAR* localappdata;
|
||||
SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, NULL, &localappdata);
|
||||
_snwprintf_s(dump_folder,
|
||||
sizeof(dump_folder),
|
||||
_TRUNCATE,
|
||||
L"%ls\\CrashDumps",
|
||||
localappdata);
|
||||
CoTaskMemFree(localappdata);
|
||||
}
|
||||
RegCloseKey(registry_key);
|
||||
|
||||
/* Create dump folder if it doesn't already exist. */
|
||||
CreateDirectoryW(dump_folder, NULL);
|
||||
|
||||
/* Construct dump filename from process name and PID. */
|
||||
_snwprintf_s(dump_name,
|
||||
sizeof(dump_name),
|
||||
_TRUNCATE,
|
||||
L"%ls\\%ls.%d.dmp",
|
||||
dump_folder,
|
||||
basename,
|
||||
pid);
|
||||
|
||||
hDumpFile = CreateFileW(dump_name,
|
||||
GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
CREATE_NEW,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
if (hDumpFile != INVALID_HANDLE_VALUE) {
|
||||
DWORD dump_options, sym_options;
|
||||
FILE_DISPOSITION_INFO DeleteOnClose = { TRUE };
|
||||
|
||||
/* If something goes wrong while writing it out, delete the file. */
|
||||
SetFileInformationByHandle(hDumpFile,
|
||||
FileDispositionInfo,
|
||||
&DeleteOnClose,
|
||||
sizeof(DeleteOnClose));
|
||||
|
||||
/* Tell wine to dump ELF modules as well. */
|
||||
sym_options = SymGetOptions();
|
||||
SymSetOptions(sym_options | 0x40000000);
|
||||
|
||||
/* MiniDumpWithAvxXStateContext might be undef in server2012r2 or mingw < 12 */
|
||||
#ifndef MiniDumpWithAvxXStateContext
|
||||
#define MiniDumpWithAvxXStateContext 0x00200000
|
||||
#endif
|
||||
/* We default to a fairly complete dump. In the future, we may want to
|
||||
* allow clients to customize what kind of dump to create. */
|
||||
dump_options = MiniDumpWithFullMemory |
|
||||
MiniDumpIgnoreInaccessibleMemory |
|
||||
MiniDumpWithAvxXStateContext;
|
||||
|
||||
if (MiniDumpWriteDump(process_handle,
|
||||
pid,
|
||||
hDumpFile,
|
||||
dump_options,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL)) {
|
||||
/* Don't delete the file on close if we successfully wrote it out. */
|
||||
FILE_DISPOSITION_INFO DontDeleteOnClose = { FALSE };
|
||||
SetFileInformationByHandle(hDumpFile,
|
||||
FileDispositionInfo,
|
||||
&DontDeleteOnClose,
|
||||
sizeof(DontDeleteOnClose));
|
||||
}
|
||||
SymSetOptions(sym_options);
|
||||
CloseHandle(hDumpFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (signum) {
|
||||
case SIGQUIT:
|
||||
case SIGTERM:
|
||||
case SIGKILL:
|
||||
case SIGINT: {
|
||||
|
3
deps/libuv/src/win/stream.c
vendored
3
deps/libuv/src/win/stream.c
vendored
@ -204,7 +204,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_WRITABLE) ||
|
||||
handle->flags & UV_HANDLE_SHUTTING ||
|
||||
uv__is_stream_shutting(handle) ||
|
||||
uv__is_closing(handle)) {
|
||||
return UV_ENOTCONN;
|
||||
}
|
||||
@ -214,7 +214,6 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
|
||||
req->cb = cb;
|
||||
|
||||
handle->flags &= ~UV_HANDLE_WRITABLE;
|
||||
handle->flags |= UV_HANDLE_SHUTTING;
|
||||
handle->stream.conn.shutdown_req = req;
|
||||
handle->reqs_pending++;
|
||||
REGISTER_HANDLE_REQ(loop, handle, req);
|
||||
|
44
deps/libuv/src/win/tcp.c
vendored
44
deps/libuv/src/win/tcp.c
vendored
@ -29,14 +29,6 @@
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
/*
|
||||
* Threshold of active tcp streams for which to preallocate tcp read buffers.
|
||||
* (Due to node slab allocator performing poorly under this pattern,
|
||||
* the optimization is temporarily disabled (threshold=0). This will be
|
||||
* revisited once node allocator is improved.)
|
||||
*/
|
||||
const unsigned int uv_active_tcp_streams_threshold = 0;
|
||||
|
||||
/*
|
||||
* Number of simultaneous pending AcceptEx calls.
|
||||
*/
|
||||
@ -214,7 +206,6 @@ void uv__process_tcp_shutdown_req(uv_loop_t* loop, uv_tcp_t* stream, uv_shutdown
|
||||
assert(stream->flags & UV_HANDLE_CONNECTION);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
|
||||
err = 0;
|
||||
@ -274,7 +265,6 @@ void uv__tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
}
|
||||
|
||||
uv__handle_close(handle);
|
||||
loop->active_tcp_streams--;
|
||||
}
|
||||
|
||||
|
||||
@ -484,26 +474,9 @@ static void uv__tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
|
||||
req = &handle->read_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
/*
|
||||
* Preallocate a read buffer if the number of active streams is below
|
||||
* the threshold.
|
||||
*/
|
||||
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.base == NULL ||
|
||||
handle->tcp.conn.read_buffer.len == 0) {
|
||||
handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
|
||||
return;
|
||||
}
|
||||
assert(handle->tcp.conn.read_buffer.base != NULL);
|
||||
buf = handle->tcp.conn.read_buffer;
|
||||
} else {
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
buf.base = (char*) &uv_zero_;
|
||||
buf.len = 0;
|
||||
}
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
buf.base = (char*) &uv_zero_;
|
||||
buf.len = 0;
|
||||
|
||||
/* Prepare the overlapped structure. */
|
||||
memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
|
||||
@ -550,7 +523,7 @@ int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
||||
struct linger l = { 1, 0 };
|
||||
|
||||
/* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
if (uv__is_stream_shutting(handle))
|
||||
return UV_EINVAL;
|
||||
|
||||
if (0 != setsockopt(handle->socket, SOL_SOCKET, SO_LINGER, (const char*)&l, sizeof(l)))
|
||||
@ -654,7 +627,6 @@ 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) {
|
||||
uv_loop_t* loop = server->loop;
|
||||
int err = 0;
|
||||
int family;
|
||||
|
||||
@ -716,8 +688,6 @@ int uv__tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
|
||||
}
|
||||
}
|
||||
|
||||
loop->active_tcp_streams++;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1163,7 +1133,7 @@ void uv__process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
closesocket(handle->socket);
|
||||
handle->socket = INVALID_SOCKET;
|
||||
}
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
if (uv__is_stream_shutting(handle))
|
||||
uv__process_tcp_shutdown_req(loop,
|
||||
handle,
|
||||
handle->stream.conn.shutdown_req);
|
||||
@ -1248,7 +1218,6 @@ void uv__process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
|
||||
0) == 0) {
|
||||
uv__connection_init((uv_stream_t*)handle);
|
||||
handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
loop->active_tcp_streams++;
|
||||
} else {
|
||||
err = WSAGetLastError();
|
||||
}
|
||||
@ -1331,7 +1300,6 @@ int uv__tcp_xfer_import(uv_tcp_t* tcp,
|
||||
tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
|
||||
}
|
||||
|
||||
tcp->loop->active_tcp_streams++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1432,7 +1400,7 @@ static void uv__tcp_try_cancel_reqs(uv_tcp_t* tcp) {
|
||||
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 (non_ifs_lsp) {
|
||||
DWORD bytes;
|
||||
if (WSAIoctl(socket,
|
||||
|
139
deps/libuv/src/win/thread.c
vendored
139
deps/libuv/src/win/thread.c
vendored
@ -180,6 +180,81 @@ int uv_thread_create_ex(uv_thread_t* tid,
|
||||
return UV_EIO;
|
||||
}
|
||||
|
||||
int uv_thread_setaffinity(uv_thread_t* tid,
|
||||
char* cpumask,
|
||||
char* oldmask,
|
||||
size_t mask_size) {
|
||||
int i;
|
||||
HANDLE hproc;
|
||||
DWORD_PTR procmask;
|
||||
DWORD_PTR sysmask;
|
||||
DWORD_PTR threadmask;
|
||||
DWORD_PTR oldthreadmask;
|
||||
int cpumasksize;
|
||||
|
||||
cpumasksize = uv_cpumask_size();
|
||||
assert(cpumasksize > 0);
|
||||
if (mask_size < (size_t)cpumasksize)
|
||||
return UV_EINVAL;
|
||||
|
||||
hproc = GetCurrentProcess();
|
||||
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
threadmask = 0;
|
||||
for (i = 0; i < cpumasksize; i++) {
|
||||
if (cpumask[i]) {
|
||||
if (procmask & (1 << i))
|
||||
threadmask |= 1 << i;
|
||||
else
|
||||
return UV_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
oldthreadmask = SetThreadAffinityMask(*tid, threadmask);
|
||||
if (oldthreadmask == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
if (oldmask != NULL) {
|
||||
for (i = 0; i < cpumasksize; i++)
|
||||
oldmask[i] = (oldthreadmask >> i) & 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_thread_getaffinity(uv_thread_t* tid,
|
||||
char* cpumask,
|
||||
size_t mask_size) {
|
||||
int i;
|
||||
HANDLE hproc;
|
||||
DWORD_PTR procmask;
|
||||
DWORD_PTR sysmask;
|
||||
DWORD_PTR threadmask;
|
||||
int cpumasksize;
|
||||
|
||||
cpumasksize = uv_cpumask_size();
|
||||
assert(cpumasksize > 0);
|
||||
if (mask_size < (size_t)cpumasksize)
|
||||
return UV_EINVAL;
|
||||
|
||||
hproc = GetCurrentProcess();
|
||||
if (!GetProcessAffinityMask(hproc, &procmask, &sysmask))
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
threadmask = SetThreadAffinityMask(*tid, procmask);
|
||||
if (threadmask == 0 || SetThreadAffinityMask(*tid, threadmask) == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
for (i = 0; i < cpumasksize; i++)
|
||||
cpumask[i] = (threadmask >> i) & 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uv_thread_getcpu(void) {
|
||||
return GetCurrentProcessorNumber();
|
||||
}
|
||||
|
||||
uv_thread_t uv_thread_self(void) {
|
||||
uv_thread_t key;
|
||||
@ -374,6 +449,7 @@ void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
@ -383,69 +459,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) {
|
||||
int err;
|
||||
|
||||
barrier->n = count;
|
||||
barrier->count = 0;
|
||||
|
||||
err = uv_mutex_init(&barrier->mutex);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = uv_sem_init(&barrier->turnstile1, 0);
|
||||
if (err)
|
||||
goto error2;
|
||||
|
||||
err = uv_sem_init(&barrier->turnstile2, 1);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
uv_sem_destroy(&barrier->turnstile1);
|
||||
error2:
|
||||
uv_mutex_destroy(&barrier->mutex);
|
||||
return err;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void uv_barrier_destroy(uv_barrier_t* barrier) {
|
||||
uv_sem_destroy(&barrier->turnstile2);
|
||||
uv_sem_destroy(&barrier->turnstile1);
|
||||
uv_mutex_destroy(&barrier->mutex);
|
||||
}
|
||||
|
||||
|
||||
int uv_barrier_wait(uv_barrier_t* barrier) {
|
||||
int serial_thread;
|
||||
|
||||
uv_mutex_lock(&barrier->mutex);
|
||||
if (++barrier->count == barrier->n) {
|
||||
uv_sem_wait(&barrier->turnstile2);
|
||||
uv_sem_post(&barrier->turnstile1);
|
||||
}
|
||||
uv_mutex_unlock(&barrier->mutex);
|
||||
|
||||
uv_sem_wait(&barrier->turnstile1);
|
||||
uv_sem_post(&barrier->turnstile1);
|
||||
|
||||
uv_mutex_lock(&barrier->mutex);
|
||||
serial_thread = (--barrier->count == 0);
|
||||
if (serial_thread) {
|
||||
uv_sem_wait(&barrier->turnstile1);
|
||||
uv_sem_post(&barrier->turnstile2);
|
||||
}
|
||||
uv_mutex_unlock(&barrier->mutex);
|
||||
|
||||
uv_sem_wait(&barrier->turnstile2);
|
||||
uv_sem_post(&barrier->turnstile2);
|
||||
return serial_thread;
|
||||
}
|
||||
|
||||
|
||||
int uv_key_create(uv_key_t* key) {
|
||||
key->tls_index = TlsAlloc();
|
||||
if (key->tls_index == TLS_OUT_OF_INDEXES)
|
||||
|
25
deps/libuv/src/win/tty.c
vendored
25
deps/libuv/src/win/tty.c
vendored
@ -23,12 +23,7 @@
|
||||
#include <io.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
# include "uv/stdint-msvc2008.h"
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef COMMON_LVB_REVERSE_VIDEO
|
||||
# define COMMON_LVB_REVERSE_VIDEO 0x4000
|
||||
@ -175,14 +170,14 @@ void uv__console_init(void) {
|
||||
0);
|
||||
if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO sb_info;
|
||||
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
uv_mutex_init(&uv__tty_console_resize_mutex);
|
||||
if (GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info)) {
|
||||
uv__tty_console_width = sb_info.dwSize.X;
|
||||
uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||
}
|
||||
QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
|
||||
NULL,
|
||||
WT_EXECUTELONGFUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2239,11 +2234,11 @@ void uv__process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
|
||||
handle->stream.conn.write_reqs_pending--;
|
||||
if (handle->stream.conn.write_reqs_pending == 0)
|
||||
if (handle->flags & UV_HANDLE_SHUTTING)
|
||||
uv__process_tty_shutdown_req(loop,
|
||||
handle,
|
||||
handle->stream.conn.shutdown_req);
|
||||
if (handle->stream.conn.write_reqs_pending == 0 &&
|
||||
uv__is_stream_shutting(handle))
|
||||
uv__process_tty_shutdown_req(loop,
|
||||
handle,
|
||||
handle->stream.conn.shutdown_req);
|
||||
|
||||
DECREASE_PENDING_REQ_COUNT(handle);
|
||||
}
|
||||
@ -2274,7 +2269,6 @@ void uv__process_tty_shutdown_req(uv_loop_t* loop, uv_tty_t* stream, uv_shutdown
|
||||
assert(req);
|
||||
|
||||
stream->stream.conn.shutdown_req = NULL;
|
||||
stream->flags &= ~UV_HANDLE_SHUTTING;
|
||||
UNREGISTER_HANDLE_REQ(loop, stream, req);
|
||||
|
||||
/* TTY shutdown is really just a no-op */
|
||||
@ -2429,7 +2423,6 @@ static void uv__tty_console_signal_resize(void) {
|
||||
height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
|
||||
|
||||
uv_mutex_lock(&uv__tty_console_resize_mutex);
|
||||
assert(uv__tty_console_width != -1 && uv__tty_console_height != -1);
|
||||
if (width != uv__tty_console_width || height != uv__tty_console_height) {
|
||||
uv__tty_console_width = width;
|
||||
uv__tty_console_height = height;
|
||||
|
203
deps/libuv/src/win/udp.c
vendored
203
deps/libuv/src/win/udp.c
vendored
@ -29,11 +29,6 @@
|
||||
#include "req-inl.h"
|
||||
|
||||
|
||||
/*
|
||||
* Threshold of active udp streams for which to preallocate udp read buffers.
|
||||
*/
|
||||
const unsigned int uv_active_udp_streams_threshold = 0;
|
||||
|
||||
/* A zero-size buffer for use by uv_udp_read */
|
||||
static char uv_zero_[] = "";
|
||||
int uv_udp_getpeername(const uv_udp_t* handle,
|
||||
@ -276,84 +271,35 @@ static void uv__udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
|
||||
req = &handle->recv_req;
|
||||
memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
|
||||
|
||||
/*
|
||||
* Preallocate a read buffer if the number of active streams is below
|
||||
* the threshold.
|
||||
*/
|
||||
if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
|
||||
handle->flags &= ~UV_HANDLE_ZERO_READ;
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
|
||||
handle->recv_buffer = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &handle->recv_buffer);
|
||||
if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
|
||||
return;
|
||||
}
|
||||
assert(handle->recv_buffer.base != NULL);
|
||||
buf.base = (char*) uv_zero_;
|
||||
buf.len = 0;
|
||||
flags = MSG_PEEK;
|
||||
|
||||
buf = handle->recv_buffer;
|
||||
memset(&handle->recv_from, 0, sizeof handle->recv_from);
|
||||
handle->recv_from_len = sizeof handle->recv_from;
|
||||
flags = 0;
|
||||
|
||||
result = handle->func_wsarecvfrom(handle->socket,
|
||||
(WSABUF*) &buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
(struct sockaddr*) &handle->recv_from,
|
||||
&handle->recv_from_len,
|
||||
&req->u.io.overlapped,
|
||||
NULL);
|
||||
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv__insert_pending_req(loop, req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv__insert_pending_req(loop, req);
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
result = handle->func_wsarecv(handle->socket,
|
||||
(WSABUF*) &buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
&req->u.io.overlapped,
|
||||
NULL);
|
||||
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv__insert_pending_req(loop, req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
} else {
|
||||
handle->flags |= UV_HANDLE_ZERO_READ;
|
||||
|
||||
buf.base = (char*) uv_zero_;
|
||||
buf.len = 0;
|
||||
flags = MSG_PEEK;
|
||||
|
||||
result = handle->func_wsarecv(handle->socket,
|
||||
(WSABUF*) &buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
&req->u.io.overlapped,
|
||||
NULL);
|
||||
|
||||
if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
|
||||
/* Process the req without IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
req->u.io.overlapped.InternalHigh = bytes;
|
||||
handle->reqs_pending++;
|
||||
uv__insert_pending_req(loop, req);
|
||||
} else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
|
||||
/* The req will be processed with IOCP. */
|
||||
handle->flags |= UV_HANDLE_READ_PENDING;
|
||||
handle->reqs_pending++;
|
||||
} else {
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv__insert_pending_req(loop, req);
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
/* Make this req pending reporting an error. */
|
||||
SET_REQ_ERROR(req, WSAGetLastError());
|
||||
uv__insert_pending_req(loop, req);
|
||||
handle->reqs_pending++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +322,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
loop->active_udp_streams++;
|
||||
|
||||
handle->recv_cb = recv_cb;
|
||||
handle->alloc_cb = alloc_cb;
|
||||
@ -393,7 +338,6 @@ int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
|
||||
int uv__udp_recv_stop(uv_udp_t* handle) {
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
handle->loop->active_udp_streams--;
|
||||
DECREASE_ACTIVE_COUNT(loop, handle);
|
||||
}
|
||||
|
||||
@ -497,57 +441,68 @@ void uv__process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
|
||||
DWORD bytes, err, flags;
|
||||
struct sockaddr_storage from;
|
||||
int from_len;
|
||||
int count;
|
||||
|
||||
/* 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, UV__UDP_DGRAM_MAXSIZE, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
assert(buf.base != NULL);
|
||||
/* Prevent loop starvation when the data comes in as fast as
|
||||
* (or faster than) we can read it. */
|
||||
count = 32;
|
||||
|
||||
memset(&from, 0, sizeof from);
|
||||
from_len = sizeof from;
|
||||
do {
|
||||
/* Do at most `count` nonblocking receive. */
|
||||
buf = uv_buf_init(NULL, 0);
|
||||
handle->alloc_cb((uv_handle_t*) handle, UV__UDP_DGRAM_MAXSIZE, &buf);
|
||||
if (buf.base == NULL || buf.len == 0) {
|
||||
handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
memset(&from, 0, sizeof from);
|
||||
from_len = sizeof from;
|
||||
|
||||
if (WSARecvFrom(handle->socket,
|
||||
(WSABUF*)&buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
(struct sockaddr*) &from,
|
||||
&from_len,
|
||||
NULL,
|
||||
NULL) != SOCKET_ERROR) {
|
||||
flags = 0;
|
||||
|
||||
/* Message received */
|
||||
handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
|
||||
} else {
|
||||
err = WSAGetLastError();
|
||||
if (err == WSAEMSGSIZE) {
|
||||
/* Message truncated */
|
||||
handle->recv_cb(handle,
|
||||
bytes,
|
||||
&buf,
|
||||
(const struct sockaddr*) &from,
|
||||
UV_UDP_PARTIAL);
|
||||
} else if (err == WSAEWOULDBLOCK) {
|
||||
/* Kernel buffer empty */
|
||||
handle->recv_cb(handle, 0, &buf, NULL, 0);
|
||||
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
|
||||
/* WSAECONNRESET/WSANETRESET is ignored because this just indicates
|
||||
* that a previous sendto operation failed.
|
||||
*/
|
||||
handle->recv_cb(handle, 0, &buf, NULL, 0);
|
||||
if (WSARecvFrom(handle->socket,
|
||||
(WSABUF*)&buf,
|
||||
1,
|
||||
&bytes,
|
||||
&flags,
|
||||
(struct sockaddr*) &from,
|
||||
&from_len,
|
||||
NULL,
|
||||
NULL) != SOCKET_ERROR) {
|
||||
|
||||
/* Message received */
|
||||
err = ERROR_SUCCESS;
|
||||
handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
|
||||
} else {
|
||||
/* Any other error that we want to report back to the user. */
|
||||
uv_udp_recv_stop(handle);
|
||||
handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
|
||||
err = WSAGetLastError();
|
||||
if (err == WSAEMSGSIZE) {
|
||||
/* Message truncated */
|
||||
handle->recv_cb(handle,
|
||||
bytes,
|
||||
&buf,
|
||||
(const struct sockaddr*) &from,
|
||||
UV_UDP_PARTIAL);
|
||||
} else if (err == WSAEWOULDBLOCK) {
|
||||
/* Kernel buffer empty */
|
||||
handle->recv_cb(handle, 0, &buf, NULL, 0);
|
||||
} else if (err == WSAECONNRESET || err == WSAENETRESET) {
|
||||
/* WSAECONNRESET/WSANETRESET is ignored because this just indicates
|
||||
* that a previous sendto operation failed.
|
||||
*/
|
||||
handle->recv_cb(handle, 0, &buf, NULL, 0);
|
||||
} else {
|
||||
/* Any other error that we want to report back to the user. */
|
||||
uv_udp_recv_stop(handle);
|
||||
handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (err == ERROR_SUCCESS &&
|
||||
count-- > 0 &&
|
||||
/* The recv_cb callback may decide to pause or close the handle. */
|
||||
(handle->flags & UV_HANDLE_READING) &&
|
||||
!(handle->flags & UV_HANDLE_READ_PENDING));
|
||||
}
|
||||
|
||||
done:
|
||||
|
310
deps/libuv/src/win/util.c
vendored
310
deps/libuv/src/win/util.c
vendored
@ -31,6 +31,7 @@
|
||||
#include "internal.h"
|
||||
|
||||
/* clang-format off */
|
||||
#include <sysinfoapi.h>
|
||||
#include <winsock2.h>
|
||||
#include <winperf.h>
|
||||
#include <iphlpapi.h>
|
||||
@ -121,9 +122,6 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* utf16_len contains the length, *not* including the terminating null. */
|
||||
utf16_buffer[utf16_len] = L'\0';
|
||||
|
||||
/* Convert to UTF-8 */
|
||||
utf8_len = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
@ -151,6 +149,51 @@ int uv_exepath(char* buffer, size_t* size_ptr) {
|
||||
}
|
||||
|
||||
|
||||
static int uv__cwd(WCHAR** buf, DWORD *len) {
|
||||
WCHAR* p;
|
||||
DWORD n;
|
||||
DWORD t;
|
||||
|
||||
t = GetCurrentDirectoryW(0, NULL);
|
||||
for (;;) {
|
||||
if (t == 0)
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
|
||||
/* |t| is the size of the buffer _including_ nul. */
|
||||
p = uv__malloc(t * sizeof(*p));
|
||||
if (p == NULL)
|
||||
return UV_ENOMEM;
|
||||
|
||||
/* |n| is the size of the buffer _excluding_ nul but _only on success_.
|
||||
* If |t| was too small because another thread changed the working
|
||||
* directory, |n| is the size the buffer should be _including_ nul.
|
||||
* It therefore follows we must resize when n >= t and fail when n == 0.
|
||||
*/
|
||||
n = GetCurrentDirectoryW(t, p);
|
||||
if (n > 0)
|
||||
if (n < t)
|
||||
break;
|
||||
|
||||
uv__free(p);
|
||||
t = n;
|
||||
}
|
||||
|
||||
/* The returned directory should not have a trailing slash, unless it points
|
||||
* at a drive root, like c:\. Remove it if needed.
|
||||
*/
|
||||
t = n - 1;
|
||||
if (p[t] == L'\\' && !(n == 3 && p[1] == L':')) {
|
||||
p[t] = L'\0';
|
||||
n = t;
|
||||
}
|
||||
|
||||
*buf = p;
|
||||
*len = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uv_cwd(char* buffer, size_t* size) {
|
||||
DWORD utf16_len;
|
||||
WCHAR *utf16_buffer;
|
||||
@ -160,30 +203,9 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(0, NULL);
|
||||
if (utf16_len == 0) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
utf16_buffer = uv__malloc(utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (utf16_len == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if (utf16_buffer[utf16_len - 1] == L'\\' &&
|
||||
!(utf16_len == 3 && utf16_buffer[1] == L':')) {
|
||||
utf16_len--;
|
||||
utf16_buffer[utf16_len] = L'\0';
|
||||
r = uv__cwd(&utf16_buffer, &utf16_len);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Check how much space we need */
|
||||
@ -226,8 +248,9 @@ int uv_cwd(char* buffer, size_t* size) {
|
||||
|
||||
int uv_chdir(const char* dir) {
|
||||
WCHAR *utf16_buffer;
|
||||
size_t utf16_len, new_utf16_len;
|
||||
DWORD utf16_len;
|
||||
WCHAR drive_letter, env_var[4];
|
||||
int r;
|
||||
|
||||
if (dir == NULL) {
|
||||
return UV_EINVAL;
|
||||
@ -262,32 +285,22 @@ int uv_chdir(const char* dir) {
|
||||
return uv_translate_sys_error(GetLastError());
|
||||
}
|
||||
|
||||
/* uv__cwd() will return a new buffer. */
|
||||
uv__free(utf16_buffer);
|
||||
utf16_buffer = NULL;
|
||||
|
||||
/* 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. */
|
||||
new_utf16_len = GetCurrentDirectoryW(utf16_len, utf16_buffer);
|
||||
if (new_utf16_len > utf16_len ) {
|
||||
uv__free(utf16_buffer);
|
||||
utf16_buffer = uv__malloc(new_utf16_len * sizeof(WCHAR));
|
||||
if (utf16_buffer == NULL) {
|
||||
/* When updating the environment variable fails, return UV_OK anyway.
|
||||
* We did successfully change current working directory, only updating
|
||||
* hidden env variable failed. */
|
||||
return 0;
|
||||
}
|
||||
new_utf16_len = GetCurrentDirectoryW(new_utf16_len, utf16_buffer);
|
||||
}
|
||||
if (utf16_len == 0) {
|
||||
uv__free(utf16_buffer);
|
||||
r = uv__cwd(&utf16_buffer, &utf16_len);
|
||||
if (r == UV_ENOMEM) {
|
||||
/* When updating the environment variable fails, return UV_OK anyway.
|
||||
* We did successfully change current working directory, only updating
|
||||
* hidden env variable failed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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--;
|
||||
utf16_buffer[utf16_len] = L'\0';
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (utf16_len < 2 || utf16_buffer[1] != L':') {
|
||||
@ -330,7 +343,7 @@ uint64_t uv_get_free_memory(void) {
|
||||
memory_status.dwLength = sizeof(memory_status);
|
||||
|
||||
if (!GlobalMemoryStatusEx(&memory_status)) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)memory_status.ullAvailPhys;
|
||||
@ -342,7 +355,7 @@ uint64_t uv_get_total_memory(void) {
|
||||
memory_status.dwLength = sizeof(memory_status);
|
||||
|
||||
if (!GlobalMemoryStatusEx(&memory_status)) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint64_t)memory_status.ullTotalPhys;
|
||||
@ -354,6 +367,11 @@ uint64_t uv_get_constrained_memory(void) {
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_get_available_memory(void) {
|
||||
return uv_get_free_memory();
|
||||
}
|
||||
|
||||
|
||||
uv_pid_t uv_os_getpid(void) {
|
||||
return GetCurrentProcessId();
|
||||
}
|
||||
@ -487,11 +505,43 @@ int uv_get_process_title(char* buffer, size_t size) {
|
||||
}
|
||||
|
||||
|
||||
/* https://github.com/libuv/libuv/issues/1674 */
|
||||
int uv_clock_gettime(uv_clock_id clock_id, uv_timespec64_t* ts) {
|
||||
FILETIME ft;
|
||||
int64_t t;
|
||||
|
||||
if (ts == NULL)
|
||||
return UV_EFAULT;
|
||||
|
||||
switch (clock_id) {
|
||||
case UV_CLOCK_MONOTONIC:
|
||||
uv__once_init();
|
||||
t = uv__hrtime(UV__NANOSEC);
|
||||
ts->tv_sec = t / 1000000000;
|
||||
ts->tv_nsec = t % 1000000000;
|
||||
return 0;
|
||||
case UV_CLOCK_REALTIME:
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
/* In 100-nanosecond increments from 1601-01-01 UTC because why not? */
|
||||
t = (int64_t) ft.dwHighDateTime << 32 | ft.dwLowDateTime;
|
||||
/* Convert to UNIX epoch, 1970-01-01. Still in 100 ns increments. */
|
||||
t -= 116444736000000000ll;
|
||||
/* Now convert to seconds and nanoseconds. */
|
||||
ts->tv_sec = t / 10000000;
|
||||
ts->tv_nsec = t % 10000000 * 100;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return UV_EINVAL;
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv_hrtime(void) {
|
||||
uv__once_init();
|
||||
return uv__hrtime(UV__NANOSEC);
|
||||
}
|
||||
|
||||
|
||||
uint64_t uv__hrtime(unsigned int scale) {
|
||||
LARGE_INTEGER counter;
|
||||
double scaled_freq;
|
||||
@ -678,71 +728,6 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
|
||||
}
|
||||
|
||||
|
||||
static int is_windows_version_or_greater(DWORD os_major,
|
||||
DWORD os_minor,
|
||||
WORD service_pack_major,
|
||||
WORD service_pack_minor) {
|
||||
OSVERSIONINFOEX osvi;
|
||||
DWORDLONG condition_mask = 0;
|
||||
int op = VER_GREATER_EQUAL;
|
||||
|
||||
/* Initialize the OSVERSIONINFOEX structure. */
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
osvi.dwMajorVersion = os_major;
|
||||
osvi.dwMinorVersion = os_minor;
|
||||
osvi.wServicePackMajor = service_pack_major;
|
||||
osvi.wServicePackMinor = service_pack_minor;
|
||||
|
||||
/* Initialize the condition mask. */
|
||||
VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
|
||||
VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
|
||||
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
|
||||
VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
|
||||
|
||||
/* Perform the test. */
|
||||
return (int) VerifyVersionInfo(
|
||||
&osvi,
|
||||
VER_MAJORVERSION | VER_MINORVERSION |
|
||||
VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
|
||||
condition_mask);
|
||||
}
|
||||
|
||||
|
||||
static int address_prefix_match(int family,
|
||||
struct sockaddr* address,
|
||||
struct sockaddr* prefix_address,
|
||||
int prefix_len) {
|
||||
uint8_t* address_data;
|
||||
uint8_t* prefix_address_data;
|
||||
int i;
|
||||
|
||||
assert(address->sa_family == family);
|
||||
assert(prefix_address->sa_family == family);
|
||||
|
||||
if (family == AF_INET6) {
|
||||
address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
|
||||
prefix_address_data =
|
||||
(uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
|
||||
} else {
|
||||
address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
|
||||
prefix_address_data =
|
||||
(uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
|
||||
}
|
||||
|
||||
for (i = 0; i < prefix_len >> 3; i++) {
|
||||
if (address_data[i] != prefix_address_data[i])
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (prefix_len % 8)
|
||||
return prefix_address_data[i] ==
|
||||
(address_data[i] & (0xff << (8 - prefix_len % 8)));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
int* count_ptr) {
|
||||
IP_ADAPTER_ADDRESSES* win_address_buf;
|
||||
@ -755,26 +740,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
uv_interface_address_t* uv_address;
|
||||
|
||||
int count;
|
||||
|
||||
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 |
|
||||
GAA_FLAG_SKIP_DNS_SERVER;
|
||||
} else {
|
||||
/* We need at least XP SP1. */
|
||||
if (!is_windows_version_or_greater(5, 1, 1, 0))
|
||||
return UV_ENOTSUP;
|
||||
|
||||
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
|
||||
GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
|
||||
}
|
||||
|
||||
flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
|
||||
GAA_FLAG_SKIP_DNS_SERVER;
|
||||
|
||||
/* Fetch the size of the adapters reported by windows, and then get the list
|
||||
* itself. */
|
||||
@ -938,37 +910,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
|
||||
|
||||
sa = unicast_address->Address.lpSockaddr;
|
||||
|
||||
/* XP has no OnLinkPrefixLength field. */
|
||||
if (is_vista_or_greater) {
|
||||
prefix_len =
|
||||
((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
|
||||
} else {
|
||||
/* Prior to Windows Vista the FirstPrefix pointed to the list with
|
||||
* single prefix for each IP address assigned to the adapter.
|
||||
* Order of FirstPrefix does not match order of FirstUnicastAddress,
|
||||
* so we need to find corresponding prefix.
|
||||
*/
|
||||
IP_ADAPTER_PREFIX* prefix;
|
||||
prefix_len = 0;
|
||||
|
||||
for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
|
||||
/* We want the longest matching prefix. */
|
||||
if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
|
||||
prefix->PrefixLength <= prefix_len)
|
||||
continue;
|
||||
|
||||
if (address_prefix_match(sa->sa_family, sa,
|
||||
prefix->Address.lpSockaddr, prefix->PrefixLength)) {
|
||||
prefix_len = prefix->PrefixLength;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no matching prefix information, return a single-host
|
||||
* subnet mask (e.g. 255.255.255.255 for IPv4).
|
||||
*/
|
||||
if (!prefix_len)
|
||||
prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
|
||||
}
|
||||
prefix_len =
|
||||
((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
|
||||
|
||||
memset(uv_address, 0, sizeof *uv_address);
|
||||
|
||||
@ -1093,8 +1036,8 @@ int uv_os_homedir(char* buffer, size_t* size) {
|
||||
if (r != UV_ENOENT)
|
||||
return r;
|
||||
|
||||
/* USERPROFILE is not set, so call uv__getpwuid_r() */
|
||||
r = uv__getpwuid_r(&pwd);
|
||||
/* USERPROFILE is not set, so call uv_os_get_passwd() */
|
||||
r = uv_os_get_passwd(&pwd);
|
||||
|
||||
if (r != 0) {
|
||||
return r;
|
||||
@ -1181,17 +1124,6 @@ int uv_os_tmpdir(char* buffer, size_t* size) {
|
||||
}
|
||||
|
||||
|
||||
void uv_os_free_passwd(uv_passwd_t* pwd) {
|
||||
if (pwd == NULL)
|
||||
return;
|
||||
|
||||
uv__free(pwd->username);
|
||||
uv__free(pwd->homedir);
|
||||
pwd->username = NULL;
|
||||
pwd->homedir = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Converts a UTF-16 string into a UTF-8 one. The resulting string is
|
||||
* null-terminated.
|
||||
@ -1288,7 +1220,7 @@ int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
|
||||
}
|
||||
|
||||
|
||||
int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
static int uv__getpwuid_r(uv_passwd_t* pwd) {
|
||||
HANDLE token;
|
||||
wchar_t username[UNLEN + 1];
|
||||
wchar_t *path;
|
||||
@ -1366,6 +1298,16 @@ int uv_os_get_passwd(uv_passwd_t* pwd) {
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_passwd2(uv_passwd_t* pwd, uv_uid_t uid) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_get_group(uv_group_t* grp, uv_uid_t gid) {
|
||||
return UV_ENOTSUP;
|
||||
}
|
||||
|
||||
|
||||
int uv_os_environ(uv_env_item_t** envitems, int* count) {
|
||||
wchar_t* env;
|
||||
wchar_t* penv;
|
||||
@ -1769,6 +1711,22 @@ int uv_os_uname(uv_utsname_t* buffer) {
|
||||
RegCloseKey(registry_key);
|
||||
|
||||
if (r == ERROR_SUCCESS) {
|
||||
/* Windows 11 shares dwMajorVersion with Windows 10
|
||||
* this workaround tries to disambiguate that by checking
|
||||
* if the dwBuildNumber is from Windows 11 releases (>= 22000).
|
||||
*
|
||||
* This workaround replaces the ProductName key value
|
||||
* from "Windows 10 *" to "Windows 11 *" */
|
||||
if (os_info.dwMajorVersion == 10 &&
|
||||
os_info.dwBuildNumber >= 22000 &&
|
||||
product_name_w_size >= ARRAY_SIZE(L"Windows 10")) {
|
||||
/* If ProductName starts with "Windows 10" */
|
||||
if (wcsncmp(product_name_w, L"Windows 10", ARRAY_SIZE(L"Windows 10") - 1) == 0) {
|
||||
/* Bump 10 to 11 */
|
||||
product_name_w[9] = '1';
|
||||
}
|
||||
}
|
||||
|
||||
version_size = WideCharToMultiByte(CP_UTF8,
|
||||
0,
|
||||
product_name_w,
|
||||
|
Reference in New Issue
Block a user