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