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