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