github.com/searKing/golang/go@v1.2.117/os/signal/cgo/signal_handler_linux.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 && linux
    10  
    11  #include "signal_handler_linux.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  // https://github.com/boostorg/stacktrace/blob/5c6740b68067cbd7070d2965bfbce32e81f680c9/example/terminate_handler.cpp
    29  void SignalHandler::operator()(int signum, siginfo_t *info, void *context) {
    30    WriteSignalStacktrace(signum);
    31  
    32    void *on_signal_ctx = on_signal_ctx_;
    33    auto on_signal = on_signal_;
    34    if (on_signal) {
    35      on_signal(on_signal_ctx, signal_dump_to_fd_, signum, info, context);
    36    }
    37  
    38    DoSignalChan(signum, info, context);
    39  
    40    InvokeGoSignalHandler(signum, info, context);
    41  }
    42  
    43  void SignalHandler::DoSignalChan(int signum, siginfo_t *info, void *context) {
    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  
    59    if (to >= 0 && to != signum) {
    60      InvokeGoSignalHandler(to, info, context);
    61    }
    62  
    63    // I don't know why suspend will block forever sometimes, so use an ugly
    64    // implement as a loop, the same as in windows
    65    if (wait >= 0 && wait != signum) {
    66      gotSignals[wait] = false;
    67      for (;;) {
    68        bool got = gotSignals[wait];
    69        if (got) {
    70          gotSignals[wait] = false;
    71          break;
    72        }
    73        // sleep 1s at most, will awake when an unmasked signal is received
    74        sleep(1);
    75      }
    76    }
    77  
    78    if (sleepInSeconds > 0) {
    79      sleep(sleepInSeconds);
    80    }
    81  }
    82  void SignalHandler::InvokeGoSignalHandler(int signum, siginfo_t *info,
    83                                            void *context) {
    84    auto it = go_registered_handlers_.find(signum);
    85    if (it != go_registered_handlers_.end()) {
    86      auto handlers = it->second;
    87      SignalHandlerSigActionHandler sigActionHandler = handlers.first;
    88      SignalHandlerSignalHandler signalHandler = handlers.second;
    89  
    90      // http://man7.org/linux/man-pages/man7/signal.7.html
    91      if (sigActionHandler) {
    92        sigActionHandler(signum, info, context);
    93        return;
    94      }
    95      if (signalHandler == SIG_IGN) {
    96        return;
    97      }
    98      if (signalHandler == SIG_DFL) {
    99        struct sigaction preSa;
   100        memset(&preSa, 0, sizeof(preSa));
   101        sigaction(signum, nullptr, &preSa);
   102  
   103        preSa.sa_sigaction = nullptr;
   104        preSa.sa_handler = SIG_DFL;
   105  
   106        sigaction(signum, &preSa, nullptr);
   107        raise(signum);
   108        return;
   109      }
   110  
   111      signalHandler(signum);
   112    }
   113  }
   114  
   115  void SignalHandler::RegisterOnSignal(
   116      std::function<void(void *ctx, int fd, int signum, siginfo_t *info,
   117                         void *context)>
   118          callback,
   119      void *ctx) {
   120    on_signal_ctx_ = ctx;
   121    on_signal_ = callback;
   122  }
   123  
   124  void SignalHandler::SetGoRegisteredSignalHandlersIfEmpty(
   125      int signum, SignalHandlerSigActionHandler action,
   126      SignalHandlerSignalHandler handler) {
   127    auto it = go_registered_handlers_.find(signum);
   128  
   129    // register once, avoid go's signal actions are lost.
   130    if (it == go_registered_handlers_.end()) {
   131      go_registered_handlers_[signum] = std::make_pair(action, handler);
   132    }
   133  }
   134  
   135  // for CGO
   136  
   137  int SignalHandler::SetSig(int signum) {
   138    SignalHandlerSigActionHandler sa_sigaction_action = nullptr;
   139    SignalHandlerSignalHandler sa_sigaction_handler = nullptr;
   140    sa_sigaction_action = [](int signum, siginfo_t *info, void *context) {
   141      GetInstance()(signum, info, context);
   142    };
   143  
   144    return SetSig(signum, sa_sigaction_action, sa_sigaction_handler);
   145  }
   146  
   147  int SignalHandler::SetSig(int signum, SignalHandlerSigActionHandler action,
   148                            SignalHandlerSignalHandler handler) {
   149    stack_t ss;
   150    sigaltstack(NULL, &ss);
   151    ss.ss_sp = malloc(SIGSTKSZ * 100);
   152    ss.ss_size = SIGSTKSZ * 100;
   153    ss.ss_flags = 0;
   154    if (sigaltstack(&ss, NULL) == -1) {
   155      return EXIT_FAILURE;
   156    }
   157    struct sigaction sa;
   158    memset(&sa, 0, sizeof(sa));
   159    sigaction(signum, nullptr, &sa);
   160    //  sigemptyset(&sa.sa_mask);
   161    //  sigfillset(&sa.sa_mask);
   162    if (sa.sa_flags | SA_SIGINFO) {
   163      GetInstance().SetGoRegisteredSignalHandlersIfEmpty(signum, sa.sa_sigaction,
   164                                                         nullptr);
   165    } else {
   166      GetInstance().SetGoRegisteredSignalHandlersIfEmpty(signum, nullptr,
   167                                                         sa.sa_handler);
   168    }
   169    sa.sa_flags = sa.sa_flags & (~SA_SIGINFO);
   170    sa.sa_flags = sa.sa_flags | SA_ONSTACK | SA_RESTART;
   171    sa.sa_handler = nullptr;
   172    if (action) {
   173      // If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of
   174      // sa_handler) specifies the signal-handling function for signum.  This
   175      // function receives three arguments, as described below.
   176      sa.sa_flags = sa.sa_flags | SA_SIGINFO;
   177      sa.sa_sigaction = action;
   178    } else if (handler) {
   179      sa.sa_handler = handler;
   180    }
   181    return sigaction(signum, &sa, nullptr);
   182  }
   183  
   184  }  // namespace searking