11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#include <algorithm> 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci#include "async_wrap-inl.h" 251cb0ef41Sopenharmony_ci#include "debug_utils-inl.h" 261cb0ef41Sopenharmony_ci#include "env-inl.h" 271cb0ef41Sopenharmony_ci#include "node_errors.h" 281cb0ef41Sopenharmony_ci#include "node_internals.h" 291cb0ef41Sopenharmony_ci#include "node_watchdog.h" 301cb0ef41Sopenharmony_ci#include "util-inl.h" 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_cinamespace node { 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciusing v8::Context; 351cb0ef41Sopenharmony_ciusing v8::FunctionCallbackInfo; 361cb0ef41Sopenharmony_ciusing v8::FunctionTemplate; 371cb0ef41Sopenharmony_ciusing v8::Isolate; 381cb0ef41Sopenharmony_ciusing v8::Local; 391cb0ef41Sopenharmony_ciusing v8::Object; 401cb0ef41Sopenharmony_ciusing v8::Value; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ciWatchdog::Watchdog(v8::Isolate* isolate, uint64_t ms, bool* timed_out) 431cb0ef41Sopenharmony_ci : isolate_(isolate), timed_out_(timed_out) { 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci int rc; 461cb0ef41Sopenharmony_ci rc = uv_loop_init(&loop_); 471cb0ef41Sopenharmony_ci if (rc != 0) { 481cb0ef41Sopenharmony_ci OnFatalError("node::Watchdog::Watchdog()", "Failed to initialize uv loop."); 491cb0ef41Sopenharmony_ci } 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ci rc = uv_async_init(&loop_, &async_, [](uv_async_t* signal) { 521cb0ef41Sopenharmony_ci Watchdog* w = ContainerOf(&Watchdog::async_, signal); 531cb0ef41Sopenharmony_ci uv_stop(&w->loop_); 541cb0ef41Sopenharmony_ci }); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci CHECK_EQ(0, rc); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci rc = uv_timer_init(&loop_, &timer_); 591cb0ef41Sopenharmony_ci CHECK_EQ(0, rc); 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci rc = uv_timer_start(&timer_, &Watchdog::Timer, ms, 0); 621cb0ef41Sopenharmony_ci CHECK_EQ(0, rc); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci rc = uv_thread_create(&thread_, &Watchdog::Run, this); 651cb0ef41Sopenharmony_ci CHECK_EQ(0, rc); 661cb0ef41Sopenharmony_ci} 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ciWatchdog::~Watchdog() { 701cb0ef41Sopenharmony_ci uv_async_send(&async_); 711cb0ef41Sopenharmony_ci uv_thread_join(&thread_); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci uv_close(reinterpret_cast<uv_handle_t*>(&async_), nullptr); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci // UV_RUN_DEFAULT so that libuv has a chance to clean up. 761cb0ef41Sopenharmony_ci uv_run(&loop_, UV_RUN_DEFAULT); 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci CheckedUvLoopClose(&loop_); 791cb0ef41Sopenharmony_ci} 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_civoid Watchdog::Run(void* arg) { 831cb0ef41Sopenharmony_ci Watchdog* wd = static_cast<Watchdog*>(arg); 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci // UV_RUN_DEFAULT the loop will be stopped either by the async or the 861cb0ef41Sopenharmony_ci // timer handle. 871cb0ef41Sopenharmony_ci uv_run(&wd->loop_, UV_RUN_DEFAULT); 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci // Loop ref count reaches zero when both handles are closed. 901cb0ef41Sopenharmony_ci // Close the timer handle on this side and let ~Watchdog() close async_ 911cb0ef41Sopenharmony_ci uv_close(reinterpret_cast<uv_handle_t*>(&wd->timer_), nullptr); 921cb0ef41Sopenharmony_ci} 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_civoid Watchdog::Timer(uv_timer_t* timer) { 951cb0ef41Sopenharmony_ci Watchdog* w = ContainerOf(&Watchdog::timer_, timer); 961cb0ef41Sopenharmony_ci *w->timed_out_ = true; 971cb0ef41Sopenharmony_ci w->isolate()->TerminateExecution(); 981cb0ef41Sopenharmony_ci uv_stop(&w->loop_); 991cb0ef41Sopenharmony_ci} 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ciSigintWatchdog::SigintWatchdog( 1031cb0ef41Sopenharmony_ci v8::Isolate* isolate, bool* received_signal) 1041cb0ef41Sopenharmony_ci : isolate_(isolate), received_signal_(received_signal) { 1051cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex()); 1061cb0ef41Sopenharmony_ci // Register this watchdog with the global SIGINT/Ctrl+C listener. 1071cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Register(this); 1081cb0ef41Sopenharmony_ci // Start the helper thread, if that has not already happened. 1091cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Start(); 1101cb0ef41Sopenharmony_ci} 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_ciSigintWatchdog::~SigintWatchdog() { 1141cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex()); 1151cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Unregister(this); 1161cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Stop(); 1171cb0ef41Sopenharmony_ci} 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ciSignalPropagation SigintWatchdog::HandleSigint() { 1201cb0ef41Sopenharmony_ci *received_signal_ = true; 1211cb0ef41Sopenharmony_ci isolate_->TerminateExecution(); 1221cb0ef41Sopenharmony_ci return SignalPropagation::kStopPropagation; 1231cb0ef41Sopenharmony_ci} 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_civoid TraceSigintWatchdog::Init(Environment* env, Local<Object> target) { 1261cb0ef41Sopenharmony_ci Isolate* isolate = env->isolate(); 1271cb0ef41Sopenharmony_ci Local<FunctionTemplate> constructor = NewFunctionTemplate(isolate, New); 1281cb0ef41Sopenharmony_ci constructor->InstanceTemplate()->SetInternalFieldCount( 1291cb0ef41Sopenharmony_ci TraceSigintWatchdog::kInternalFieldCount); 1301cb0ef41Sopenharmony_ci constructor->Inherit(HandleWrap::GetConstructorTemplate(env)); 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci SetProtoMethod(isolate, constructor, "start", Start); 1331cb0ef41Sopenharmony_ci SetProtoMethod(isolate, constructor, "stop", Stop); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci SetConstructorFunction( 1361cb0ef41Sopenharmony_ci env->context(), target, "TraceSigintWatchdog", constructor); 1371cb0ef41Sopenharmony_ci} 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_civoid TraceSigintWatchdog::New(const FunctionCallbackInfo<Value>& args) { 1401cb0ef41Sopenharmony_ci // This constructor should not be exposed to public javascript. 1411cb0ef41Sopenharmony_ci // Therefore we assert that we are not trying to call this as a 1421cb0ef41Sopenharmony_ci // normal function. 1431cb0ef41Sopenharmony_ci CHECK(args.IsConstructCall()); 1441cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(args); 1451cb0ef41Sopenharmony_ci new TraceSigintWatchdog(env, args.This()); 1461cb0ef41Sopenharmony_ci} 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_civoid TraceSigintWatchdog::Start(const FunctionCallbackInfo<Value>& args) { 1491cb0ef41Sopenharmony_ci TraceSigintWatchdog* watchdog; 1501cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&watchdog, args.Holder()); 1511cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex()); 1521cb0ef41Sopenharmony_ci // Register this watchdog with the global SIGINT/Ctrl+C listener. 1531cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Register(watchdog); 1541cb0ef41Sopenharmony_ci // Start the helper thread, if that has not already happened. 1551cb0ef41Sopenharmony_ci int r = SigintWatchdogHelper::GetInstance()->Start(); 1561cb0ef41Sopenharmony_ci CHECK_EQ(r, 0); 1571cb0ef41Sopenharmony_ci} 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_civoid TraceSigintWatchdog::Stop(const FunctionCallbackInfo<Value>& args) { 1601cb0ef41Sopenharmony_ci TraceSigintWatchdog* watchdog; 1611cb0ef41Sopenharmony_ci ASSIGN_OR_RETURN_UNWRAP(&watchdog, args.Holder()); 1621cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex()); 1631cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Unregister(watchdog); 1641cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Stop(); 1651cb0ef41Sopenharmony_ci} 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ciTraceSigintWatchdog::TraceSigintWatchdog(Environment* env, Local<Object> object) 1681cb0ef41Sopenharmony_ci : HandleWrap(env, 1691cb0ef41Sopenharmony_ci object, 1701cb0ef41Sopenharmony_ci reinterpret_cast<uv_handle_t*>(&handle_), 1711cb0ef41Sopenharmony_ci AsyncWrap::PROVIDER_SIGINTWATCHDOG) { 1721cb0ef41Sopenharmony_ci int r = uv_async_init(env->event_loop(), &handle_, [](uv_async_t* handle) { 1731cb0ef41Sopenharmony_ci TraceSigintWatchdog* watchdog = 1741cb0ef41Sopenharmony_ci ContainerOf(&TraceSigintWatchdog::handle_, handle); 1751cb0ef41Sopenharmony_ci watchdog->signal_flag_ = SignalFlags::FromIdle; 1761cb0ef41Sopenharmony_ci watchdog->HandleInterrupt(); 1771cb0ef41Sopenharmony_ci }); 1781cb0ef41Sopenharmony_ci CHECK_EQ(r, 0); 1791cb0ef41Sopenharmony_ci uv_unref(reinterpret_cast<uv_handle_t*>(&handle_)); 1801cb0ef41Sopenharmony_ci} 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ciSignalPropagation TraceSigintWatchdog::HandleSigint() { 1831cb0ef41Sopenharmony_ci /** 1841cb0ef41Sopenharmony_ci * In case of uv loop polling, i.e. no JS currently running, activate the 1851cb0ef41Sopenharmony_ci * loop to run a piece of JS code to trigger interruption. 1861cb0ef41Sopenharmony_ci */ 1871cb0ef41Sopenharmony_ci CHECK_EQ(uv_async_send(&handle_), 0); 1881cb0ef41Sopenharmony_ci env()->isolate()->RequestInterrupt( 1891cb0ef41Sopenharmony_ci [](v8::Isolate* isolate, void* data) { 1901cb0ef41Sopenharmony_ci TraceSigintWatchdog* self = static_cast<TraceSigintWatchdog*>(data); 1911cb0ef41Sopenharmony_ci if (self->signal_flag_ == SignalFlags::None) { 1921cb0ef41Sopenharmony_ci self->signal_flag_ = SignalFlags::FromInterrupt; 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci self->HandleInterrupt(); 1951cb0ef41Sopenharmony_ci }, 1961cb0ef41Sopenharmony_ci this); 1971cb0ef41Sopenharmony_ci return SignalPropagation::kContinuePropagation; 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_civoid TraceSigintWatchdog::HandleInterrupt() { 2011cb0ef41Sopenharmony_ci // Do not nest interrupts. 2021cb0ef41Sopenharmony_ci if (interrupting) { 2031cb0ef41Sopenharmony_ci return; 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci interrupting = true; 2061cb0ef41Sopenharmony_ci if (signal_flag_ == SignalFlags::None) { 2071cb0ef41Sopenharmony_ci return; 2081cb0ef41Sopenharmony_ci } 2091cb0ef41Sopenharmony_ci Environment* env_ = env(); 2101cb0ef41Sopenharmony_ci // FIXME: Before 2111cb0ef41Sopenharmony_ci // https://github.com/nodejs/node/pull/29207#issuecomment-527667993 get 2121cb0ef41Sopenharmony_ci // fixed, additional JavaScript code evaluation shall be prevented from 2131cb0ef41Sopenharmony_ci // running during interruption. 2141cb0ef41Sopenharmony_ci FPrintF(stderr, 2151cb0ef41Sopenharmony_ci "KEYBOARD_INTERRUPT: Script execution was interrupted by `SIGINT`\n"); 2161cb0ef41Sopenharmony_ci if (signal_flag_ == SignalFlags::FromInterrupt) { 2171cb0ef41Sopenharmony_ci PrintStackTrace(env_->isolate(), 2181cb0ef41Sopenharmony_ci v8::StackTrace::CurrentStackTrace( 2191cb0ef41Sopenharmony_ci env_->isolate(), 10, v8::StackTrace::kDetailed)); 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci signal_flag_ = SignalFlags::None; 2221cb0ef41Sopenharmony_ci interrupting = false; 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(SigintWatchdogHelper::GetInstanceActionMutex()); 2251cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Unregister(this); 2261cb0ef41Sopenharmony_ci SigintWatchdogHelper::GetInstance()->Stop(); 2271cb0ef41Sopenharmony_ci raise(SIGINT); 2281cb0ef41Sopenharmony_ci} 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci#ifdef __POSIX__ 2311cb0ef41Sopenharmony_civoid* SigintWatchdogHelper::RunSigintWatchdog(void* arg) { 2321cb0ef41Sopenharmony_ci // Inside the helper thread. 2331cb0ef41Sopenharmony_ci bool is_stopping; 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci do { 2361cb0ef41Sopenharmony_ci uv_sem_wait(&instance.sem_); 2371cb0ef41Sopenharmony_ci is_stopping = InformWatchdogsAboutSignal(); 2381cb0ef41Sopenharmony_ci } while (!is_stopping); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci return nullptr; 2411cb0ef41Sopenharmony_ci} 2421cb0ef41Sopenharmony_ci 2431cb0ef41Sopenharmony_civoid SigintWatchdogHelper::HandleSignal(int signum, 2441cb0ef41Sopenharmony_ci siginfo_t* info, 2451cb0ef41Sopenharmony_ci void* ucontext) { 2461cb0ef41Sopenharmony_ci uv_sem_post(&instance.sem_); 2471cb0ef41Sopenharmony_ci} 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci#else 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci// Windows starts a separate thread for executing the handler, so no extra 2521cb0ef41Sopenharmony_ci// helper thread is required. 2531cb0ef41Sopenharmony_ciBOOL WINAPI SigintWatchdogHelper::WinCtrlCHandlerRoutine(DWORD dwCtrlType) { 2541cb0ef41Sopenharmony_ci if (!instance.watchdog_disabled_ && 2551cb0ef41Sopenharmony_ci (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT)) { 2561cb0ef41Sopenharmony_ci InformWatchdogsAboutSignal(); 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci // Return true because the signal has been handled. 2591cb0ef41Sopenharmony_ci return TRUE; 2601cb0ef41Sopenharmony_ci } else { 2611cb0ef41Sopenharmony_ci return FALSE; 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci#endif 2651cb0ef41Sopenharmony_ci 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_cibool SigintWatchdogHelper::InformWatchdogsAboutSignal() { 2681cb0ef41Sopenharmony_ci Mutex::ScopedLock list_lock(instance.list_mutex_); 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci bool is_stopping = false; 2711cb0ef41Sopenharmony_ci#ifdef __POSIX__ 2721cb0ef41Sopenharmony_ci is_stopping = instance.stopping_; 2731cb0ef41Sopenharmony_ci#endif 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci // If there are no listeners and the helper thread has been awoken by a signal 2761cb0ef41Sopenharmony_ci // (= not when stopping it), indicate that by setting has_pending_signal_. 2771cb0ef41Sopenharmony_ci if (instance.watchdogs_.empty() && !is_stopping) { 2781cb0ef41Sopenharmony_ci instance.has_pending_signal_ = true; 2791cb0ef41Sopenharmony_ci } 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci for (auto it = instance.watchdogs_.rbegin(); it != instance.watchdogs_.rend(); 2821cb0ef41Sopenharmony_ci it++) { 2831cb0ef41Sopenharmony_ci SignalPropagation wp = (*it)->HandleSigint(); 2841cb0ef41Sopenharmony_ci if (wp == SignalPropagation::kStopPropagation) { 2851cb0ef41Sopenharmony_ci break; 2861cb0ef41Sopenharmony_ci } 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_ci return is_stopping; 2901cb0ef41Sopenharmony_ci} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci 2931cb0ef41Sopenharmony_ciint SigintWatchdogHelper::Start() { 2941cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci if (start_stop_count_++ > 0) { 2971cb0ef41Sopenharmony_ci return 0; 2981cb0ef41Sopenharmony_ci } 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_ci#ifdef __POSIX__ 3011cb0ef41Sopenharmony_ci CHECK_EQ(has_running_thread_, false); 3021cb0ef41Sopenharmony_ci has_pending_signal_ = false; 3031cb0ef41Sopenharmony_ci stopping_ = false; 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci sigset_t sigmask; 3061cb0ef41Sopenharmony_ci sigfillset(&sigmask); 3071cb0ef41Sopenharmony_ci sigset_t savemask; 3081cb0ef41Sopenharmony_ci CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, &savemask)); 3091cb0ef41Sopenharmony_ci sigmask = savemask; 3101cb0ef41Sopenharmony_ci int ret = pthread_create(&thread_, nullptr, RunSigintWatchdog, nullptr); 3111cb0ef41Sopenharmony_ci CHECK_EQ(0, pthread_sigmask(SIG_SETMASK, &sigmask, nullptr)); 3121cb0ef41Sopenharmony_ci if (ret != 0) { 3131cb0ef41Sopenharmony_ci return ret; 3141cb0ef41Sopenharmony_ci } 3151cb0ef41Sopenharmony_ci has_running_thread_ = true; 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci RegisterSignalHandler(SIGINT, HandleSignal); 3181cb0ef41Sopenharmony_ci#else 3191cb0ef41Sopenharmony_ci if (watchdog_disabled_) { 3201cb0ef41Sopenharmony_ci watchdog_disabled_ = false; 3211cb0ef41Sopenharmony_ci } else { 3221cb0ef41Sopenharmony_ci SetConsoleCtrlHandler(WinCtrlCHandlerRoutine, TRUE); 3231cb0ef41Sopenharmony_ci } 3241cb0ef41Sopenharmony_ci#endif 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ci return 0; 3271cb0ef41Sopenharmony_ci} 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci 3301cb0ef41Sopenharmony_cibool SigintWatchdogHelper::Stop() { 3311cb0ef41Sopenharmony_ci bool had_pending_signal; 3321cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(mutex_); 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci { 3351cb0ef41Sopenharmony_ci Mutex::ScopedLock list_lock(list_mutex_); 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci had_pending_signal = has_pending_signal_; 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci if (--start_stop_count_ > 0) { 3401cb0ef41Sopenharmony_ci has_pending_signal_ = false; 3411cb0ef41Sopenharmony_ci return had_pending_signal; 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci#ifdef __POSIX__ 3451cb0ef41Sopenharmony_ci // Set stopping now because it's only protected by list_mutex_. 3461cb0ef41Sopenharmony_ci stopping_ = true; 3471cb0ef41Sopenharmony_ci#endif 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci watchdogs_.clear(); 3501cb0ef41Sopenharmony_ci } 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci#ifdef __POSIX__ 3531cb0ef41Sopenharmony_ci if (!has_running_thread_) { 3541cb0ef41Sopenharmony_ci has_pending_signal_ = false; 3551cb0ef41Sopenharmony_ci return had_pending_signal; 3561cb0ef41Sopenharmony_ci } 3571cb0ef41Sopenharmony_ci 3581cb0ef41Sopenharmony_ci // Wake up the helper thread. 3591cb0ef41Sopenharmony_ci uv_sem_post(&sem_); 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci // Wait for the helper thread to finish. 3621cb0ef41Sopenharmony_ci CHECK_EQ(0, pthread_join(thread_, nullptr)); 3631cb0ef41Sopenharmony_ci has_running_thread_ = false; 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci RegisterSignalHandler(SIGINT, SignalExit, true); 3661cb0ef41Sopenharmony_ci#else 3671cb0ef41Sopenharmony_ci watchdog_disabled_ = true; 3681cb0ef41Sopenharmony_ci#endif 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci had_pending_signal = has_pending_signal_; 3711cb0ef41Sopenharmony_ci has_pending_signal_ = false; 3721cb0ef41Sopenharmony_ci 3731cb0ef41Sopenharmony_ci return had_pending_signal; 3741cb0ef41Sopenharmony_ci} 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_cibool SigintWatchdogHelper::HasPendingSignal() { 3781cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(list_mutex_); 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_ci return has_pending_signal_; 3811cb0ef41Sopenharmony_ci} 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_civoid SigintWatchdogHelper::Register(SigintWatchdogBase* wd) { 3841cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(list_mutex_); 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci watchdogs_.push_back(wd); 3871cb0ef41Sopenharmony_ci} 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_civoid SigintWatchdogHelper::Unregister(SigintWatchdogBase* wd) { 3901cb0ef41Sopenharmony_ci Mutex::ScopedLock lock(list_mutex_); 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci auto it = std::find(watchdogs_.begin(), watchdogs_.end(), wd); 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci CHECK_NE(it, watchdogs_.end()); 3951cb0ef41Sopenharmony_ci watchdogs_.erase(it); 3961cb0ef41Sopenharmony_ci} 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ciSigintWatchdogHelper::SigintWatchdogHelper() 4001cb0ef41Sopenharmony_ci : start_stop_count_(0), 4011cb0ef41Sopenharmony_ci has_pending_signal_(false) { 4021cb0ef41Sopenharmony_ci#ifdef __POSIX__ 4031cb0ef41Sopenharmony_ci has_running_thread_ = false; 4041cb0ef41Sopenharmony_ci stopping_ = false; 4051cb0ef41Sopenharmony_ci CHECK_EQ(0, uv_sem_init(&sem_, 0)); 4061cb0ef41Sopenharmony_ci#else 4071cb0ef41Sopenharmony_ci watchdog_disabled_ = false; 4081cb0ef41Sopenharmony_ci#endif 4091cb0ef41Sopenharmony_ci} 4101cb0ef41Sopenharmony_ci 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ciSigintWatchdogHelper::~SigintWatchdogHelper() { 4131cb0ef41Sopenharmony_ci start_stop_count_ = 0; 4141cb0ef41Sopenharmony_ci Stop(); 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci#ifdef __POSIX__ 4171cb0ef41Sopenharmony_ci CHECK_EQ(has_running_thread_, false); 4181cb0ef41Sopenharmony_ci uv_sem_destroy(&sem_); 4191cb0ef41Sopenharmony_ci#endif 4201cb0ef41Sopenharmony_ci} 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ciSigintWatchdogHelper SigintWatchdogHelper::instance; 4231cb0ef41Sopenharmony_ciMutex SigintWatchdogHelper::instance_action_mutex_; 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_cinamespace watchdog { 4261cb0ef41Sopenharmony_cistatic void Initialize(Local<Object> target, 4271cb0ef41Sopenharmony_ci Local<Value> unused, 4281cb0ef41Sopenharmony_ci Local<Context> context, 4291cb0ef41Sopenharmony_ci void* priv) { 4301cb0ef41Sopenharmony_ci Environment* env = Environment::GetCurrent(context); 4311cb0ef41Sopenharmony_ci TraceSigintWatchdog::Init(env, target); 4321cb0ef41Sopenharmony_ci} 4331cb0ef41Sopenharmony_ci} // namespace watchdog 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci} // namespace node 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ciNODE_BINDING_CONTEXT_AWARE_INTERNAL(watchdog, node::watchdog::Initialize) 438