linux 信號機制
軟中斷信號 Signal,簡稱信號,用來通知進程發生了異步事件,進程之間可以互相通過系統調用 kill 等函數來發送軟中斷信號。內核也可以因為內部事件而給進程發送信號,通知進程發生了某個事件。
進程對信號的處理
進程對信號的處理有三種方式:
忽略信號: 大部分信號可被忽略,除SIGSTOP和SIGKILL信號外(這是超級用戶殺掉或停掉任意進程的手段)。
捕獲信號: 注冊信號處理函數,它對產生的特定信號做處理。
信號默認動作: unix內核定義的默認動作,有5種情況:
a) 流產abort:終止進程并產生core文件。
b) 終止stop:終止進程但不生成core文件。
c) 忽略:忽略信號。
d) 掛起suspend:掛起進程。
e) 繼續continue:若進程是掛起的,則resume進程,否則忽略此信號。
捕獲進程退出信號
當程序由于某種原因要退出時,系統也會給進程發送信號。
此時,如果沒有對信號進行捕獲,進程就會執行默認退出動作。
當軟件在客戶環境運行時,為了方便 debug, 可以在程序異常退出時,打印程序當前的堆棧信息
下面五種都是進程退出信號。
// 捕獲信號,對于這些信號都執行 coreDumpHandle
signal(SIGQUIT, coreDumpHandle);
signal(SIGILL, coreDumpHandle);
signal(SIGABRT, coreDumpHandle);
signal(SIGSEGV, coreDumpHandle);
signal(SIGTRAP, coreDumpHandle);
可以通過在終端執行 man 7 signal
查看各種信號的說明
c++ 打印堆棧信息
#include <signal.h>
#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <QFile>
#include <QTextStream>void coreDumpHandle(int signum) {string path = "/xxx/xxx/coreDump.log";void* callStack[128];int frames = backstrace(callStack, sizeof(callStack) / sizeof(callStack[0]));char** strs = backtrack_symbols(callStack, frames);if (strs == nullptr)exit(0);QFile out(path.c_str());if (!out.open(QIODevice::WrietOnly | QIODevece::Text | QIODevice::Truncate)) {exit(0);}QTextStream textStream(&out);textStream << "Get signal: " << strsignal(signum) << "\n";textStream << "Call stack:\n";unsigned count = 0;for (int i = 0; i < frames; ++i) {Dl_info info;if (dladdr(callStack[i], &info) && info.dli_sname) {int status;char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);if (status == 0) {QString str = QString("[%1] %2 : %3 0x%4\n").arg(count++).arg(info.dli_fname).arg(demangled).arg(reinterpret_cast<quintptr>(((void*)callStack[i])), 0, 16);textStream << str;} else {QString str = QString("[%1] %2 : %3 0x%4\n").arg(count++).arg(info.dli_fname).arg(info.dli_fname).arg(reinterpret_cast<quintptr>(((void*)callStack[i])), 0, 16);textStream << str;}free(demangled);}else {// printf("[%d] %s : ???\n", i, info.dli_fname);}}out.close();free(strs);exit(0);
}