github.com/searKing/golang/go@v1.2.117/os/signal/cgo/signal_handler_unix.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 && unix && !linux
    10  
    11  #include "signal_handler_unix.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  SignalHandler &SignalHandler::GetInstance() {
    22    static SignalHandler instance;
    23    return instance;
    24  }
    25  // https://github.com/boostorg/stacktrace/blob/5c6740b68067cbd7070d2965bfbce32e81f680c9/example/terminate_handler.cpp
    26  void SignalHandler::operator()(int signum, siginfo_t *info, void *context) {
    27    WriteSignalStacktrace(signum);
    28  
    29    void *on_signal_ctx = on_signal_ctx_;
    30    auto on_signal = on_signal_;
    31    if (on_signal) {
    32      on_signal(on_signal_ctx, signal_dump_to_fd_, signum, info, context);
    33    }
    34  
    35    DoSignalChan(signum, info, context);
    36  
    37    InvokeGoSignalHandler(signum, info, context);
    38  }
    39  
    40  void SignalHandler::DoSignalChan(int signum, siginfo_t *info, void *context) {
    41    auto it = sig_invoke_signal_chains_.find(signum);
    42    if (it == sig_invoke_signal_chains_.end()) {
    43      return;
    44    }
    45    auto &sig_chain = it->second;
    46    int from = std::get<0>(sig_chain);
    47    // consist validation_
    48    if (from != signum) {
    49      return;
    50    }
    51    int to = std::get<1>(sig_chain);
    52    int wait = std::get<2>(sig_chain);
    53    int sleepInSeconds = std::get<3>(sig_chain);
    54  
    55    do {
    56      sigset_t new_set, old_set;
    57      if (wait >= 0 && wait != signum) {
    58        // Block {wait} and save current signal mask.
    59        sigemptyset(&new_set);
    60        sigaddset(&new_set, wait);
    61        if (sigprocmask(SIG_BLOCK, &new_set, &old_set) < 0) {
    62          (void)!write(signal_dump_to_fd_, "block Signal(", strlen("block Signal("));
    63          (void)!WriteInt(signal_dump_to_fd_, wait);
    64          (void)!write(signal_dump_to_fd_, ") for Signal(", strlen(") for Signal("));
    65          (void)!WriteInt(signal_dump_to_fd_, signum);
    66          (void)!write(signal_dump_to_fd_, ") failed.\n", strlen(") failed.\n"));
    67          break;
    68        }
    69      }
    70      if (to >= 0 && to != signum) {
    71        InvokeGoSignalHandler(to, info, context);
    72      }
    73      if (wait >= 0 && wait != signum) {
    74        sigset_t ignoremask;
    75        sigfillset(&ignoremask);
    76        sigdelset(&ignoremask, wait);
    77  
    78        // Pause, resume when any signal's signal handler is executed,
    79        // except {wait}.
    80        sigsuspend(&ignoremask);
    81  
    82        // Reset signal mask which unblocks {wait}.
    83        sigprocmask(SIG_SETMASK, &old_set, nullptr);
    84      }
    85    } while (0);
    86  
    87    if (sleepInSeconds > 0) {
    88      sleep(sleepInSeconds);
    89    }
    90  }
    91  void SignalHandler::InvokeGoSignalHandler(int signum, siginfo_t *info,
    92                                            void *context) {
    93    auto it = go_registered_handlers_.find(signum);
    94    if (it != go_registered_handlers_.end()) {
    95      auto handlers = it->second;
    96      SignalHandlerSigActionHandler sigActionHandler = handlers.first;
    97      SignalHandlerSignalHandler signalHandler = handlers.second;
    98  
    99      // http://man7.org/linux/man-pages/man7/signal.7.html
   100      if (sigActionHandler) {
   101        sigActionHandler(signum, info, context);
   102        return;
   103      }
   104      if (signalHandler == SIG_IGN) {
   105        return;
   106      }
   107      if (signalHandler == SIG_DFL) {
   108        struct sigaction preSa;
   109        memset(&preSa, 0, sizeof(preSa));
   110        sigaction(signum, nullptr, &preSa);
   111  
   112        preSa.sa_sigaction = nullptr;
   113        preSa.sa_handler = SIG_DFL;
   114  
   115        sigaction(signum, &preSa, nullptr);
   116        raise(signum);
   117        return;
   118      }
   119  
   120      signalHandler(signum);
   121    }
   122  }
   123  
   124  void SignalHandler::RegisterOnSignal(
   125      std::function<void(void *ctx, int fd, int signum, siginfo_t *info,
   126                         void *context)>
   127          callback,
   128      void *ctx) {
   129    on_signal_ctx_ = ctx;
   130    on_signal_ = callback;
   131  }
   132  
   133  void SignalHandler::SetGoRegisteredSignalHandlersIfEmpty(
   134      int signum, SignalHandlerSigActionHandler action,
   135      SignalHandlerSignalHandler handler) {
   136    auto it = go_registered_handlers_.find(signum);
   137  
   138    // register once, avoid go's signal actions are lost.
   139    if (it == go_registered_handlers_.end()) {
   140      go_registered_handlers_[signum] = std::make_pair(action, handler);
   141    }
   142  }
   143  
   144  // for CGO
   145  
   146  int SignalHandler::SetSig(int signum) {
   147    SignalHandlerSigActionHandler sa_sigaction_action = nullptr;
   148    SignalHandlerSignalHandler sa_sigaction_handler = nullptr;
   149    sa_sigaction_action = [](int signum, siginfo_t *info, void *context) {
   150      GetInstance()(signum, info, context);
   151    };
   152  
   153    return SetSig(signum, sa_sigaction_action, sa_sigaction_handler);
   154  }
   155  
   156  int SignalHandler::SetSig(int signum, SignalHandlerSigActionHandler action,
   157                            SignalHandlerSignalHandler handler) {
   158    stack_t ss;
   159    sigaltstack(NULL, &ss);
   160    ss.ss_sp = malloc(SIGSTKSZ * 100);
   161    ss.ss_size = SIGSTKSZ * 100;
   162    ss.ss_flags = 0;
   163    if (sigaltstack(&ss, NULL) == -1) {
   164      return EXIT_FAILURE;
   165    }
   166    struct sigaction sa;
   167    memset(&sa, 0, sizeof(sa));
   168    sigaction(signum, nullptr, &sa);
   169    //  sigemptyset(&sa.sa_mask);
   170    //  sigfillset(&sa.sa_mask);
   171    if (sa.sa_flags | SA_SIGINFO) {
   172      GetInstance().SetGoRegisteredSignalHandlersIfEmpty(signum, sa.sa_sigaction,
   173                                                         nullptr);
   174    } else {
   175      GetInstance().SetGoRegisteredSignalHandlersIfEmpty(signum, nullptr,
   176                                                         sa.sa_handler);
   177    }
   178    sa.sa_flags = sa.sa_flags & (~SA_SIGINFO);
   179    sa.sa_flags = sa.sa_flags | SA_ONSTACK | SA_RESTART;
   180    sa.sa_handler = nullptr;
   181    if (action) {
   182      // If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of
   183      // sa_handler) specifies the signal-handling function for signum.  This
   184      // function receives three arguments, as described below.
   185      sa.sa_flags = sa.sa_flags | SA_SIGINFO;
   186      sa.sa_sigaction = action;
   187    } else if (handler) {
   188      sa.sa_handler = handler;
   189    }
   190    return sigaction(signum, &sa, nullptr);
   191  }
   192  
   193  }  // namespace searking