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