From 3d70ae7f78fab3842ef9f5a2edf1a7ca71cf93d0 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 13 Aug 2019 12:58:15 -0700 Subject: [PATCH 1/3] refactor: convert to n-api --- src/common.h | 60 ++++++++++++++++++++++ src/watchdog.cc | 131 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 168 insertions(+), 23 deletions(-) create mode 100644 src/common.h diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..b7463ad --- /dev/null +++ b/src/common.h @@ -0,0 +1,60 @@ +#include + +// Empty value so that macros here are able to return NULL or void +#define NAPI_RETVAL_NOTHING // Intentionally blank #define + +#define GET_AND_THROW_LAST_ERROR(env) \ + do \ + { \ + const napi_extended_error_info *error_info; \ + napi_get_last_error_info((env), &error_info); \ + bool is_pending; \ + napi_is_exception_pending((env), &is_pending); \ + /* If an exception is already pending, don't rethrow it */ \ + if (!is_pending) \ + { \ + const char *error_message = error_info->error_message != NULL ? error_info->error_message : "empty error message"; \ + napi_throw_error((env), NULL, error_message); \ + } \ + } while (0) + +#define NAPI_ASSERT_BASE(env, assertion, message, ret_val) \ + do \ + { \ + if (!(assertion)) \ + { \ + napi_throw_error( \ + (env), \ + NULL, \ + "assertion (" #assertion ") failed: " message); \ + return ret_val; \ + } \ + } while (0) + +// Returns NULL on failed assertion. +// This is meant to be used inside napi_callback methods. +#define NAPI_ASSERT(env, assertion, message) \ + NAPI_ASSERT_BASE(env, assertion, message, NULL) + +#define NAPI_CALL_BASE(env, the_call, ret_val) \ + do \ + { \ + if ((the_call) != napi_ok) \ + { \ + GET_AND_THROW_LAST_ERROR((env)); \ + return ret_val; \ + } \ + } while (0) + +// Returns NULL if the_call doesn't return napi_ok. +#define NAPI_CALL(env, the_call) \ + NAPI_CALL_BASE(env, the_call, NULL) + +// Returns empty if the_call doesn't return napi_ok. +#define NAPI_CALL_RETURN_VOID(env, the_call) \ + NAPI_CALL_BASE(env, the_call, NAPI_RETVAL_NOTHING) + +#define DECLARE_NAPI_PROPERTY(name, func) \ + { \ + (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL \ + } diff --git a/src/watchdog.cc b/src/watchdog.cc index 330b2cd..7f9ec7e 100644 --- a/src/watchdog.cc +++ b/src/watchdog.cc @@ -3,21 +3,37 @@ * Licensed under the MIT License. See LICENSE in the project root for license information. *--------------------------------------------------------------------------------------------*/ -#include -#include +#include "common.h" #include #include -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) -#else +#if defined(_WIN32) || defined(__WIN32) +#ifndef WIN32 +#define WIN32 +#endif +#endif + +#if !defined(WIN32) #include +#include +#else +#include #endif -using namespace v8; +namespace +{ + +using WorkerInfo = struct +{ + int64_t parent_pid = 0; + napi_async_work request = nullptr; +}; + +WorkerInfo worker_info; bool w_processIsRunning(long pid) { -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) +#if defined(WIN32) HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid); DWORD ret = WaitForSingleObject(process, 0); CloseHandle(process); @@ -29,44 +45,113 @@ bool w_processIsRunning(long pid) void w_sleep(int seconds) { -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) +#if defined(WIN32) Sleep(seconds * 1000); #else sleep(seconds); #endif } -long w_parentpid = 0; // id of the parent process -uv_thread_t w_monitor_thread_id; // id of the monitor thread - -void w_monitor(void *arg) +void Execute(napi_env env, void *data) { + auto *info = static_cast(data); + + if (info != &worker_info) + { + return; + } + while (true) { - if (!w_processIsRunning(w_parentpid)) + if (!w_processIsRunning(info->parent_pid)) { - w_sleep(5); - exit(87); + return; } w_sleep(1); } } -void _Start(const FunctionCallbackInfo &args) +void Complete(napi_env env, napi_status status, void *data) +{ + auto *info = static_cast(data); + + if (info != &worker_info) + { + napi_throw_type_error(env, nullptr, "Wrong data parameter to Complete."); + return; + } + + if (status != napi_ok) + { + napi_throw_type_error(env, nullptr, "Execute callback failed."); + return; + } + + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, info->request)); + + exit(87); +} + +} // namespace + +napi_value Start(napi_env env, napi_callback_info info) { - w_parentpid = (long)Local::Cast(args[0])->Value(); - uv_thread_create(&w_monitor_thread_id, w_monitor, NULL); + size_t argc = 1; + napi_value argv[1]; + NAPI_CALL(env, + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + + NAPI_ASSERT(env, argc == 1, "Wrong number of arguments, expected 1."); + + napi_valuetype t; + NAPI_CALL(env, napi_typeof(env, argv[0], &t)); + NAPI_ASSERT(env, t == napi_number, + "Wrong argument, number expected."); + + NAPI_CALL(env, napi_get_value_int64(env, argv[0], &worker_info.parent_pid)); + + napi_value resource_name; + NAPI_CALL(env, napi_create_string_utf8( + env, "StartWorkerProcess", NAPI_AUTO_LENGTH, &resource_name)); + NAPI_CALL(env, napi_create_async_work(env, nullptr, resource_name, + Execute, Complete, &worker_info, &worker_info.request)); + NAPI_CALL(env, napi_queue_async_work(env, worker_info.request)); + + return nullptr; } -void _Exit(const FunctionCallbackInfo &args) +napi_value Exit(napi_env env, napi_callback_info info) { - exit(args[0]->Int32Value()); + size_t argc = 1; + napi_value argv[1]; + NAPI_CALL(env, + napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr)); + + NAPI_ASSERT(env, argc == 1, "Wrong number of arguments, expected 1."); + + napi_valuetype t; + NAPI_CALL(env, napi_typeof(env, argv[0], &t)); + NAPI_ASSERT(env, t == napi_number, + "Wrong argument, number expected."); + + int32_t code; + NAPI_CALL(env, napi_get_value_int32(env, argv[0], &code)); + + exit(code); + + return nullptr; } -void init(Local exports) +napi_value Init(napi_env env, napi_value exports) { - NODE_SET_METHOD(exports, "start", _Start); - NODE_SET_METHOD(exports, "exit", _Exit); + napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("start", Start), + DECLARE_NAPI_PROPERTY("exit", Exit)}; + + NAPI_CALL(env, napi_define_properties( + env, exports, sizeof(properties) / sizeof(*properties), properties)); + + return exports; } -NODE_MODULE(addon, init) +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init); From 9e80a7102ed19ea115544e353d0d3adc6b16abd6 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Thu, 15 Aug 2019 16:53:14 -0700 Subject: [PATCH 2/3] fix: delete async task in worker thread and exit --- src/watchdog.cc | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/watchdog.cc b/src/watchdog.cc index 7f9ec7e..173af09 100644 --- a/src/watchdog.cc +++ b/src/watchdog.cc @@ -65,33 +65,15 @@ void Execute(napi_env env, void *data) { if (!w_processIsRunning(info->parent_pid)) { + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, info->request)); + w_sleep(5); + exit(87); return; } w_sleep(1); } } -void Complete(napi_env env, napi_status status, void *data) -{ - auto *info = static_cast(data); - - if (info != &worker_info) - { - napi_throw_type_error(env, nullptr, "Wrong data parameter to Complete."); - return; - } - - if (status != napi_ok) - { - napi_throw_type_error(env, nullptr, "Execute callback failed."); - return; - } - - NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, info->request)); - - exit(87); -} - } // namespace napi_value Start(napi_env env, napi_callback_info info) @@ -114,7 +96,7 @@ napi_value Start(napi_env env, napi_callback_info info) NAPI_CALL(env, napi_create_string_utf8( env, "StartWorkerProcess", NAPI_AUTO_LENGTH, &resource_name)); NAPI_CALL(env, napi_create_async_work(env, nullptr, resource_name, - Execute, Complete, &worker_info, &worker_info.request)); + Execute, nullptr, &worker_info, &worker_info.request)); NAPI_CALL(env, napi_queue_async_work(env, worker_info.request)); return nullptr; From 6b6fb8cf5716d24e2712b54c7021fa891d326f86 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Fri, 16 Aug 2019 13:09:05 -0700 Subject: [PATCH 3/3] fix: Don't call into v8 from worker thread callback --- src/watchdog.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/watchdog.cc b/src/watchdog.cc index 173af09..0bc0552 100644 --- a/src/watchdog.cc +++ b/src/watchdog.cc @@ -65,7 +65,6 @@ void Execute(napi_env env, void *data) { if (!w_processIsRunning(info->parent_pid)) { - NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, info->request)); w_sleep(5); exit(87); return;