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