fixed some bugs in the signal related functions of the QSE::App class

This commit is contained in:
hyung-hwan 2018-09-04 08:46:48 +00:00
parent bb7a03bbc5
commit 82995c9f0d
4 changed files with 112 additions and 37 deletions

View File

@ -78,15 +78,27 @@ public:
_SigLink _sig[QSE_NSIGS]; _SigLink _sig[QSE_NSIGS];
public:
typedef void (*SignalHandler) (int sig); typedef void (*SignalHandler) (int sig);
static int setSignalHandler (int sig, SignalHandler sighr);
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); int subscribeToSignal (int sig, bool accept);
void unhandleSignal (int sig); void unsubscribeFromSignal (int sig);
// You may set a global signal handler with setSignalHandler().
// If an application is subscribing to a single with subscribeToSignal(),
// this function is doomed to fail. If a successful call to
// setSignalHandler() has been made withoutut unsetSingalHandler() called
// yet, a subsequence call to subscribeToSignal() is doomed to fail too.
// These two different interfaces are mutually exclusive.
static int setSignalHandler (int sig, SignalHandler sighr);
static int unsetSignalHandler (int sig);
protected:
static int set_signal_handler_no_mutex (int sig, SignalHandler sighr);
static int unset_signal_handler_no_mutex (int sig);
void unsubscribe_from_signal_no_mutex (int sig);
void unsubscribe_from_all_signals_no_mutex ();
}; };
// functor as a template parameter // functor as a template parameter

View File

@ -417,7 +417,7 @@
#if defined(SYS_rename) && defined(QSE_USE_SYSCALL) #if defined(SYS_rename) && defined(QSE_USE_SYSCALL)
# define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath) # define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath)
#else #else
int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */ extern int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */
# define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath) # define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath)
#endif #endif

View File

@ -34,7 +34,6 @@
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
static Mutex g_app_mutex; static Mutex g_app_mutex;
static App* g_app_top = QSE_NULL; // maintain the chain of application objects static App* g_app_top = QSE_NULL; // maintain the chain of application objects
static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, }; static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, };
@ -61,9 +60,14 @@ App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false), _prev_ap
App::~App () QSE_CPP_NOEXCEPT App::~App () QSE_CPP_NOEXCEPT
{ {
ScopedMutexLocker sml(g_app_mutex); ScopedMutexLocker sml(g_app_mutex);
this->unsubscribe_from_all_signals_no_mutex ();
if (this->_next_app) this->_next_app->_prev_app = this->_prev_app; 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->_prev_app) this->_prev_app->_next_app = this->_next_app;
if (this == g_app_top) g_app_top = this->_next_app; if (this == g_app_top)
{
QSE_ASSERT (this->_prev_app == QSE_NULL);
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
@ -134,10 +138,9 @@ int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT
return 0; return 0;
} }
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);
} }
int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT
@ -145,7 +148,7 @@ int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT
qse_mchar_t* mpath; qse_mchar_t* mpath;
mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr()); mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr());
if (!mpath) return -1; if (!mpath) return -1;
int n = App::chroot ((const qse_mchar_t*)mpath); int n = App::chroot((const qse_mchar_t*)mpath);
this->getMmgr()->dispose (mpath); this->getMmgr()->dispose (mpath);
return n; return n;
} }
@ -201,8 +204,13 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
} }
} }
int App::setSignalHandler (int sig, SignalHandler sighr) int App::setSignalHandler (int sig, SignalHandler sighr)
{
ScopedMutexLocker sml(g_app_mutex);
return App::set_signal_handler_no_mutex (sig, sighr);
}
int App::set_signal_handler_no_mutex (int sig, SignalHandler sighr)
{ {
if (App::_sighrs[0][sig]) return -1; // already set if (App::_sighrs[0][sig]) return -1; // already set
@ -236,6 +244,12 @@ int App::setSignalHandler (int sig, SignalHandler sighr)
} }
int App::unsetSignalHandler (int sig) int App::unsetSignalHandler (int sig)
{
ScopedMutexLocker sml(g_app_mutex);
return App::unset_signal_handler_no_mutex(sig);
}
int App::unset_signal_handler_no_mutex(int sig)
{ {
if (!App::_sighrs[0][sig]) return -1; if (!App::_sighrs[0][sig]) return -1;
@ -268,7 +282,7 @@ static void handle_signal (int sig)
} }
} }
void App::handleSignal (int sig, bool accept) int App::subscribeToSignal (int sig, bool accept)
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
@ -278,31 +292,56 @@ void App::handleSignal (int sig, bool accept)
_SigLink& sl = this->_sig[sig]; _SigLink& sl = this->_sig[sig];
if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED)) if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED))
{ {
if (!g_app_sig[sig]) QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL);
App* xapp = g_app_sig[sig];
App* xapp_xprev = QSE_NULL;
g_app_sig[sig] = this;
sl._state = _SigLink::ACCEPTED;
sl._next = xapp;
if (xapp)
{
xapp_xprev = xapp->_sig[sig]._prev;
xapp->_sig[sig]._prev = this;
}
else
{ {
// no application is set to accept this signal. // no application is set to accept this signal.
// this is the first time to // this is the first time to
App::setSignalHandler (sig, handle_signal); if (App::set_signal_handler_no_mutex(sig, handle_signal) <= -1)
{
// roll back
g_app_sig[sig] = xapp;
if (xapp) xapp->_sig[sig]._prev = xapp_xprev;
sl._state = _SigLink::UNHANDLED;
sl._next = QSE_NULL;
QSE_ASSERT (sl._prev == QSE_NULL);
return -1;
}
} }
sl._state = _SigLink::ACCEPTED; QSE_ASSERT (sl._prev == QSE_NULL);
sl._next = g_app_sig[sig];
g_app_sig[sig] = this;
} }
else else
{ {
// already configured to receive the signal. // already configured to receive the signal. change the state only
QSE_ASSERT (g_app_sig[sig] != QSE_NULL); QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
sl._state = reqstate; sl._state = reqstate;
} }
return 0;
} }
void App::unhandleSignal (int sig) void App::unsubscribeFromSignal (int sig)
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
ScopedMutexLocker sml(g_app_mutex); ScopedMutexLocker sml(g_app_mutex);
this->unsubscribe_from_signal_no_mutex (sig);
}
void App::unsubscribe_from_signal_no_mutex (int sig)
{
_SigLink& sl = this->_sig[sig]; _SigLink& sl = this->_sig[sig];
if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED)) if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED))
{ {
@ -314,24 +353,29 @@ void App::unhandleSignal (int sig)
{ {
QSE_ASSERT (g_app_sig[sig] != QSE_NULL); QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
if (g_app_sig[sig] == this) g_app_sig[sig] = sl._next; if (g_app_sig[sig] == this)
if (sl._next)
{ {
sl._next->_sig[sig]._prev = sl._prev; QSE_ASSERT (sl._prev == QSE_NULL);
sl._next = QSE_NULL; g_app_sig[sig] = sl._next;
}
if (sl._prev)
{
sl._prev->_sig[sig]._next = sl._next;
sl._prev = QSE_NULL;
} }
if (!g_app_sig[sig]) App::unsetSignalHandler (sig); if (sl._next) sl._next->_sig[sig]._prev = sl._prev;
if (sl._prev) sl._prev->_sig[sig]._next = sl._next;
sl._prev = QSE_NULL;
sl._next = QSE_NULL;
if (!g_app_sig[sig]) App::unset_signal_handler_no_mutex (sig);
sl._state = _SigLink::UNHANDLED; sl._state = _SigLink::UNHANDLED;
} }
} }
void App::unsubscribe_from_all_signals_no_mutex()
{
for (int i = 0; i < QSE_NSIGS; i++)
{
this->unsubscribe_from_signal_no_mutex (i);
}
}
///////////////////////////////// /////////////////////////////////
QSE_END_NAMESPACE(QSE) QSE_END_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////

View File

@ -70,6 +70,9 @@ public:
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
case SIGHUP: case SIGHUP:
g_prt_mutex.lock();
qse_printf (QSE_T("requesting to stop server...app %p server %p\n"), this, &this->server);
g_prt_mutex.unlock();
this->server.stop(); this->server.stop();
break; break;
} }
@ -89,11 +92,27 @@ static int test1()
{ {
QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000);
MyApp app (&heap_mmgr); MyApp app (&heap_mmgr);
app.handleSignal (SIGINT, true);
app.handleSignal (SIGTERM, true); MyApp app2 (&heap_mmgr);
MyApp app3 (&heap_mmgr);
MyApp app4 (&heap_mmgr);
app.subscribeToSignal (SIGINT, true) ;
app.subscribeToSignal (SIGTERM, true);
app4.subscribeToSignal (SIGINT, true);
app3.subscribeToSignal (SIGINT, true);
app2.subscribeToSignal (SIGINT, true);
int n = app.run(); int n = app.run();
app.handleSignal (SIGTERM, false); app.subscribeToSignal (SIGTERM, false);
app.handleSignal (SIGINT, false); app.subscribeToSignal (SIGINT, false);
app4.unsubscribeFromSignal (SIGINT);
app3.unsubscribeFromSignal (SIGINT);
app2.unsubscribeFromSignal (SIGINT);
return n; return n;
} }