From 74b49e821b8ea63052f28cfa1155e813a1b5f07b Mon Sep 17 00:00:00 2001 From: Igor Zinkovsky Date: Wed, 2 Nov 2011 14:05:22 -0700 Subject: [PATCH] uv_kill --- include/uv.h | 4 +++ src/unix/dl.c | 2 -- src/unix/process.c | 11 +++++++ src/uv-common.c | 3 ++ src/uv-common.h | 2 ++ src/win/error.c | 3 -- src/win/internal.h | 5 --- src/win/process.c | 77 +++++++++++++++++++++++++++++++++------------- test/test-list.h | 2 ++ test/test-spawn.c | 44 +++++++++++++++++++++++++- 10 files changed, 120 insertions(+), 33 deletions(-) diff --git a/include/uv.h b/include/uv.h index 3336b757..fda459f0 100644 --- a/include/uv.h +++ b/include/uv.h @@ -983,6 +983,10 @@ UV_EXTERN int uv_spawn(uv_loop_t*, uv_process_t*, UV_EXTERN int uv_process_kill(uv_process_t*, int signum); +/* Kills the process with the specified signal. */ +UV_EXTERN uv_err_t uv_kill(int pid, int signum); + + /* * uv_work_t is a subclass of uv_req_t */ diff --git a/src/unix/dl.c b/src/unix/dl.c index 83355951..6c4ddff8 100644 --- a/src/unix/dl.c +++ b/src/unix/dl.c @@ -26,8 +26,6 @@ #include -static const uv_err_t uv_ok_ = { UV_OK, 0 }; - uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) { void* handle = dlopen(filename, RTLD_LAZY); if (handle == NULL) { diff --git a/src/unix/process.c b/src/unix/process.c index a7686450..555be5a6 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -300,3 +300,14 @@ int uv_process_kill(uv_process_t* process, int signum) { return 0; } } + + +uv_err_t uv_kill(int pid, int signum) { + int r = kill(pid, signum); + + if (r) { + return uv__new_sys_error(errno); + } else { + return uv_ok_; + } +} diff --git a/src/uv-common.c b/src/uv-common.c index 30fc3062..28f9cf6c 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -48,6 +48,9 @@ uv_buf_t uv_buf_init(char* base, size_t len) { } +const uv_err_t uv_ok_ = { UV_OK, 0 }; + + const char* uv_err_name(uv_err_t err) { switch (err.code) { case UV_UNKNOWN: return "UNKNOWN"; diff --git a/src/uv-common.h b/src/uv-common.h index ec6d1519..eecb1304 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -48,6 +48,8 @@ void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle); int uv_ares_handles_empty(uv_loop_t* loop); +extern const uv_err_t uv_ok_; + uv_err_code uv_translate_sys_error(int sys_errno); void uv__set_error(uv_loop_t* loop, uv_err_code code, int sys_error); void uv__set_sys_error(uv_loop_t* loop, int sys_error); diff --git a/src/win/error.c b/src/win/error.c index 1c523227..5b43a65f 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -30,9 +30,6 @@ #include "internal.h" -const uv_err_t uv_ok_ = { UV_OK, ERROR_SUCCESS }; - - /* * Display an error message and abort the event loop. */ diff --git a/src/win/internal.h b/src/win/internal.h index 08dbcc2f..deb8972c 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -286,11 +286,6 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle); int uv_parent_pid(); -/* - * Error handling - */ -extern const uv_err_t uv_ok_; - void uv_fatal_error(const int errorno, const char* syscall); uv_err_code uv_translate_sys_error(int sys_errno); diff --git a/src/win/process.c b/src/win/process.c index 0e709840..195db501 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -26,8 +26,11 @@ #include #include #include +#include #include +#define SIGKILL 9 + typedef struct env_var { const char* narrow; const wchar_t* wide; @@ -1052,35 +1055,65 @@ done: } -int uv_process_kill(uv_process_t* process, int signum) { +static uv_err_t uv__kill(HANDLE process_handle, int signum) { DWORD status; + uv_err_t err; + + if (signum == SIGTERM || signum == SIGKILL) { + /* Kill the process. On Windows, killed processes normally return 1. */ + if (TerminateProcess(process_handle, 1)) { + err = uv_ok_; + } else { + err = uv__new_sys_error(GetLastError()); + } + } else if (signum == 0) { + /* Health check: is the process still alive? */ + if (GetExitCodeProcess(process_handle, &status) && + status == STILL_ACTIVE) { + err = uv_ok_; + } else { + err = uv__new_sys_error(GetLastError()); + } + } else { + err.code = UV_ENOSYS; + } + + return err; +} + + +int uv_process_kill(uv_process_t* process, int signum) { + uv_err_t err; if (process->process_handle == INVALID_HANDLE_VALUE) { uv__set_artificial_error(process->loop, UV_EINVAL); return -1; } - if (signum) { - /* Kill the process. On Windows, killed processes normally return 1. */ - if (TerminateProcess(process->process_handle, 1)) { - process->exit_signal = signum; - return 0; - } - else { - uv__set_sys_error(process->loop, GetLastError()); - return -1; - } - } - else { - /* Health check: is the process still alive? */ - if (GetExitCodeProcess(process->process_handle, &status) && status == STILL_ACTIVE) { - return 0; - } - else { - uv__set_artificial_error(process->loop, UV_EINVAL); - return -1; - } + err = uv__kill(process->process_handle, signum); + + if (err.code != UV_OK) { + uv__set_error(process->loop, err.code, err.sys_errno_); + return -1; } - assert(0 && "unreachable"); + process->exit_signal = signum; + + return 0; +} + + +uv_err_t uv_kill(int pid, int signum) { + uv_err_t err; + HANDLE process_handle = OpenProcess(PROCESS_TERMINATE | + PROCESS_QUERY_INFORMATION, FALSE, pid); + + if (process_handle == INVALID_HANDLE_VALUE) { + return uv__new_sys_error(GetLastError()); + } + + err = uv__kill(process_handle, signum); + CloseHandle(process_handle); + + return err; } diff --git a/test/test-list.h b/test/test-list.h index 70fd7845..49bd5ccc 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -89,6 +89,7 @@ TEST_DECLARE (spawn_stdout) TEST_DECLARE (spawn_stdin) TEST_DECLARE (spawn_and_kill) TEST_DECLARE (spawn_and_ping) +TEST_DECLARE (kill) TEST_DECLARE (fs_file_noent) TEST_DECLARE (fs_file_async) TEST_DECLARE (fs_file_sync) @@ -227,6 +228,7 @@ TASK_LIST_START TEST_ENTRY (spawn_stdin) TEST_ENTRY (spawn_and_kill) TEST_ENTRY (spawn_and_ping) + TEST_ENTRY (kill) #ifdef _WIN32 TEST_ENTRY (spawn_detect_pipe_name_collisions_on_windows) TEST_ENTRY (argument_escaping) diff --git a/test/test-spawn.c b/test/test-spawn.c index e7351585..192644ba 100644 --- a/test/test-spawn.c +++ b/test/test-spawn.c @@ -33,6 +33,7 @@ static uv_process_options_t options; static char exepath[1024]; static size_t exepath_size = 1024; static char* args[3]; +static int no_term_signal; #define OUTPUT_SIZE 1024 static char output[OUTPUT_SIZE]; @@ -55,6 +56,8 @@ static void exit_cb(uv_process_t* process, int exit_status, int term_signal) { static void kill_cb(uv_process_t* process, int exit_status, int term_signal) { + uv_err_t err; + printf("exit_cb\n"); exit_cb_called++; #ifdef _WIN32 @@ -62,8 +65,14 @@ static void kill_cb(uv_process_t* process, int exit_status, int term_signal) { #else ASSERT(exit_status == 0); #endif - ASSERT(term_signal == 15); + ASSERT(no_term_signal || term_signal == 15); uv_close((uv_handle_t*)process, close_cb); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + err = uv_kill(process->pid, 0); + ASSERT(err.code != UV_OK); } @@ -261,6 +270,39 @@ TEST_IMPL(spawn_and_ping) { } +TEST_IMPL(kill) { + int r; + uv_err_t err; + +#ifdef _WIN32 + no_term_signal = 1; +#endif + + init_process_options("spawn_helper4", kill_cb); + + r = uv_spawn(uv_default_loop(), &process, options); + ASSERT(r == 0); + + /* Sending signum == 0 should check if the + * child process is still alive, not kill it. + */ + err = uv_kill(process.pid, 0); + ASSERT(err.code == UV_OK); + + /* Kill the process. */ + err = uv_kill(process.pid, /* SIGTERM */ 15); + ASSERT(err.code == UV_OK); + + r = uv_run(uv_default_loop()); + ASSERT(r == 0); + + ASSERT(exit_cb_called == 1); + ASSERT(close_cb_called == 1); + + return 0; +} + + #ifdef _WIN32 TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { int r;