Commit ce6224ef authored by Pavel Vainerman's avatar Pavel Vainerman

(UActivator): рефакторинг процесса завершения.

Переделал обработку через libev. Убрал (пока) всё лишнее (создание дампа, защитный kill).
parent 30930362
...@@ -25,9 +25,11 @@ ...@@ -25,9 +25,11 @@
#include <deque> #include <deque>
#include <memory> #include <memory>
#include <omniORB4/CORBA.h> #include <omniORB4/CORBA.h>
#include <ev++.h>
#include "UniSetTypes.h" #include "UniSetTypes.h"
#include "UniSetObject.h" #include "UniSetObject.h"
#include "UniSetManager.h" #include "UniSetManager.h"
#include "EventLoopServer.h"
#include "OmniThreadCreator.h" #include "OmniThreadCreator.h"
#include "UHttpRequestHandler.h" #include "UHttpRequestHandler.h"
#include "UHttpServer.h" #include "UHttpServer.h"
...@@ -58,6 +60,7 @@ namespace uniset ...@@ -58,6 +60,7 @@ namespace uniset
* *
*/ */
class UniSetActivator: class UniSetActivator:
public EventLoopServer,
public UniSetManager public UniSetManager
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
, public uniset::UHttp::IHttpRequestRegistry , public uniset::UHttp::IHttpRequestRegistry
...@@ -67,24 +70,16 @@ namespace uniset ...@@ -67,24 +70,16 @@ namespace uniset
static UniSetActivatorPtr Instance(); static UniSetActivatorPtr Instance();
std::shared_ptr<UniSetActivator> get_aptr();
// ------------------------------------
virtual ~UniSetActivator(); virtual ~UniSetActivator();
virtual void run(bool thread); void run( bool async );
virtual void stop(); void stop();
virtual void uaDestroy(int signo = 0);
virtual uniset::ObjectType getType() override virtual uniset::ObjectType getType() override
{ {
return uniset::ObjectType("UniSetActivator"); return uniset::ObjectType("UniSetActivator");
} }
typedef sigc::signal<void, int> TerminateEvent_Signal;
TerminateEvent_Signal signal_terminate_event();
bool noUseGdbForStackTrace() const;
const std::string getAbortScript() const;
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
// Поддрежка REST API (IHttpRequestRegistry) // Поддрежка REST API (IHttpRequestRegistry)
...@@ -98,38 +93,25 @@ namespace uniset ...@@ -98,38 +93,25 @@ namespace uniset
virtual void work(); virtual void work();
CORBA::ORB_ptr getORB();
virtual void sysCommand( const uniset::SystemMessage* sm ) override;
// уносим в protected, т.к. Activator должен быть только один.. // уносим в protected, т.к. Activator должен быть только один..
UniSetActivator(); UniSetActivator();
static std::shared_ptr<UniSetActivator> inst; static std::shared_ptr<UniSetActivator> inst;
private: private:
friend void uniset::terminate_thread();
friend void uniset::finished_thread();
friend std::shared_ptr<uniset::Configuration> uniset::uniset_init( int argc, const char* const* argv, const std::string& xmlfile );
static void terminated(int signo);
static void normalexit();
static void normalterminate();
static void set_signals(bool ask);
void term( int signo );
void init(); void init();
static void evsignal( ev::sig& signal, int signo );
virtual void evprepare() override;
virtual void evfinish() override;
std::shared_ptr< OmniThreadCreator<UniSetActivator> > orbthr; std::shared_ptr< OmniThreadCreator<UniSetActivator> > orbthr;
CORBA::ORB_var orb; CORBA::ORB_var orb;
TerminateEvent_Signal s_term;
std::atomic_bool omDestroy;
pid_t thid = { 0 }; // id orb потока
bool _noUseGdbForStackTrace = { false };
std::string abortScript = { "" }; // скрипт вызываемый при прерывании программы (SIGSEGV,SIGABRT) ev::sig sigINT;
ev::sig sigTERM;
ev::sig sigABRT;
ev::sig sigQUIT;
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
std::shared_ptr<uniset::UHttp::UHttpServer> httpserv; std::shared_ptr<uniset::UHttp::UHttpServer> httpserv;
......
...@@ -78,23 +78,6 @@ namespace uniset ...@@ -78,23 +78,6 @@ namespace uniset
virtual bool add( const std::shared_ptr<UniSetObject>& obj ); virtual bool add( const std::shared_ptr<UniSetObject>& obj );
virtual bool remove( const std::shared_ptr<UniSetObject>& obj ); virtual bool remove( const std::shared_ptr<UniSetObject>& obj );
// -------------------------- // --------------------------
/*! Получение доступа к подчиненному менеджеру по идентификатору
* \return shared_ptr<>, если объект не найден будет возвращен shared_ptr<> = nullptr
*/
const std::shared_ptr<UniSetManager> itemM(const uniset::ObjectId id);
/*! Получение доступа к подчиненному объекту по идентификатору
* \return shared_ptr<>, если объект не найден будет возвращен shared_ptr<> = nullptr
*/
const std::shared_ptr<UniSetObject> itemO( const uniset::ObjectId id );
// Функции для работы со списками подчиненных объектов
// ---------------
UniSetManagerList::const_iterator beginMList();
UniSetManagerList::const_iterator endMList();
ObjectsList::const_iterator beginOList();
ObjectsList::const_iterator endOList();
size_t objectsCount() const; // количество подчиненных объектов size_t objectsCount() const; // количество подчиненных объектов
// --------------- // ---------------
...@@ -127,14 +110,14 @@ namespace uniset ...@@ -127,14 +110,14 @@ namespace uniset
//! \note Переопределяя не забывайте вызвать базовую //! \note Переопределяя не забывайте вызвать базовую
virtual bool deactivateObject() override; virtual bool deactivateObject() override;
const std::shared_ptr<UniSetObject> findObject( const std::string& name ); const std::shared_ptr<UniSetObject> findObject( const std::string& name ) const;
const std::shared_ptr<UniSetManager> findManager( const std::string& name ); const std::shared_ptr<UniSetManager> findManager( const std::string& name ) const;
// рекурсивный поиск по всем объекам // рекурсивный поиск по всем объекам
const std::shared_ptr<UniSetObject> deepFindObject( const std::string& name ); const std::shared_ptr<UniSetObject> deepFindObject( const std::string& name ) const;
// рекурсивное наполнение списка объектов // рекурсивное наполнение списка объектов
void getAllObjectsList( std::vector<std::shared_ptr<UniSetObject>>& vec, size_t lim = 1000 ); void getAllObjectsList(std::vector<std::shared_ptr<UniSetObject> >& vec, size_t lim = 1000 );
typedef UniSetManagerList::iterator MListIterator; typedef UniSetManagerList::iterator MListIterator;
...@@ -144,14 +127,21 @@ namespace uniset ...@@ -144,14 +127,21 @@ namespace uniset
PortableServer::POA_var poa; PortableServer::POA_var poa;
PortableServer::POAManager_var pman; PortableServer::POAManager_var pman;
// Функции для работы со списками подчиненных объектов
// ---------------
UniSetManagerList::const_iterator beginMList();
UniSetManagerList::const_iterator endMList();
ObjectsList::const_iterator beginOList();
ObjectsList::const_iterator endOList();
private: private:
int sig; int sig;
UniSetManagerList mlist; UniSetManagerList mlist;
ObjectsList olist; ObjectsList olist;
uniset::uniset_rwmutex olistMutex; mutable uniset::uniset_rwmutex olistMutex;
uniset::uniset_rwmutex mlistMutex; mutable uniset::uniset_rwmutex mlistMutex;
}; };
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
} // end of uniset namespace } // end of uniset namespace
......
...@@ -1452,8 +1452,8 @@ namespace uniset ...@@ -1452,8 +1452,8 @@ namespace uniset
return uniset::uconf; return uniset::uconf;
} }
atexit( UniSetActivator::normalexit ); // atexit( UniSetActivator::normalexit );
set_terminate( UniSetActivator::normalterminate ); // ловушка для неизвестных исключений // set_terminate( UniSetActivator::normalterminate ); // ловушка для неизвестных исключений
string confile = uniset::getArgParam( "--confile", argc, argv, xmlfile ); string confile = uniset::getArgParam( "--confile", argc, argv, xmlfile );
uniset::uconf = make_shared<Configuration>(argc, argv, confile); uniset::uconf = make_shared<Configuration>(argc, argv, confile);
......
...@@ -50,503 +50,24 @@ ...@@ -50,503 +50,24 @@
using namespace uniset; using namespace uniset;
using namespace std; using namespace std;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
/*
Завершение работы организовано следующим образом:
-------------------------------------------------
Т.к. UniSetActivator в системе только один (singleton), он заказывает на себя
все сигналы связанные с завершением работы, а также устанавливает обработчики на штатный выход из программы (atexit)
и обработчик на выход по исключению (set_terminate).
В качестве обработчика сигналов регистрируется функция activator_terminate( int signo ).
При вызове run() (в функции work) создаётся "глобальный" поток g_term_thread, который
засыпает до события на condition переменной g_termevent.
Когда срабатывает обработчик сигнала, он выставляет флаг завершения (g_term=true) и вызывает
g_termevent.notify_one(); чтобы процесс завершения начал свою работу. (см. activator_terminate).
После этого начинается процесс завершения.
- orb shutdown
- uaDestroy()
- завершение CORBA-потока (если был создан) (функция work).
- orb destroy
Для защиты от "зависания" во время завершения, создаётся ещё один поток g_kill_thread, который ожидает завершения
в течение KILL_TIMEOUT и формирует сигнал SIGKILL если в течение этого времени не выставился флаг g_done = true;
Помимио этого в процессе завершения создаётся временный поток g_fini_thread,
который в течение TERMINATE_TIMEOUT секунд ждёт события 'g_finievent' (от процесса остановки котока для ORB).
После чего происходит "принудительное" отключение, обработчики сигналов восстанавливаются на умолчательные и процесс
завершается..
В случае, если для UniSetActivator был создан отдельный поток ( run(true) ) при завершении работы программы
срабатывает обработчик UniSetActivator::normalexit или UniSetActivator::normalterminate, которые
делают тоже самое. Будят процесс завершения.. и дожидаются завершения его работы.
// Обработка SIGSEGV
Для обработки SIGSEGV выделен отдельный обработчик (activator_terminate_with_calltrace),
который выводит stack trace и завершает работу.
Если для ulog включён SYSTEM, то trace выводится в него для возможности (если получиться)
увидеть его удалённо через logserver (если он запушен).
Если не включён, то выводиться в cerr.
Сам обработчик только выводит trace и завершает работу, восстановив обработчик SIGSEGV по умолчанию,
без какой-либо специальной обработки завершения.
Помимо этого, вывод stack trace сделан и для сигнала SIGABRT
*/
// ------------------------------------------------------------------------------------------
static std::shared_ptr<UniSetActivator> g_act;
static std::atomic_bool g_finished = ATOMIC_VAR_INIT(0);
static std::atomic_bool g_term = ATOMIC_VAR_INIT(0);
static std::atomic_bool g_done = ATOMIC_VAR_INIT(0);
static std::atomic_bool g_work_stopped = ATOMIC_VAR_INIT(0);
static std::atomic_int g_signo = ATOMIC_VAR_INIT(0);
static std::atomic_bool g_trace_done = ATOMIC_VAR_INIT(0);
static std::mutex g_workmutex;
static std::mutex g_termmutex;
static std::condition_variable g_termevent;
static std::mutex g_finimutex;
static std::condition_variable g_finievent;
static std::mutex g_donemutex;
static std::condition_variable g_doneevent;
static std::mutex g_trace_donemutex;
static std::condition_variable g_trace_doneevent;
static std::shared_ptr<std::thread> g_term_thread;
static std::shared_ptr<std::thread> g_fini_thread;
static std::shared_ptr<std::thread> g_kill_thread;
static const int TERMINATE_TIMEOUT_SEC = 3; // время отведенное на завершение процесса [сек]
static const int THREAD_TERMINATE_PAUSE = 50; // [мсек] пауза при завершении потока (см. work())
static const int KILL_TIMEOUT_SEC = 8;
static pid_t g_stacktrace_proc_pid = 0; // pid процесса делающего stack trace (для защиты от зависания)
// ------------------------------------------------------------------------------------------
// Чтобы не выделять память во время "вылета",
// выделим необходимое для stacktrace зараннее
// ----------
#define FUNCNAMESIZE 256
#define MAXFRAMES 64
// выделение специального стека заранее
// +60 - это на всякие переменные при обработке stack trace и т.п.
static char g_stack_body[(MAXFRAMES + 60)*FUNCNAMESIZE];
//static char trace_buf[10000];
static stack_t g_sigseg_stack;
static void on_stacktrace_timeout(); // поток для защиты от зависания "процесса создания stack trace"
// ------------------------------------------------------------------------------------------
// код функции printStackTrace взят с https://oroboro.com/stack-trace-on-crash/
// будет работать только под LINUX (т.к. используется backtrace)
// Как альтернативу, можно применить libunwind
// ------------------------------------------------------------------------------------------
// Выводим используя ulog() чтобы можно было удалённо увидеть через LogServer
// (хотя конечно это как повезёт и зависит от того где собственно произошла ошибка)
// ------------------------------------------------------------------------------------------
#define TRACELOG ( to_cerr ? cerr : log->system(false) )
static inline void printStackTrace()
{
auto log = ulog();
// если логи отключены, то и выводить не будем
bool to_cerr = ( !log || !log->is_system() );
// первый лог выводим с датой, а дальше уже просто
( to_cerr ? cerr : log->system() ) << "stack trace:\n";
TRACELOG << "-----------------------------------------" << endl;
void* addrlist[MAXFRAMES];
// retrieve current stack addresses
unsigned int addrlen = backtrace(addrlist, MAXFRAMES);
if ( addrlen == 0 )
{
log->system() << "...empty stack..\n";
return;
}
// resolve addresses into strings containing "filename(function+address)",
// Actually it will be ## program address function + offset
// this array must be free()-ed
char** symbollist = backtrace_symbols( addrlist, addrlen );
TRACELOG << std::left;
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for ( unsigned int i = 4; i < addrlen; i++ )
{
Dl_info dl;
if(!dladdr(addrlist[i], &dl))
break;
const char* sym = dl.dli_sname;
int status = 0;
char* ret = abi::__cxa_demangle( sym, NULL, 0, &status );
if( status == 0 && ret )
sym = ret;
if( dl.dli_fname && sym )
{
TRACELOG << setw(30) << symbollist[i]
<< " ( " << setw(40) << dl.dli_fname
<< " ): " << sym
<< endl << flush;
}
else
{
TRACELOG << setw(30) << symbollist[i] << endl << flush;
}
if( ret )
std::free(ret);
}
std::free(symbollist);
TRACELOG << "-----------------------------------------" << endl << flush;
}
// ------------------------------------------------------------------------------------------
// за основу взят код функции отсюда https://habrahabr.ru/company/ispsystem/blog/144198/
bool gdb_print_trace()
{
auto log = ulog();
// если логи отключены, то и выводить будем в cerr
bool to_cerr = ( !log || !log->is_system() );
char pid_buf[30];
sprintf(pid_buf, "%d", getpid());
char name_buf[512];
ssize_t ind = readlink("/proc/self/exe", name_buf, 511);
if( ind < 0 )
{
perror("Can't readlink...");
return false;
}
name_buf[ind] = 0;
TRACELOG << "stack trace: for " << name_buf << " pid=" << pid_buf << endl;
int child_pid = fork();
if( child_pid == -1 )
{
perror("Can't fork...");
return false;
}
if( child_pid == 0 ) // CHILD
{
msleep(300); // пауза чтобы родитель успел подготовиться..
dup2(2, 1); // redirect output to stderr
if( g_act && !g_act->getAbortScript().empty() )
{
TRACELOG << "run script: " << g_act->getAbortScript() << " for stack trace: proc " << name_buf << " pid=" << pid_buf << endl;
execlp(g_act->getAbortScript().c_str(), g_act->getAbortScript().c_str(), name_buf, pid_buf, NULL);
}
else
{
TRACELOG << "direct run gdb for stack trace for pid=" << pid_buf << " name=" << name_buf << " ..." << endl;
// приходится выводить информацию по всем потокам, т.к. мы не знаем в каком сработал сигнал
// его надо смотреть по выводу "<signal handler called>"
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread apply all bt", name_buf, pid_buf, NULL);
}
// abort(); /* If gdb failed to start */
return false;
}
else // PARENT
{
if( g_act && !g_act->getAbortScript().empty() )
{
TRACELOG << "stack trace: run script " << g_act->getAbortScript() << endl;
}
g_stacktrace_proc_pid = child_pid;
g_trace_done = false;
std::thread t(on_stacktrace_timeout); // запускаем поток "защищающий" от зависания процесса создания stack trace
waitpid(child_pid, NULL, 0);
g_trace_done = true;
g_trace_doneevent.notify_all();
t.join();
}
TRACELOG << "-----------------------------------------" << endl << flush;
return true;
}
// ------------------------------------------------------------------------------------------
static void on_stacktrace_timeout()
{
ulogsys << "****** STACK TRACE guard thread start (for pid=" << g_stacktrace_proc_pid << ") ******" << endl << flush;
std::unique_lock<std::mutex> lk(g_trace_donemutex);
g_trace_doneevent.wait_for(lk, std::chrono::milliseconds(KILL_TIMEOUT_SEC * 1000), []()
{
return (g_trace_done == true);
} );
if( !g_trace_done )
{
ulogsys << "****** STACK TRACE TIMEOUT.. (kill process) *******" << endl << flush;
kill(g_stacktrace_proc_pid, SIGKILL);
}
else
ulogsys << "****** STACK TRACE guard thread finish ******" << endl << flush;
}
// ------------------------------------------------------------------------------------------
static void start_terminate_process()
{
// посылаем сигнал потоку завершения, чтобы проснулся и начал заверешение
{
std::unique_lock<std::mutex> lk(g_termmutex);
if( g_term )
return;
g_term = true;
}
g_termevent.notify_all();
}
// ------------------------------------------------------------------------------------------
static void wait_done()
{
std::unique_lock<std::mutex> lk(g_donemutex);
while( !g_done )
g_doneevent.wait(lk, []()
{
return (g_done == true);
} );
}
// ------------------------------------------------------------------------------------------
static void activator_terminate( int signo )
{
if( g_term )
return;
g_signo = signo;
if( signo == SIGABRT )
{
if( g_act && !g_act->noUseGdbForStackTrace() )
{
if( !gdb_print_trace() )
printStackTrace(); // пробуем сами..
}
else
printStackTrace();
// exit(EXIT_FAILURE);
// return;
}
// else
// exit(EXIT_SUCCESS);
start_terminate_process();
}
// ------------------------------------------------------------------------------------------
static void activator_terminate_with_calltrace( int signo )
{
if( g_act && !g_act->noUseGdbForStackTrace() )
{
if( !gdb_print_trace() )
printStackTrace(); // пробуем сами..
}
else
printStackTrace();
// т.к. это SIGSEGV, то просто вылетаем по умолчанию..
signal(signo, SIG_DFL);
raise(signo);
}
// ------------------------------------------------------------------------------------------
void finished_thread()
{
ulogsys << "****** WAIT FINISH START **** " << endl << flush;
std::unique_lock<std::mutex> lk(g_finimutex);
if( g_finished )
return;
g_finished = true;
std::unique_lock<std::mutex> lkw(g_workmutex);
g_finievent.wait_for(lkw, std::chrono::milliseconds(TERMINATE_TIMEOUT_SEC * 1000), []()
{
return (g_work_stopped == true);
} );
ulogsys << "****** WAIT FINISH END(" << g_work_stopped << ") ****" << endl << flush;
}
// ------------------------------------------------------------------------------------------
void on_finish_timeout()
{
std::unique_lock<std::mutex> lk(g_donemutex);
if( g_done )
return;
g_doneevent.wait_for(lk, std::chrono::milliseconds(KILL_TIMEOUT_SEC * 1000), []()
{
return (g_done == true);
} );
if( !g_done )
{
ulogsys << "(KILL THREAD): WAIT TIMEOUT..KILL *******" << endl << flush;
raise(SIGKILL);
}
ulogsys << "(KILL THREAD): ..bye.." << endl;
}
// ------------------------------------------------------------------------------------------
namespace uniset namespace uniset
{ {
void terminate_thread()
{
ulogsys << "****** TERMINATE THREAD: STARTED *******" << endl << flush;
{
std::unique_lock<std::mutex> locker(g_termmutex);
g_term = false;
while( !g_term )
g_termevent.wait(locker);
// g_termmutex надо отпустить, т.к. он будет проверяться в ~UniSetActvator
}
ulogsys << "****** TERMINATE THREAD: event signo=" << g_signo << endl << flush;
{
std::unique_lock<std::mutex> locker(g_finimutex);
if( g_finished )
return;
}
{
std::unique_lock<std::mutex> lk(g_donemutex);
g_done = false;
g_kill_thread = make_shared<std::thread>(on_finish_timeout);
}
if( g_act )
{
{
std::unique_lock<std::mutex> lk(g_finimutex);
if( g_finished )
{
ulogsys << "...FINISHED ALREADY STARTED..." << endl << flush;
return;
}
g_fini_thread = make_shared<std::thread>(finished_thread);
}
ulogsys << "(TERMINATE THREAD): call terminated.." << endl << flush;
g_act->terminated(g_signo);
#if 0
try
{
ulogsys << "TERMINATE THREAD: orb shutdown.." << endl;
if( g_act->orb )
g_act->orb->shutdown(true);
ulogsys << "TERMINATE THREAD: orb shutdown ok.." << endl;
}
catch( const omniORB::fatalException& fe )
{
ulogsys << "(TERMINATE THREAD): : omniORB::fatalException:" << endl;
ulogsys << "(TERMINATE THREAD): file: " << fe.file() << endl;
ulogsys << "(TERMINATE THREAD): line: " << fe.line() << endl;
ulogsys << "(TERMINATE THREAD): mesg: " << fe.errmsg() << endl;
}
catch( const std::exception& ex )
{
ulogsys << "(TERMINATE THREAD): " << ex.what() << endl;
}
#endif
if( g_fini_thread && g_fini_thread->joinable() )
g_fini_thread->join();
ulogsys << "(TERMINATE THREAD): FINISHED OK.." << endl << flush;
if( g_act && g_act->orb )
{
try
{
ulogsys << "(TERMINATE THREAD): destroy.." << endl;
g_act->orb->destroy();
ulogsys << "(TERMINATE THREAD): destroy ok.." << endl;
}
catch( const omniORB::fatalException& fe )
{
ulogsys << "(TERMINATE THREAD): : omniORB::fatalException:" << endl;
ulogsys << "(TERMINATE THREAD): file: " << fe.file() << endl;
ulogsys << "(TERMINATE THREAD): line: " << fe.line() << endl;
ulogsys << "(TERMINATE THREAD): mesg: " << fe.errmsg() << endl;
}
catch( const std::exception& ex )
{
ulogsys << "(TERMINATE THREAD): " << ex.what() << endl;
}
}
// g_act = nullptr;
UniSetActivator::set_signals(false);
}
{
std::unique_lock<std::mutex> lk(g_donemutex);
g_done = true;
}
g_doneevent.notify_all();
g_kill_thread->join();
ulogsys << "(TERMINATE THREAD): ..bye.." << endl;
}
}
// ---------------------------------------------------------------------------
UniSetActivatorPtr UniSetActivator::inst; UniSetActivatorPtr UniSetActivator::inst;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
UniSetActivatorPtr UniSetActivator::Instance() UniSetActivatorPtr UniSetActivator::Instance()
{ {
if( inst == nullptr ) if( inst == nullptr )
{
inst = shared_ptr<UniSetActivator>( new UniSetActivator() ); inst = shared_ptr<UniSetActivator>( new UniSetActivator() );
g_act = inst;
}
return inst; return inst;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
std::shared_ptr<UniSetActivator> UniSetActivator::get_aptr()
{
return std::dynamic_pointer_cast<UniSetActivator>(get_ptr());
}
// ---------------------------------------------------------------------------
UniSetActivator::UniSetActivator(): UniSetActivator::UniSetActivator():
UniSetManager(uniset::DefaultObjectId), UniSetManager(uniset::DefaultObjectId)
omDestroy(false)
{ {
// thread(false); // отключаем поток (раз не задан id)
UniSetActivator::init(); UniSetActivator::init();
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
void UniSetActivator::init() void UniSetActivator::init()
{ {
...@@ -555,10 +76,6 @@ void UniSetActivator::init() ...@@ -555,10 +76,6 @@ void UniSetActivator::init()
auto conf = uniset_conf(); auto conf = uniset_conf();
_noUseGdbForStackTrace = ( findArgParam("--uniset-no-use-gdb-for-stacktrace", conf->getArgc(), conf->getArgv()) != -1 );
abortScript = conf->getArgParam("--uniset-abort-script", "");
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
if( findArgParam("--activator-run-httpserver", conf->getArgc(), conf->getArgv()) != -1 ) if( findArgParam("--activator-run-httpserver", conf->getArgc(), conf->getArgv()) != -1 )
...@@ -580,76 +97,27 @@ void UniSetActivator::init() ...@@ -580,76 +97,27 @@ void UniSetActivator::init()
poa = root_poa->create_POA("my poa", pman, pl); poa = root_poa->create_POA("my poa", pman, pl);
if( CORBA::is_nil(poa) ) if( CORBA::is_nil(poa) )
{
ucrit << myname << "(init): init poa failed!!!" << endl; ucrit << myname << "(init): init poa failed!!!" << endl;
std::terminate();
}
// Чтобы подключиться к функциям завершения как можно раньше (раньше создания объектов) sigTERM.set(loop);
// этот код перенесён в Configuration::uniset_init (в надежде, что uniset_init всегда вызывается одной из первых). sigINT.set(loop);
// atexit( UniSetActivator::normalexit ); sigABRT.set(loop);
// set_terminate( UniSetActivator::normalterminate ); // ловушка для неизвестных исключений sigQUIT.set(loop);
sigINT.set<&UniSetActivator::evsignal>();
sigTERM.set<&UniSetActivator::evsignal>();
sigABRT.set<&UniSetActivator::evsignal>();
sigQUIT.set<&UniSetActivator::evsignal>();
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
UniSetActivator::~UniSetActivator() UniSetActivator::~UniSetActivator()
{ {
} if( active )
// ------------------------------------------------------------------------------------------
void UniSetActivator::uaDestroy( int signo )
{
if( omDestroy || !g_act )
return;
omDestroy = true;
ulogsys << myname << "(uaDestroy): begin..." << endl;
ulogsys << myname << "(uaDestroy): terminate... " << endl;
term(signo);
ulogsys << myname << "(uaDestroy): terminate ok. " << endl;
try
{
stop(); stop();
}
catch( const omniORB::fatalException& fe )
{
ucrit << myname << "(uaDestroy): : поймали omniORB::fatalException:" << endl;
ucrit << myname << "(uaDestroy): file: " << fe.file() << endl;
ucrit << myname << "(uaDestroy): line: " << fe.line() << endl;
ucrit << myname << "(uaDestroy): mesg: " << fe.errmsg() << endl;
}
catch(...)
{
ulogsys << myname << "(uaDestroy): orb shutdown: catch... " << endl;
}
ulogsys << myname << "(uaDestroy): pman deactivate... " << endl;
pman->deactivate(false, true);
ulogsys << myname << "(uaDestroy): pman deactivate ok. " << endl;
try
{
ulogsys << myname << "(uaDestroy): shutdown orb... " << endl;
if( orb )
orb->shutdown(true);
ulogsys << myname << "(uaDestroy): shutdown ok." << endl;
}
catch( const omniORB::fatalException& fe )
{
ucrit << myname << "(uaDestroy): : поймали omniORB::fatalException:" << endl;
ucrit << myname << "(uaDestroy): file: " << fe.file() << endl;
ucrit << myname << "(uaDestroy): line: " << fe.line() << endl;
ucrit << myname << "(uaDestroy): mesg: " << fe.errmsg() << endl;
}
catch( const std::exception& ex )
{
ucrit << myname << "(uaDestroy): " << ex.what() << endl;
}
ulogsys << myname << "(uaDestroy): begin..." << endl;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
/*! /*!
* Если thread=true то функция создает отдельный поток для обработки приходящих сообщений. * Если thread=true то функция создает отдельный поток для обработки приходящих сообщений.
...@@ -663,7 +131,9 @@ void UniSetActivator::run( bool thread ) ...@@ -663,7 +131,9 @@ void UniSetActivator::run( bool thread )
{ {
ulogsys << myname << "(run): создаю менеджер " << endl; ulogsys << myname << "(run): создаю менеджер " << endl;
UniSetManager::initPOA( get_aptr() ); auto aptr = std::static_pointer_cast<UniSetActivator>(get_ptr());
UniSetManager::initPOA(aptr);
if( getId() == uniset::DefaultObjectId ) if( getId() == uniset::DefaultObjectId )
offThread(); // отключение потока обработки сообщений, раз не задан ObjectId offThread(); // отключение потока обработки сообщений, раз не задан ObjectId
...@@ -675,7 +145,8 @@ void UniSetActivator::run( bool thread ) ...@@ -675,7 +145,8 @@ void UniSetActivator::run( bool thread )
pman->activate(); pman->activate();
msleep(50); msleep(50);
set_signals(true); if( !thread )
async_evrun();
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
...@@ -698,13 +169,14 @@ void UniSetActivator::run( bool thread ) ...@@ -698,13 +169,14 @@ void UniSetActivator::run( bool thread )
if( thread ) if( thread )
{ {
uinfo << myname << "(run): запускаемся с созданием отдельного потока... " << endl; uinfo << myname << "(run): запускаемся с созданием отдельного потока... " << endl;
orbthr = make_shared< OmniThreadCreator<UniSetActivator> >( get_aptr(), &UniSetActivator::work); orbthr = make_shared< OmniThreadCreator<UniSetActivator> >( aptr, &UniSetActivator::work);
orbthr->start(); orbthr->start();
} }
else else
{ {
uinfo << myname << "(run): запускаемся без создания отдельного потока... " << endl; uinfo << myname << "(run): запускаемся без создания отдельного потока... " << endl;
work(); work();
evstop();
} }
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
...@@ -736,22 +208,65 @@ void UniSetActivator::stop() ...@@ -736,22 +208,65 @@ void UniSetActivator::stop()
httpserv->stop(); httpserv->stop();
#endif #endif
ulogsys << myname << "(stop): pman deactivate... " << endl;
pman->deactivate(false, true);
ulogsys << myname << "(stop): pman deactivate ok. " << endl;
try
{
ulogsys << myname << "(stop): shutdown orb... " << endl;
if( orb )
orb->shutdown(true);
ulogsys << myname << "(stop): shutdown ok." << endl;
}
catch( const omniORB::fatalException& fe )
{
ucrit << myname << "(stop): : поймали omniORB::fatalException:" << endl;
ucrit << myname << "(stop): file: " << fe.file() << endl;
ucrit << myname << "(stop): line: " << fe.line() << endl;
ucrit << myname << "(stop): mesg: " << fe.errmsg() << endl;
}
catch( const std::exception& ex )
{
ucrit << myname << "(stop): " << ex.what() << endl;
}
if( orbthr )
orbthr->join();
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
void UniSetActivator::evsignal( ev::sig& signal, int signo )
{
auto act = UniSetActivator::Instance();
act->stop();
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::evprepare()
{
sigINT.start(SIGINT);
sigTERM.start(SIGTERM);
sigABRT.start(SIGABRT);
sigQUIT.start(SIGQUIT);
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::evfinish()
{
sigINT.stop();
sigTERM.stop();
sigABRT.stop();
sigQUIT.stop();
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::work() void UniSetActivator::work()
{ {
ulogsys << myname << "(work): запускаем orb на обработку запросов..." << endl; ulogsys << myname << "(work): запускаем orb на обработку запросов..." << endl;
try try
{ {
if( orbthr )
thid = orbthr->getTID();
else
thid = getpid();
g_term_thread = make_shared<std::thread>(terminate_thread);
omniORB::setMainThread(); omniORB::setMainThread();
orb->run(); orb->run();
} }
...@@ -776,123 +291,6 @@ void UniSetActivator::work() ...@@ -776,123 +291,6 @@ void UniSetActivator::work()
} }
ulogsys << myname << "(work): orb thread stopped!" << endl << flush; ulogsys << myname << "(work): orb thread stopped!" << endl << flush;
{
std::unique_lock<std::mutex> lkw(g_workmutex);
g_work_stopped = true;
}
g_finievent.notify_one();
if( orbthr )
{
// почему-то без этой паузы при завершении возникает "double free or corruption"
// и вообще какой-то race между завершением штатным и нашим
// видимо потому-что обычно activator запускается в main()
// и как только этот поток прерывается идёт завершение работы
// а мы и так уже завершаемся.. и получается какой-то race..
msleep(THREAD_TERMINATE_PAUSE);
wait_done();
}
}
// ------------------------------------------------------------------------------------------
CORBA::ORB_ptr UniSetActivator::getORB()
{
return orb;
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::sysCommand( const uniset::SystemMessage* sm )
{
switch(sm->command)
{
case SystemMessage::LogRotate:
{
ulogsys << myname << "(sysCommand): logRotate" << endl;
auto ul = ulog();
if( !ul )
break;
// переоткрываем логи
string fname = ul->getLogFile();
if( fname.empty() )
{
ul->logFile(fname.c_str(), true);
ulogany << myname << "(sysCommand): ***************** ulog LOG ROTATE *****************" << endl;
}
}
break;
}
}
// -------------------------------------------------------------------------
void UniSetActivator::set_signals(bool ask)
{
struct sigaction act; // = { { 0 } };
struct sigaction oact; // = { { 0 } };
memset(&act, 0, sizeof(act));
memset(&act, 0, sizeof(oact));
sigemptyset(&act.sa_mask);
sigemptyset(&oact.sa_mask);
// добавляем сигналы, которые будут игнорироваться
// при обработке сигнала
sigaddset(&act.sa_mask, SIGINT);
sigaddset(&act.sa_mask, SIGTERM);
sigaddset(&act.sa_mask, SIGABRT );
sigaddset(&act.sa_mask, SIGQUIT);
// sigaddset(&act.sa_mask, SIGALRM);
// act.sa_flags = 0;
// act.sa_flags |= SA_RESTART;
// act.sa_flags |= SA_RESETHAND;
if(ask)
act.sa_handler = activator_terminate; // terminated;
else
act.sa_handler = SIG_DFL;
sigaction(SIGINT, &act, &oact);
sigaction(SIGTERM, &act, &oact);
sigaction(SIGABRT, &act, &oact);
sigaction(SIGQUIT, &act, &oact);
// SIGSEGV отдельно
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGSEGV);
act.sa_flags = 0;
// act.sa_flags |= SA_RESTART;
act.sa_flags |= SA_RESETHAND;
#if 1
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;
#endif
if(ask)
act.sa_handler = activator_terminate_with_calltrace;
else
act.sa_handler = SIG_DFL;
sigaction(SIGSEGV, &act, &oact);
}
// ------------------------------------------------------------------------------------------
UniSetActivator::TerminateEvent_Signal UniSetActivator::signal_terminate_event()
{
return s_term;
}
// ------------------------------------------------------------------------------------------
bool UniSetActivator::noUseGdbForStackTrace() const
{
return _noUseGdbForStackTrace;
}
// ------------------------------------------------------------------------------------------
const string UniSetActivator::getAbortScript() const
{
return abortScript;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
#ifndef DISABLE_REST_API #ifndef DISABLE_REST_API
...@@ -966,96 +364,5 @@ Poco::JSON::Object::Ptr UniSetActivator::httpRequestByName( const string& name, ...@@ -966,96 +364,5 @@ Poco::JSON::Object::Ptr UniSetActivator::httpRequestByName( const string& name,
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
#endif // #ifndef DISABLE_REST_API #endif // #ifndef DISABLE_REST_API
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
void UniSetActivator::terminated( int signo ) } // end of namespace uniset
{
if( !g_act )
return;
ulogsys << "(terminated): start.." << endl;
try
{
g_act->uaDestroy(signo);
ulogsys << "(terminated): uaDestroy ok.." << endl;
}
catch( const omniORB::fatalException& fe )
{
ulogsys << "(terminated): : поймали omniORB::fatalException:" << endl;
ulogsys << "(terminated): file: " << fe.file() << endl;
ulogsys << "(terminated): line: " << fe.line() << endl;
ulogsys << "(terminated): mesg: " << fe.errmsg() << endl;
}
catch( const std::exception& ex )
{
ulogsys << "(terminated): " << ex.what() << endl;
}
g_term = true;
ulogsys << "terminated ok.." << endl;
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::normalexit()
{
if( !g_act )
return;
ulogsys << g_act->getName() << "(exit): ..begin..." << endl << flush;
start_terminate_process();
ulogsys << "(exit): wait done.." << endl << flush;
#if 1
if( g_term_thread && g_term_thread->joinable() )
g_term_thread->join();
#else
if( g_doneevent )
{
std::unique_lock<std::mutex> locker(g_donemutex);
while( !g_done )
g_doneevent.wait(locker);
}
#endif
ulogsys << "(exit): wait done OK (good bye)" << endl << flush;
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::normalterminate()
{
if( !g_act )
return;
ulogsys << g_act->getName() << "(default terminate): ..begin..." << endl << flush;
normalexit();
}
// ------------------------------------------------------------------------------------------
void UniSetActivator::term( int signo )
{
ulogsys << myname << "(term): TERM" << endl;
{
std::unique_lock<std::mutex> locker(g_termmutex);
if( g_term )
return;
}
try
{
ulogsys << myname << "(term): вызываем sigterm()" << endl;
sigterm(signo);
s_term.emit(signo);
ulogsys << myname << "(term): sigterm() ok." << endl;
}
catch( const uniset::Exception& ex )
{
ucrit << myname << "(term): " << ex << endl;
}
catch(...) {}
ulogsys << myname << "(term): END TERM" << endl;
}
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
...@@ -465,7 +465,7 @@ bool UniSetManager::deactivateObject() ...@@ -465,7 +465,7 @@ bool UniSetManager::deactivateObject()
return true; return true;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
const std::shared_ptr<UniSetObject> UniSetManager::findObject( const string& name ) const std::shared_ptr<UniSetObject> UniSetManager::findObject( const string& name ) const
{ {
uniset_rwmutex_rlock lock(olistMutex); uniset_rwmutex_rlock lock(olistMutex);
...@@ -478,7 +478,7 @@ const std::shared_ptr<UniSetObject> UniSetManager::findObject( const string& nam ...@@ -478,7 +478,7 @@ const std::shared_ptr<UniSetObject> UniSetManager::findObject( const string& nam
return nullptr; return nullptr;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
const std::shared_ptr<UniSetManager> UniSetManager::findManager( const string& name ) const std::shared_ptr<UniSetManager> UniSetManager::findManager( const string& name ) const
{ {
uniset_rwmutex_rlock lock(mlistMutex); uniset_rwmutex_rlock lock(mlistMutex);
...@@ -491,7 +491,7 @@ const std::shared_ptr<UniSetManager> UniSetManager::findManager( const string& n ...@@ -491,7 +491,7 @@ const std::shared_ptr<UniSetManager> UniSetManager::findManager( const string& n
return nullptr; return nullptr;
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
const std::shared_ptr<UniSetObject> UniSetManager::deepFindObject( const string& name ) const std::shared_ptr<UniSetObject> UniSetManager::deepFindObject( const string& name ) const
{ {
{ {
auto obj = findObject(name); auto obj = findObject(name);
...@@ -617,7 +617,7 @@ bool UniSetManager::removeManager( const std::shared_ptr<UniSetManager>& child ) ...@@ -617,7 +617,7 @@ bool UniSetManager::removeManager( const std::shared_ptr<UniSetManager>& child )
} }
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
#if 0
const std::shared_ptr<UniSetManager> UniSetManager::itemM( const ObjectId id ) const std::shared_ptr<UniSetManager> UniSetManager::itemM( const ObjectId id )
{ {
...@@ -652,7 +652,7 @@ const std::shared_ptr<UniSetObject> UniSetManager::itemO( const ObjectId id ) ...@@ -652,7 +652,7 @@ const std::shared_ptr<UniSetObject> UniSetManager::itemO( const ObjectId id )
return nullptr; // std::shared_ptr<UniSetObject>(); return nullptr; // std::shared_ptr<UniSetObject>();
} }
#endif
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
int UniSetManager::getObjectsInfo( const std::shared_ptr<UniSetManager>& mngr, SimpleInfoSeq* seq, int UniSetManager::getObjectsInfo( const std::shared_ptr<UniSetManager>& mngr, SimpleInfoSeq* seq,
......
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