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