Browse Source

Upgrade libuv to 2e9a743

v0.7.4-release
Ryan Dahl 13 years ago
parent
commit
89b14fc0ff
  1. 2
      deps/uv/config-mingw.mk
  2. 1
      deps/uv/include/uv-win.h
  3. 2
      deps/uv/msvs/libuv-test.vcxproj
  4. 1
      deps/uv/src/win/internal.h
  5. 67
      deps/uv/src/win/pipe.c
  6. 151
      deps/uv/src/win/process.c
  7. 6
      deps/uv/test/test-list.h
  8. 44
      deps/uv/test/test-spawn.c

2
deps/uv/config-mingw.mk

@ -33,7 +33,7 @@ WIN_OBJS=$(WIN_SRCS:.c=.o)
RUNNER_CFLAGS=$(CFLAGS) -D_GNU_SOURCE # Need _GNU_SOURCE for strdup?
RUNNER_LINKFLAGS=$(LINKFLAGS)
RUNNER_LIBS=-lws2_32 -lrpcrt4 -lole32
RUNNER_LIBS=-lws2_32
RUNNER_SRC=test/runner-win.c
uv.a: $(WIN_OBJS) src/uv-common.o src/uv-eio.o src/eio/eio.o $(CARES_OBJS)

1
deps/uv/include/uv-win.h

@ -178,6 +178,7 @@ typedef struct uv_buf_t {
HANDLE child_pipe; \
} stdio_pipes[3]; \
int exit_signal; \
DWORD spawn_errno; \
HANDLE wait_handle; \
HANDLE process_handle; \
HANDLE close_handle;

2
deps/uv/msvs/libuv-test.vcxproj

@ -84,7 +84,7 @@
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;RpcRT4.Lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">

1
deps/uv/src/win/internal.h

@ -166,7 +166,6 @@ int uv_pipe_init_with_handle(uv_pipe_t* handle, HANDLE pipeHandle);
int uv_stdio_pipe_server(uv_pipe_t* handle, DWORD access, char* name, size_t nameSize);
void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err);
void uv_pipe_endgame(uv_pipe_t* handle);
int uv_unique_pipe_name(char* name, size_t size);
int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
int uv_pipe_accept(uv_pipe_t* server, uv_pipe_t* client);

67
deps/uv/src/win/pipe.c

@ -32,29 +32,8 @@
static char uv_zero_[] = "";
int uv_unique_pipe_name(char* name, size_t size) {
unsigned char* guid_str = NULL;
GUID guid;
int err;
if (CoCreateGuid(&guid) != S_OK) {
err = -1;
goto done;
}
if (UuidToStringA(&guid, &guid_str) != ERROR_SUCCESS) {
err = -1;
goto done;
}
_snprintf(name, size, "\\\\.\\pipe\\uv\\%s", guid_str);
err = 0;
done:
if (guid_str) {
RpcStringFreeA(&guid_str);
}
return err;
static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
_snprintf(name, size, "\\\\.\\pipe\\uv\\%p-%d", ptr, GetCurrentProcessId());
}
@ -92,26 +71,36 @@ int uv_pipe_init_with_handle(uv_pipe_t* handle, HANDLE pipeHandle) {
int uv_stdio_pipe_server(uv_pipe_t* handle, DWORD access, char* name, size_t nameSize) {
HANDLE pipeHandle;
int errno;
int err;
char* ptr = (char*)handle;
err = uv_unique_pipe_name(name, nameSize);
if (err) {
goto done;
}
while (TRUE) {
uv_unique_pipe_name(ptr, name, nameSize);
pipeHandle = CreateNamedPipeA(name,
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
65536,
65536,
0,
NULL);
pipeHandle = CreateNamedPipeA(name,
access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1,
65536,
65536,
0,
NULL);
if (pipeHandle == INVALID_HANDLE_VALUE) {
uv_set_sys_error(GetLastError());
err = -1;
goto done;
if (pipeHandle != INVALID_HANDLE_VALUE) {
/* No name collisions. We're done. */
break;
}
errno = GetLastError();
if (errno != ERROR_PIPE_BUSY && errno != ERROR_ACCESS_DENIED) {
uv_set_sys_error(errno);
err = -1;
goto done;
}
/* Pipe name collision. Increment the pointer and try again. */
ptr++;
}
if (CreateIoCompletionPort(pipeHandle,

151
deps/uv/src/win/process.c

@ -496,16 +496,16 @@ wchar_t* make_program_env(char** env_block) {
}
/*
* Called on Windows thread-pool thread to indicate that
* a child process has exited.
/*
* Called on Windows thread-pool thread to indicate that
* a child process has exited.
*/
static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
uv_process_t* process = (uv_process_t*)data;
assert(didTimeout == FALSE);
assert(process);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
@ -518,13 +518,13 @@ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
}
/*
* Called on Windows thread-pool thread to indicate that
* UnregisterWaitEx has completed.
/*
* Called on Windows thread-pool thread to indicate that
* UnregisterWaitEx has completed.
*/
static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
uv_process_t* process = (uv_process_t*)data;
assert(didTimeout == FALSE);
assert(process);
@ -540,6 +540,54 @@ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) {
}
/*
* Called on windows thread pool when CreateProcess failed. It writes an error
* message to the process' intended stderr and then posts a PROCESS_EXIT
* packet to the completion port.
*/
static DWORD WINAPI spawn_failure(void* data) {
char syscall[] = "CreateProcessW: ";
char unknown[] = "unknown error\n";
uv_process_t* process = (uv_process_t*) data;
HANDLE child_stderr = process->stdio_pipes[2].child_pipe;
char* buf = NULL;
DWORD count, written;
WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL);
count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
process->spawn_errno,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR) &buf,
0,
NULL);
if (buf != NULL && count > 0) {
WriteFile(child_stderr, buf, count, &written, NULL);
LocalFree(buf);
} else {
WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL);
}
FlushFileBuffers(child_stderr);
memset(&process->exit_req.overlapped, 0, sizeof(process->exit_req.overlapped));
/* Post completed */
if (!PostQueuedCompletionStatus(LOOP->iocp,
0,
0,
&process->exit_req.overlapped)) {
uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
}
return 0;
}
/* Called on main thread after a child process has exited. */
void uv_process_proc_exit(uv_process_t* handle) {
int i;
@ -559,15 +607,18 @@ void uv_process_proc_exit(uv_process_t* handle) {
handle->wait_handle = INVALID_HANDLE_VALUE;
}
/* Clean-up the process handle. */
if (handle->process_handle != INVALID_HANDLE_VALUE) {
/* Get the exit code. */
if (!GetExitCodeProcess(handle->process_handle, &exit_code)) {
exit_code = 1;
exit_code = 127;
}
/* Clean-up the process handle. */
CloseHandle(handle->process_handle);
handle->process_handle = INVALID_HANDLE_VALUE;
} else {
/* The process never even started in the first place. */
exit_code = 127;
}
/* Fire the exit callback. */
@ -618,10 +669,10 @@ static int uv_create_stdio_pipe_pair(uv_pipe_t* server_pipe, HANDLE* child_pipe,
char pipe_name[64];
DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
if (server_pipe->type != UV_NAMED_PIPE) {
if (server_pipe->type != UV_NAMED_PIPE) {
uv_set_error(UV_EINVAL, 0);
err = -1;
goto done;
goto done;
}
/* Create server pipe handle. */
@ -681,13 +732,13 @@ done:
int uv_spawn(uv_process_t* process, uv_process_options_t options) {
int err, i;
int err = 0, i;
wchar_t* path;
int size;
wchar_t* application_path, *application, *arguments, *env, *cwd;
STARTUPINFOW startup;
PROCESS_INFORMATION info;
uv_process_init(process);
process->exit_cb = options.exit_cb;
@ -721,15 +772,15 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
GetEnvironmentVariableW(L"PATH", path, size * sizeof(wchar_t));
path[size - 1] = L'\0';
application_path = search_path(application,
application_path = search_path(application,
cwd,
path,
DEFAULT_PATH_EXT);
if (!application_path) {
uv_set_error(UV_EINVAL, 0);
err = -1;
goto done;
/* CreateProcess will fail, but this allows us to pass this error to */
/* the user asynchronously. */
application_path = application;
}
/* Create stdio pipes. */
@ -771,39 +822,45 @@ int uv_spawn(uv_process_t* process, uv_process_options_t options) {
startup.hStdOutput = process->stdio_pipes[1].child_pipe;
startup.hStdError = process->stdio_pipes[2].child_pipe;
if (!CreateProcessW(application_path,
arguments,
NULL,
NULL,
1,
CREATE_UNICODE_ENVIRONMENT,
env,
cwd,
&startup,
&info)) {
uv_set_sys_error(GetLastError());
err = -1;
goto done;
}
if (CreateProcessW(application_path,
arguments,
NULL,
NULL,
1,
CREATE_UNICODE_ENVIRONMENT,
env,
cwd,
&startup,
&info)) {
/* Spawn succeeded */
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
/* Setup notifications for when the child process exits. */
if (!RegisterWaitForSingleObject(&process->wait_handle, process->process_handle,
exit_wait_callback, (void*)process, INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
}
process->process_handle = info.hProcess;
process->pid = info.dwProcessId;
/* Setup notifications for when the child process exits. */
if (!RegisterWaitForSingleObject(&process->wait_handle, process->process_handle,
exit_wait_callback, (void*)process, INFINITE,
WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
uv_set_sys_error(GetLastError());
err = -1;
goto done;
}
CloseHandle(info.hThread);
CloseHandle(info.hThread);
err = 0;
} else {
/* CreateProcessW failed, but this failure should be delivered */
/* asynchronously to retain unix compatibility. So pretent spawn */
/* succeeded, and start a thread instead that prints an error */
/* to the child's intended stderr. */
process->spawn_errno = GetLastError();
if (!QueueUserWorkItem(spawn_failure, process, WT_EXECUTEDEFAULT)) {
uv_fatal_error(GetLastError(), "QueueUserWorkItem");
}
}
done:
free(application_path);
free(application);
if (application_path != application) {
free(application_path);
}
free(arguments);
free(cwd);
free(env);

6
deps/uv/test/test-list.h

@ -67,6 +67,9 @@ TEST_DECLARE (spawn_exit_code)
TEST_DECLARE (spawn_stdout)
TEST_DECLARE (spawn_stdin)
TEST_DECLARE (spawn_and_kill)
#ifdef _WIN32
TEST_DECLARE (spawn_detect_pipe_name_collisions_on_windows)
#endif
HELPER_DECLARE (tcp4_echo_server)
HELPER_DECLARE (tcp6_echo_server)
HELPER_DECLARE (pipe_echo_server)
@ -148,6 +151,9 @@ TASK_LIST_START
TEST_ENTRY (spawn_stdout)
TEST_ENTRY (spawn_stdin)
TEST_ENTRY (spawn_and_kill)
#ifdef _WIN32
TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows)
#endif
#if 0
/* These are for testing the test runner. */

44
deps/uv/test/test-spawn.c

@ -226,3 +226,47 @@ TEST_IMPL(spawn_and_kill) {
return 0;
}
#ifdef _WIN32
TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) {
int r;
uv_pipe_t out;
char name[64];
HANDLE pipe_handle;
uv_init();
init_process_options("spawn_helper2", exit_cb);
uv_pipe_init(&out);
options.stdout_stream = &out;
/* Create a pipe that'll cause a collision. */
_snprintf(name, sizeof(name), "\\\\.\\pipe\\uv\\%p-%d", &out, GetCurrentProcessId());
pipe_handle = CreateNamedPipeA(name,
PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
10,
65536,
65536,
0,
NULL);
ASSERT(pipe_handle != INVALID_HANDLE_VALUE);
r = uv_spawn(&process, options);
ASSERT(r == 0);
r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read);
ASSERT(r == 0);
r = uv_run();
ASSERT(r == 0);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 2); /* Once for process once for the pipe. */
printf("output is: %s", output);
ASSERT(strcmp("hello world\n", output) == 0 || strcmp("hello world\r\n", output) == 0);
return 0;
}
#endif
Loading…
Cancel
Save