Commit e21c7412 authored by Pavel Vainerman's avatar Pavel Vainerman

(UniSetActivator): добавил отдельный stack при обработке SIGSEGV

и добавил по умолчанию вывод в cerr.
parent 71329ec7
...@@ -52,7 +52,7 @@ using namespace std; ...@@ -52,7 +52,7 @@ using namespace std;
Завершение работы организовано следующим образом: Завершение работы организовано следующим образом:
------------------------------------------------- -------------------------------------------------
Т.к. UniSetActivator в системе только один (singleton), он заказывает на себя Т.к. UniSetActivator в системе только один (singleton), он заказывает на себя
все сигналы связанные с завершением работы, а также устанавливает обработчики на штатный выход из прораммы (atexit) все сигналы связанные с завершением работы, а также устанавливает обработчики на штатный выход из программы (atexit)
и обработчик на выход по исключению (set_terminate). и обработчик на выход по исключению (set_terminate).
В качестве обработчика сигналов регистрируется функция activator_terminate( int signo ). В качестве обработчика сигналов регистрируется функция activator_terminate( int signo ).
При вызове run() (в функции work) создаётся "глобальный" поток g_term_thread, который При вызове run() (в функции work) создаётся "глобальный" поток g_term_thread, который
...@@ -77,6 +77,15 @@ using namespace std; ...@@ -77,6 +77,15 @@ using namespace std;
В случае, если для UniSetActivator был создан отдельный поток ( run(true) ) при завершении работы программы В случае, если для UniSetActivator был создан отдельный поток ( run(true) ) при завершении работы программы
срабатывает обработчик UniSetActivator::normalexit или UniSetActivator::normalterminate, которые срабатывает обработчик UniSetActivator::normalexit или UniSetActivator::normalterminate, которые
делают тоже самое. Будят процесс завершения.. и дожидаются завершения его работы. делают тоже самое. Будят процесс завершения.. и дожидаются завершения его работы.
// Обработка SIGSEGV
Для обработки SIGSEGV выделен отдельный обработчик (activator_terminate_with_calltrace),
который выводит stack trace и завершает работу.
Если для ulog включён SYSTEM, то trace выводится в него для возможности (если получиться)
увидеть его удалённо через logserver (если он запушен).
Если не включён, то выводиться в cerr.
Сам обработчик только выводит trace и завершает работу, восстановив обработчик SIGSEGV по умолчанию,
без какой-либо специальной обработки завершения.
*/ */
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
static std::shared_ptr<UniSetActivator> g_act; static std::shared_ptr<UniSetActivator> g_act;
...@@ -104,12 +113,10 @@ static const int KILL_TIMEOUT = 8; ...@@ -104,12 +113,10 @@ static const int KILL_TIMEOUT = 8;
// выделим необходимое для stacktrace зараннее // выделим необходимое для stacktrace зараннее
// ---------- // ----------
#define FUNCNAMESIZE 256 #define FUNCNAMESIZE 256
static size_t funcnamesize = FUNCNAMESIZE;
static char funcname[FUNCNAMESIZE];
// storage array for stack trace address data
#define MAXFRAMES 64 #define MAXFRAMES 64
static void* addrlist[MAXFRAMES]; // выделение специального стека заранее
static char g_stack_body[MAXFRAMES*FUNCNAMESIZE+500];
static stack_t g_sigseg_stack;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
// код функции printStackTrace взят с https://oroboro.com/stack-trace-on-crash/ // код функции printStackTrace взят с https://oroboro.com/stack-trace-on-crash/
// будет работать только под LINUX (т.к. используется backtrace) // будет работать только под LINUX (т.к. используется backtrace)
...@@ -118,16 +125,20 @@ static void* addrlist[MAXFRAMES]; ...@@ -118,16 +125,20 @@ static void* addrlist[MAXFRAMES];
// Выводим используя ulog() чтобы можно было удалённо увидеть через LogServer // Выводим используя ulog() чтобы можно было удалённо увидеть через LogServer
// (хотя конечно это как повезёт и зависит от того где собственно произошла ошибка) // (хотя конечно это как повезёт и зависит от того где собственно произошла ошибка)
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
#define TRACELOG ( to_cerr ? cerr : log->system(false) )
static inline void printStackTrace() static inline void printStackTrace()
{ {
auto log = ulog(); auto log = ulog();
if( !log )
return;
if( !log->is_system() ) // если логи отключены, то и выводить не будем
return; bool to_cerr = ( !log || !log->is_system() );
// первый лог выводим с датой, а дальше уже просто
( to_cerr ? cerr : log->system() ) << "stack trace:\n";
TRACELOG << "-----------------------------------------" << endl;
log->system() << "stack trace:\n"; void* addrlist[MAXFRAMES];
// retrieve current stack addresses // retrieve current stack addresses
unsigned int addrlen = backtrace(addrlist, MAXFRAMES); unsigned int addrlen = backtrace(addrlist, MAXFRAMES);
...@@ -143,7 +154,10 @@ static inline void printStackTrace() ...@@ -143,7 +154,10 @@ static inline void printStackTrace()
// this array must be free()-ed // this array must be free()-ed
char** symbollist = backtrace_symbols( addrlist, addrlen ); char** symbollist = backtrace_symbols( addrlist, addrlen );
log->system() << std::left; TRACELOG << std::left;
size_t funcnamesize = FUNCNAMESIZE;
char funcname[FUNCNAMESIZE];
// iterate over the returned symbol lines. skip the first, it is the // iterate over the returned symbol lines. skip the first, it is the
// address of this function. // address of this function.
...@@ -186,7 +200,7 @@ static inline void printStackTrace() ...@@ -186,7 +200,7 @@ static inline void printStackTrace()
if ( begin_offset ) if ( begin_offset )
{ {
log->system() << setw(30) << symbollist[i] TRACELOG << setw(30) << symbollist[i]
<< " ( " << setw(40) << fname << " ( " << setw(40) << fname
<< " +" << setw(6) << begin_offset << " +" << setw(6) << begin_offset
<< ") " << end_offset << ") " << end_offset
...@@ -194,7 +208,7 @@ static inline void printStackTrace() ...@@ -194,7 +208,7 @@ static inline void printStackTrace()
} }
else else
{ {
log->system() << setw(30) << symbollist[i] TRACELOG << setw(30) << symbollist[i]
<< " ( " << setw(40) << fname << " ( " << setw(40) << fname
<< " " << setw(6) << "" << " " << setw(6) << ""
<< ") " << end_offset << ") " << end_offset
...@@ -204,12 +218,12 @@ static inline void printStackTrace() ...@@ -204,12 +218,12 @@ static inline void printStackTrace()
else else
{ {
// couldn't parse the line? print the whole line. // couldn't parse the line? print the whole line.
log->system() << setw(40) << symbollist[i] << endl; TRACELOG << setw(40) << symbollist[i] << endl;
} }
} }
std::free(symbollist); std::free(symbollist);
log->system() << endl << "..end of trace.." << endl << flush; TRACELOG << "-----------------------------------------" << endl << flush;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
static void activator_terminate( int signo ) static void activator_terminate( int signo )
...@@ -722,6 +736,12 @@ void UniSetActivator::set_signals(bool ask) ...@@ -722,6 +736,12 @@ void UniSetActivator::set_signals(bool ask)
act.sa_flags |= SA_RESTART; act.sa_flags |= SA_RESTART;
act.sa_flags |= SA_RESETHAND; act.sa_flags |= SA_RESETHAND;
g_sigseg_stack.ss_sp = g_stack_body;
g_sigseg_stack.ss_flags = SS_ONSTACK;
g_sigseg_stack.ss_size = sizeof(g_stack_body);
assert(!sigaltstack(&g_sigseg_stack, nullptr));
act.sa_flags |= SA_ONSTACK;
if(ask) if(ask)
act.sa_handler = activator_terminate_with_calltrace; act.sa_handler = activator_terminate_with_calltrace;
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment