enhancled the App class to support per-instance signal handler
This commit is contained in:
parent
f6c60f3c46
commit
bb7a03bbc5
@ -38,8 +38,8 @@ QSE_BEGIN_NAMESPACE(QSE)
|
|||||||
class App: public Uncopyable, public Types, public Mmged
|
class App: public Uncopyable, public Types, public Mmged
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false) {}
|
App (Mmgr* mmgr) QSE_CPP_NOEXCEPT;
|
||||||
~App () QSE_CPP_NOEXCEPT {}
|
virtual ~App () QSE_CPP_NOEXCEPT;
|
||||||
|
|
||||||
int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT;
|
int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT;
|
||||||
|
|
||||||
@ -51,14 +51,62 @@ public:
|
|||||||
int restoreUser () QSE_CPP_NOEXCEPT;
|
int restoreUser () QSE_CPP_NOEXCEPT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
virtual void on_signal (int sig) { }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _root_only;
|
bool _root_only;
|
||||||
|
|
||||||
|
private:
|
||||||
|
App* _prev_app;
|
||||||
|
App* _next_app;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct _SigLink
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UNHANDLED,
|
||||||
|
ACCEPTED,
|
||||||
|
IGNORED // handled but ignored
|
||||||
|
};
|
||||||
|
|
||||||
|
_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(UNHANDLED) {}
|
||||||
|
App* _prev;
|
||||||
|
App* _next;
|
||||||
|
int _state;
|
||||||
|
};
|
||||||
|
|
||||||
|
_SigLink _sig[QSE_NSIGS];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
typedef void (*SignalHandler) (int sig);
|
typedef void (*SignalHandler) (int sig);
|
||||||
static int setSignalHandler (int sig, SignalHandler sighr);
|
static int setSignalHandler (int sig, SignalHandler sighr);
|
||||||
static int unsetSignalHandler (int sig);
|
static int unsetSignalHandler (int sig);
|
||||||
static qse_size_t _sighrs[2][QSE_NSIGS];
|
static qse_size_t _sighrs[2][QSE_NSIGS];
|
||||||
|
|
||||||
|
void handleSignal (int sig, bool accept);
|
||||||
|
void unhandleSignal (int sig);
|
||||||
|
};
|
||||||
|
|
||||||
|
// functor as a template parameter
|
||||||
|
template <typename F>
|
||||||
|
class QSE_EXPORT AppF: public App
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AppF (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr) {}
|
||||||
|
AppF (const F& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr), __lfunc(f) {}
|
||||||
|
#if defined(QSE_CPP_ENABLE_CPP11_MOVE)
|
||||||
|
AppF (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr), __lfunc(QSE_CPP_RVREF(f)) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
F __lfunc;
|
||||||
|
|
||||||
|
void on_signal (int sig)
|
||||||
|
{
|
||||||
|
this->__lfunc(this, sig);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <qse/si/App.hpp>
|
#include <qse/si/App.hpp>
|
||||||
|
#include <qse/si/Mutex.hpp>
|
||||||
#include <qse/si/sinfo.h>
|
#include <qse/si/sinfo.h>
|
||||||
#include "../cmn/syscall.h"
|
#include "../cmn/syscall.h"
|
||||||
#include <qse/cmn/mbwc.h>
|
#include <qse/cmn/mbwc.h>
|
||||||
@ -33,6 +34,38 @@
|
|||||||
QSE_BEGIN_NAMESPACE(QSE)
|
QSE_BEGIN_NAMESPACE(QSE)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static Mutex g_app_mutex;
|
||||||
|
static App* g_app_top = QSE_NULL; // maintain the chain of application objects
|
||||||
|
static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, };
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
sigset_t sa_mask;
|
||||||
|
int sa_flags;
|
||||||
|
} g_app_oldsi[QSE_NSIGS] = { { 0, 0 }, };
|
||||||
|
|
||||||
|
App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false), _prev_app(QSE_NULL), _next_app(QSE_NULL)
|
||||||
|
{
|
||||||
|
ScopedMutexLocker sml(g_app_mutex);
|
||||||
|
if (!g_app_top)
|
||||||
|
{
|
||||||
|
g_app_top = this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_app_top->_prev_app = this;
|
||||||
|
this->_next_app = g_app_top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App::~App () QSE_CPP_NOEXCEPT
|
||||||
|
{
|
||||||
|
ScopedMutexLocker sml(g_app_mutex);
|
||||||
|
if (this->_next_app) this->_next_app->_prev_app = this->_prev_app;
|
||||||
|
if (this->_prev_app) this->_prev_app->_next_app = this->_next_app;
|
||||||
|
if (this == g_app_top) g_app_top = this->_next_app;
|
||||||
|
}
|
||||||
|
|
||||||
int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
|
int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
|
||||||
{
|
{
|
||||||
if (this->_root_only && QSE_GETEUID() != 0) return -1;
|
if (this->_root_only && QSE_GETEUID() != 0) return -1;
|
||||||
@ -102,7 +135,6 @@ int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int App::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT
|
int App::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT
|
||||||
{
|
{
|
||||||
return QSE_CHROOT (mpath);
|
return QSE_CHROOT (mpath);
|
||||||
@ -169,14 +201,6 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// i don't want to use sigset_t in App.hpp.
|
|
||||||
// so i place oldsi here as a static variable instead of
|
|
||||||
// static member variable of App
|
|
||||||
static struct
|
|
||||||
{
|
|
||||||
sigset_t sa_mask;
|
|
||||||
int sa_flags;
|
|
||||||
} oldsi[QSE_NSIGS] = { { 0, 0 }, };
|
|
||||||
|
|
||||||
int App::setSignalHandler (int sig, SignalHandler sighr)
|
int App::setSignalHandler (int sig, SignalHandler sighr)
|
||||||
{
|
{
|
||||||
@ -205,8 +229,8 @@ int App::setSignalHandler (int sig, SignalHandler sighr)
|
|||||||
|
|
||||||
App::_sighrs[0][sig] = (qse_size_t)sighr;
|
App::_sighrs[0][sig] = (qse_size_t)sighr;
|
||||||
App::_sighrs[1][sig] = (qse_size_t)oldsa.sa_handler;
|
App::_sighrs[1][sig] = (qse_size_t)oldsa.sa_handler;
|
||||||
oldsi[sig].sa_mask = oldsa.sa_mask;
|
g_app_oldsi[sig].sa_mask = oldsa.sa_mask;
|
||||||
oldsi[sig].sa_flags = oldsa.sa_flags;
|
g_app_oldsi[sig].sa_flags = oldsa.sa_flags;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -217,20 +241,97 @@ int App::unsetSignalHandler (int sig)
|
|||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sa.sa_mask = oldsi[sig].sa_mask;
|
sa.sa_mask = g_app_oldsi[sig].sa_mask;
|
||||||
sa.sa_flags = oldsi[sig].sa_flags;
|
sa.sa_flags = g_app_oldsi[sig].sa_flags;
|
||||||
if (sa.sa_flags & SA_SIGINFO)
|
if (sa.sa_flags & SA_SIGINFO)
|
||||||
sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))App::_sighrs[1][sig];
|
sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))App::_sighrs[1][sig];
|
||||||
else
|
else
|
||||||
sa.sa_handler = (SignalHandler)App::_sighrs[1][sig];
|
sa.sa_handler = (SignalHandler)App::_sighrs[1][sig];
|
||||||
|
|
||||||
if (sigaction (sig, &sa, QSE_NULL) <= -1) return -1;
|
if (::sigaction (sig, &sa, QSE_NULL) <= -1) return -1;
|
||||||
|
|
||||||
App::_sighrs[0][sig] = 0;
|
App::_sighrs[0][sig] = 0;
|
||||||
App::_sighrs[1][sig] = 0;
|
App::_sighrs[1][sig] = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_signal (int sig)
|
||||||
|
{
|
||||||
|
ScopedMutexLocker sml(g_app_mutex);
|
||||||
|
App* app = g_app_sig[sig];
|
||||||
|
while (app)
|
||||||
|
{
|
||||||
|
App::_SigLink& sl = app->_sig[sig];
|
||||||
|
App* next = sl._next;
|
||||||
|
if (sl._state == App::_SigLink::ACCEPTED) app->on_signal (sig);
|
||||||
|
app = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::handleSignal (int sig, bool accept)
|
||||||
|
{
|
||||||
|
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
|
||||||
|
|
||||||
|
int reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED;
|
||||||
|
ScopedMutexLocker sml(g_app_mutex);
|
||||||
|
|
||||||
|
_SigLink& sl = this->_sig[sig];
|
||||||
|
if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED))
|
||||||
|
{
|
||||||
|
if (!g_app_sig[sig])
|
||||||
|
{
|
||||||
|
// no application is set to accept this signal.
|
||||||
|
// this is the first time to
|
||||||
|
App::setSignalHandler (sig, handle_signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
sl._state = _SigLink::ACCEPTED;
|
||||||
|
sl._next = g_app_sig[sig];
|
||||||
|
g_app_sig[sig] = this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// already configured to receive the signal.
|
||||||
|
QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
|
||||||
|
sl._state = reqstate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::unhandleSignal (int sig)
|
||||||
|
{
|
||||||
|
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
|
||||||
|
|
||||||
|
ScopedMutexLocker sml(g_app_mutex);
|
||||||
|
|
||||||
|
_SigLink& sl = this->_sig[sig];
|
||||||
|
if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED))
|
||||||
|
{
|
||||||
|
QSE_ASSERT (g_app_sig[sig] != this);
|
||||||
|
QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL);
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
|
||||||
|
|
||||||
|
if (g_app_sig[sig] == this) g_app_sig[sig] = sl._next;
|
||||||
|
|
||||||
|
if (sl._next)
|
||||||
|
{
|
||||||
|
sl._next->_sig[sig]._prev = sl._prev;
|
||||||
|
sl._next = QSE_NULL;
|
||||||
|
}
|
||||||
|
if (sl._prev)
|
||||||
|
{
|
||||||
|
sl._prev->_sig[sig]._next = sl._next;
|
||||||
|
sl._prev = QSE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_app_sig[sig]) App::unsetSignalHandler (sig);
|
||||||
|
sl._state = _SigLink::UNHANDLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
QSE_END_NAMESPACE(QSE)
|
QSE_END_NAMESPACE(QSE)
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
@ -18,10 +18,6 @@
|
|||||||
|
|
||||||
QSE::Mutex g_prt_mutex;
|
QSE::Mutex g_prt_mutex;
|
||||||
|
|
||||||
#if defined(QSE_LANG_CPP11)
|
|
||||||
QSE::TcpServerL<int(QSE::TcpServer::Worker*)>* g_server;
|
|
||||||
#else
|
|
||||||
|
|
||||||
class ClientHandler
|
class ClientHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -55,10 +51,83 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(QSE_LANG_CPP11)
|
||||||
|
static QSE::TcpServerL<int(QSE::TcpServer::Worker*)>* g_server;
|
||||||
|
#else
|
||||||
static QSE::TcpServerF<ClientHandler>* g_server;
|
static QSE::TcpServerF<ClientHandler>* g_server;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
class MyApp: public QSE::App
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyApp(QSE::Mmgr* mmgr): App(mmgr), server(mmgr) {}
|
||||||
|
|
||||||
|
void on_signal (int sig)
|
||||||
|
{
|
||||||
|
switch (sig)
|
||||||
|
{
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGHUP:
|
||||||
|
this->server.stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int run ()
|
||||||
|
{
|
||||||
|
this->server.setThreadStackSize (256000);
|
||||||
|
return this->server.start (QSE_T("[::]:9998,0.0.0.0:9998"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSE::TcpServerF<ClientHandler> server;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int test1()
|
||||||
|
{
|
||||||
|
QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000);
|
||||||
|
MyApp app (&heap_mmgr);
|
||||||
|
app.handleSignal (SIGINT, true);
|
||||||
|
app.handleSignal (SIGTERM, true);
|
||||||
|
int n = app.run();
|
||||||
|
app.handleSignal (SIGTERM, false);
|
||||||
|
app.handleSignal (SIGINT, false);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
char locale[100];
|
||||||
|
UINT codepage = GetConsoleOutputCP();
|
||||||
|
if (codepage == CP_UTF8)
|
||||||
|
{
|
||||||
|
/*SetConsoleOUtputCP (CP_UTF8);*/
|
||||||
|
qse_setdflcmgrbyid (QSE_CMGR_UTF8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf (locale, ".%u", (unsigned int)codepage);
|
||||||
|
setlocale (LC_ALL, locale);
|
||||||
|
/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
setlocale (LC_ALL, "");
|
||||||
|
/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qse_open_stdsios ();
|
||||||
|
test1();
|
||||||
|
qse_close_stdsios ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0 ////////////////////////
|
||||||
|
|
||||||
static int test1 (void)
|
static int test1 (void)
|
||||||
{
|
{
|
||||||
QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000);
|
QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000);
|
||||||
@ -96,7 +165,6 @@ static int test1 (void)
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
&heap_mmgr
|
&heap_mmgr
|
||||||
|
|
||||||
);
|
);
|
||||||
#else
|
#else
|
||||||
QSE::TcpServerF<ClientHandler> server (&heap_mmgr);
|
QSE::TcpServerF<ClientHandler> server (&heap_mmgr);
|
||||||
@ -139,12 +207,13 @@ int main ()
|
|||||||
|
|
||||||
qse_open_stdsios ();
|
qse_open_stdsios ();
|
||||||
|
|
||||||
QSE::App::setSignalHandler (SIGINT, handle_sigint);
|
//QSE::App::setSignalHandler (SIGINT, handle_sigint);
|
||||||
test1();
|
test1();
|
||||||
QSE::App::unsetSignalHandler (SIGINT);
|
//QSE::App::unsetSignalHandler (SIGINT);
|
||||||
|
|
||||||
qse_close_stdsios ();
|
qse_close_stdsios ();
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif ////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user