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