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