github.com/searKing/golang/go@v1.2.117/os/signal/cgo/signal_handler_windows.cpp (about)

     1  // Copyright (c) 2019 The searKing authors. All Rights Reserved.
     2  //
     3  // Use of this source code is governed by a MIT-style license
     4  // that can be found in the LICENSE file in the root of the source
     5  // tree. An additional intellectual property rights grant can be found
     6  // in the file PATENTS.  All contributing project authors may
     7  // be found in the AUTHORS file in the root of the source tree.
     8  
     9  //go:build cgo && windows
    10  
    11  #include "signal_handler_windows.hpp"
    12  
    13  #include <string.h>
    14  
    15  #include <boost/stacktrace.hpp>
    16  #include <fstream>
    17  #include <memory>
    18  #include <sstream>
    19  
    20  namespace searking {
    21  // sig nums must be in [0,255)
    22  static volatile sig_atomic_t gotSignals[256];
    23  
    24  SignalHandler &SignalHandler::GetInstance() {
    25    static SignalHandler instance;
    26    return instance;
    27  }
    28  
    29  // trigger once, and user must register this signum again
    30  void SignalHandler::operator()(int signum) {
    31    WriteSignalStacktrace(signum);
    32    void *on_signal_ctx = on_signal_ctx_;
    33    auto on_signal = on_signal_;
    34  
    35    if (on_signal) {
    36      on_signal(on_signal_ctx, signal_dump_to_fd_, signum);
    37    }
    38    DoSignalChan(signum);
    39  
    40    InvokeGoSignalHandler(signum);
    41  }
    42  
    43  void SignalHandler::DoSignalChan(int signum) {
    44    gotSignals[signum] = true;
    45    auto it = sig_invoke_signal_chains_.find(signum);
    46    if (it == sig_invoke_signal_chains_.end()) {
    47      return;
    48    }
    49    auto &sig_chain = it->second;
    50    int from = std::get<0>(sig_chain);
    51    // consist validation_
    52    if (from != signum) {
    53      return;
    54    }
    55    int to = std::get<1>(sig_chain);
    56    int wait = std::get<2>(sig_chain);
    57    int sleepInSeconds = std::get<3>(sig_chain);
    58    if (to >= 0 && to != signum) {
    59      InvokeGoSignalHandler(to);
    60    }
    61    if (wait >= 0 && wait != signum) {
    62      gotSignals[wait] = false;
    63      for (;;) {
    64        bool got = gotSignals[wait];
    65        if (got) {
    66          gotSignals[wait] = false;
    67          break;
    68        }
    69        // sleep 1s at most, will awake when an unmasked signal is received
    70        sleep(1);
    71      }
    72    }
    73    if (sleepInSeconds > 0) {
    74      sleep(sleepInSeconds);
    75    }
    76  }
    77  
    78  void SignalHandler::InvokeGoSignalHandler(int signum) {
    79    auto it = go_registered_handlers_.find(signum);
    80    if (it != go_registered_handlers_.end()) {
    81      SignalHandlerSignalHandler signalHandler = it->second;
    82      ::signal(signum, signalHandler);
    83      ::raise(signum);
    84    }
    85  }
    86  
    87  void SignalHandler::RegisterOnSignal(
    88      std::function<void(void *ctx, int fd, int signum)> callback, void *ctx) {
    89    on_signal_ctx_ = ctx;
    90    on_signal_ = callback;
    91  }
    92  
    93  void SignalHandler::SetGoRegisteredSignalHandlersIfEmpty(
    94      int signum, SignalHandlerSignalHandler handler) {
    95    auto it = go_registered_handlers_.find(signum);
    96  
    97    // register once, avoid go's signal actions are lost.
    98    if (it == go_registered_handlers_.end()) {
    99      go_registered_handlers_[signum] = handler;
   100    }
   101  }
   102  
   103  int SignalHandler::SetSig(int signum) {
   104    SignalHandlerSignalHandler handler = [](int signum) {
   105      GetInstance()(signum);
   106    };
   107  
   108    return SetSig(signum, handler);
   109  }
   110  
   111  int SignalHandler::SetSig(int signum, SignalHandlerSignalHandler handler) {
   112    SignalHandlerSignalHandler prev_handler = ::signal(signum, SIG_DFL);
   113  
   114    if (SIG_ERR == prev_handler) {
   115      return -1;
   116    }
   117    GetInstance().SetGoRegisteredSignalHandlersIfEmpty(signum, prev_handler);
   118  
   119    ::signal(signum, handler);
   120    return 0;
   121  }
   122  
   123  }  // namespace searking