attempted to fix various problems related to signals in App

This commit is contained in:
hyung-hwan 2018-09-09 17:22:16 +00:00
parent 7bfba716f6
commit 9764d448af
3 changed files with 164 additions and 89 deletions

View File

@ -39,7 +39,15 @@ QSE_BEGIN_NAMESPACE(QSE)
class App: public Uncopyable, public Types, public Mmged class App: public Uncopyable, public Types, public Mmged
{ {
public: public:
typedef QSE::Bitset<QSE_NSIGS> Sigset; typedef QSE::Bitset<QSE_NSIGS> SignalSet;
enum SignalState
{
SIGNAL_UNHANDLED,
SIGNAL_ACCEPTED,
SIGNAL_IGNORED // handled but ignored
};
App (Mmgr* mmgr) QSE_CPP_NOEXCEPT; App (Mmgr* mmgr) QSE_CPP_NOEXCEPT;
virtual ~App () QSE_CPP_NOEXCEPT; virtual ~App () QSE_CPP_NOEXCEPT;
@ -56,10 +64,18 @@ public:
virtual void on_signal (int sig) { } virtual void on_signal (int sig) { }
int subscribeToSignal (int sig, bool accept); SignalState getSignalSubscription (int sig) const;
int subscribeToAllSignals (bool accept); int setSignalSubscription (int sig, SignalState ss);
void unsubscribeFromSignal (int sig);
void unsubscribeFromAllSignals (); int subscribeToSignal (int sig, bool accept)
{
return this->setSignalSubscription (sig, (accept? SIGNAL_ACCEPTED: SIGNAL_IGNORED));
}
int unsubscribeFromSignal (int sig)
{
return this->setSignalSubscription (sig, SIGNAL_UNHANDLED);
}
typedef void (*SignalHandler) (int sig); typedef void (*SignalHandler) (int sig);
static qse_size_t _sighrs[2][QSE_NSIGS]; static qse_size_t _sighrs[2][QSE_NSIGS];
@ -73,7 +89,7 @@ public:
static int setSignalHandler (int sig, SignalHandler sighr); static int setSignalHandler (int sig, SignalHandler sighr);
static int unsetSignalHandler (int sig); static int unsetSignalHandler (int sig);
int guardProcess (const qse_mchar_t* proc_name, const Sigset& signals); int guardProcess (const qse_mchar_t* proc_name, const SignalSet& signals);
private: private:
App* _prev_app; App* _prev_app;
@ -81,17 +97,10 @@ private:
struct _SigLink struct _SigLink
{ {
enum State _SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(SIGNAL_UNHANDLED) {}
{
UNHANDLED,
ACCEPTED,
IGNORED // handled but ignored
};
_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(UNHANDLED) {}
App* _prev; App* _prev;
App* _next; App* _next;
State _state; SignalState _state;
}; };
_SigLink _sig[QSE_NSIGS]; _SigLink _sig[QSE_NSIGS];
@ -101,7 +110,9 @@ protected:
static int set_signal_handler_no_mutex (int sig, SignalHandler sighr); static int set_signal_handler_no_mutex (int sig, SignalHandler sighr);
static int unset_signal_handler_no_mutex (int sig); static int unset_signal_handler_no_mutex (int sig);
int subscribe_to_signal_no_mutex (int sig, _SigLink::State reqstate); int set_signal_subscription_no_mutex (int sig, SignalState reqstate);
int subscribe_to_signal_no_mutex (int sig, SignalState reqstate);
void unsubscribe_from_signal_no_mutex (int sig); void unsubscribe_from_signal_no_mutex (int sig);
void unsubscribe_from_all_signals_no_mutex (); void unsubscribe_from_all_signals_no_mutex ();

View File

@ -261,7 +261,11 @@ int App::unset_signal_handler_no_mutex(int sig)
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];
printf ("unset signal handler......\n");
sa.sa_handler = SIG_IGN;
}
if (::sigaction (sig, &sa, QSE_NULL) <= -1) return -1; if (::sigaction (sig, &sa, QSE_NULL) <= -1) return -1;
@ -279,13 +283,13 @@ int App::unset_signal_handler_no_mutex(int sig)
{ {
App::_SigLink& sl = app->_sig[sig]; App::_SigLink& sl = app->_sig[sig];
App* next = sl._next; App* next = sl._next;
if (sl._state == App::_SigLink::ACCEPTED) if (sl._state == App::SIGNAL_ACCEPTED)
{ {
// the actual signal handler is called with the mutex locked. // the actual signal handler is called with the mutex locked.
// it must not call subscribeToSingal() or unsubscribeFromSingal() // it must not call subscribeToSingal() or unsubscribeFromSingal()
// from within the handler. // from within the handler.
if (app->_guarded_child_pid >= 0) app->on_guard_signal (sig); if (app->_guarded_child_pid >= 0) app->on_guard_signal (sig);
else app->on_signal (sig); else app->on_signal (sig);
} }
app = next; app = next;
} }
@ -297,73 +301,68 @@ printf ("relaying %d to %d\n", sig, (int)this->_guarded_child_pid);
::kill (this->_guarded_child_pid, sig); ::kill (this->_guarded_child_pid, sig);
} }
int App::subscribeToSignal (int sig, bool accept)
App::SignalState App::getSignalSubscription (int sig) const
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED; return this->_sig[sig]._state;
ScopedMutexLocker sml(g_app_mutex);
return this->subscribe_to_signal_no_mutex(sig, reqstate);
} }
int App::subscribeToAllSignals (bool accept) int App::setSignalSubscription (int sig, SignalState ss)
{ {
_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED; QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
_SigLink::State _old_state[QSE_NSIGS];
ScopedMutexLocker sml(g_app_mutex);
for (int i = 0; i < QSE_NSIGS; i++)
{
_old_state[i] = this->_sig[i]._state;
if (this->subscribe_to_signal_no_mutex(i, reqstate) <= -1)
{
// roll back on a best-efforts basis.
while (i > 0)
{
--i;
switch (_old_state[i])
{
case _SigLink::UNHANDLED:
this->unsubscribe_from_signal_no_mutex (i);
break;
case _SigLink::ACCEPTED: sigset_t sigset;
case _SigLink::IGNORED: ::sigemptyset (&sigset);
this->subscribe_to_signal_no_mutex (i, _old_state[i]); ::sigaddset (&sigset, sig);
break; ::sigprocmask (SIG_BLOCK, &sigset, QSE_NULL);
}
} int n;
return -1; {
} ScopedMutexLocker sml(g_app_mutex);
n = this->set_signal_subscription_no_mutex(sig, ss);
} }
return 0;
::sigprocmask (SIG_UNBLOCK, &sigset, QSE_NULL);
return n;
} }
void App::unsubscribeFromSignal (int sig) int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
ScopedMutexLocker sml(g_app_mutex);
this->unsubscribe_from_signal_no_mutex (sig);
}
void App::unsubscribeFromAllSignals ()
{
ScopedMutexLocker sml(g_app_mutex);
this->unsubscribe_from_all_signals_no_mutex ();
}
int App::subscribe_to_signal_no_mutex (int sig, _SigLink::State reqstate)
{
if (sig == SIGKILL || sig == SIGSTOP) return 0;
_SigLink& sl = this->_sig[sig]; _SigLink& sl = this->_sig[sig];
if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED)) if (QSE_UNLIKELY(sl._state == reqstate)) return 0; // no change
if (reqstate == SIGNAL_UNHANDLED)
{ {
// accepted/ignored -> unhandled
QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
if (g_app_sig[sig] == this)
{
QSE_ASSERT (sl._prev == QSE_NULL);
if (!sl._next)
{
if (App::unset_signal_handler_no_mutex (sig) <= -1) return -1;
}
g_app_sig[sig] = sl._next;
}
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;
sl._state = reqstate;
}
else if (QSE_LIKELY(sl._state == SIGNAL_UNHANDLED))
{
// unhandled -> accepted/ignored
QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL); QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL);
App* xapp = g_app_sig[sig]; App* xapp = g_app_sig[sig];
App* xapp_xprev = QSE_NULL; App* xapp_xprev = QSE_NULL;
g_app_sig[sig] = this; g_app_sig[sig] = this;
sl._state = _SigLink::ACCEPTED; sl._state = SIGNAL_ACCEPTED;
sl._next = xapp; sl._next = xapp;
if (xapp) if (xapp)
{ {
@ -379,10 +378,58 @@ int App::subscribe_to_signal_no_mutex (int sig, _SigLink::State reqstate)
// roll back // roll back
g_app_sig[sig] = xapp; g_app_sig[sig] = xapp;
if (xapp) xapp->_sig[sig]._prev = xapp_xprev; if (xapp) xapp->_sig[sig]._prev = xapp_xprev;
sl._state = _SigLink::UNHANDLED; sl._state = SIGNAL_UNHANDLED;
sl._next = QSE_NULL;
QSE_ASSERT (sl._prev == QSE_NULL);
return -1;
}
}
QSE_ASSERT (sl._prev == QSE_NULL);
}
else
{
// accpeted/ignored -> ignored/accepted
QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
sl._state = reqstate;
}
return reqstate;
}
int App::subscribe_to_signal_no_mutex (int sig, SignalState reqstate)
{
return this->set_signal_subscription_no_mutex (sig, reqstate);
#if 0
_SigLink& sl = this->_sig[sig];
if (QSE_LIKELY(sl._state == SIGNAL_UNHANDLED))
{
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 = SIGNAL_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.
// this is the first time to
if (App::set_signal_handler_no_mutex(sig, App::handle_signal) <= -1)
{
// roll back
g_app_sig[sig] = xapp;
if (xapp) xapp->_sig[sig]._prev = xapp_xprev;
sl._state = SIGNAL_UNHANDLED;
sl._next = QSE_NULL; sl._next = QSE_NULL;
QSE_ASSERT (sl._prev == QSE_NULL); QSE_ASSERT (sl._prev == QSE_NULL);
if (errno == EINVAL) return 0; /// dirty hack???
return -1; return -1;
} }
} }
@ -397,14 +444,15 @@ if (errno == EINVAL) return 0; /// dirty hack???
} }
return 0; return 0;
#endif
} }
void App::unsubscribe_from_signal_no_mutex (int sig) void App::unsubscribe_from_signal_no_mutex (int sig)
{ {
if (sig == SIGKILL || sig == SIGSTOP) return; this->set_signal_subscription_no_mutex (sig, SIGNAL_UNHANDLED);
#if 0
_SigLink& sl = this->_sig[sig]; _SigLink& sl = this->_sig[sig];
if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED)) if (QSE_UNLIKELY(sl._state == SIGNAL_UNHANDLED))
{ {
QSE_ASSERT (g_app_sig[sig] != this); QSE_ASSERT (g_app_sig[sig] != this);
QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL); QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL);
@ -425,8 +473,9 @@ void App::unsubscribe_from_signal_no_mutex (int sig)
if (sl._prev) sl._prev->_sig[sig]._next = sl._next; if (sl._prev) sl._prev->_sig[sig]._next = sl._next;
sl._prev = QSE_NULL; sl._prev = QSE_NULL;
sl._next = QSE_NULL; sl._next = QSE_NULL;
sl._state = _SigLink::UNHANDLED; sl._state = SIGNAL_UNHANDLED;
} }
#endif
} }
void App::unsubscribe_from_all_signals_no_mutex() void App::unsubscribe_from_all_signals_no_mutex()
@ -437,16 +486,24 @@ void App::unsubscribe_from_all_signals_no_mutex()
} }
} }
int App::guardProcess (const qse_mchar_t* proc_name, const Sigset& signals) int App::guardProcess (const qse_mchar_t* proc_name, const SignalSet& signals)
{ {
SignalState old_ss[QSE_NSIGS];
while (1) while (1)
{ {
pid_t pid = ::fork(); pid_t pid = ::fork();
if (pid == -1) return -1; if (pid == -1) return -1;
if (pid == 0) break; // child if (pid == 0) break; // child
//int _SigLink::State old_sig_states[QSE_NSIGS]; for (int i = 0; i < QSE_NSIGS; i++)
//this->subscribeToAllSignals(true); {
if (signals.isSet(i))
{
old_ss[i] = this->getSignalSubscription(i);
this->setSignalSubscription (i, SIGNAL_ACCEPTED);
}
}
this->_guarded_child_pid = pid; this->_guarded_child_pid = pid;
@ -462,8 +519,12 @@ int App::guardProcess (const qse_mchar_t* proc_name, const Sigset& signals)
} }
this->_guarded_child_pid = -1; this->_guarded_child_pid = -1;
// TODO: restore signal handlers to the previous states for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]);
}
printf ("child exited - exited %d exit status %d\n", WIFEXITED(status), WEXITSTATUS(status));
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
{ {
return 0; return 0;

View File

@ -67,7 +67,7 @@ public:
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
case SIGHUP: case SIGHUP:
qse_printf (QSE_T("requesting to stop server...app %p server %p\n"), this, &this->server); qse_printf (QSE_T("requesting to stop server...app %p server %p - pid %d\n"), this, &this->server, (int)getpid());
this->server.stop(); this->server.stop();
break; break;
} }
@ -75,7 +75,7 @@ public:
int run () int run ()
{ {
QSE::App::Sigset signals; QSE::App::SignalSet signals;
signals.set (SIGINT); signals.set (SIGINT);
signals.set (SIGHUP); signals.set (SIGHUP);
signals.set (SIGTERM); signals.set (SIGTERM);
@ -99,24 +99,26 @@ 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);
//MyApp app2 (&heap_mmgr); MyApp app2 (&heap_mmgr);
//MyApp app3 (&heap_mmgr); MyApp app3 (&heap_mmgr);
//MyApp app4 (&heap_mmgr); MyApp app4 (&heap_mmgr);
app.subscribeToSignal (SIGINT, true); app.subscribeToSignal (SIGINT, true);
app.subscribeToSignal (SIGTERM, true); app.subscribeToSignal (SIGTERM, true);
//app4.subscribeToSignal (SIGINT, true); app4.subscribeToSignal (SIGINT, true);
//app3.subscribeToSignal (SIGINT, true); app3.subscribeToSignal (SIGINT, true);
//app2.subscribeToSignal (SIGINT, true); app2.subscribeToSignal (SIGINT, true);
int n = app.run(); int n = app.run();
app.subscribeToSignal (SIGTERM, false); app.subscribeToSignal (SIGTERM, false);
app.subscribeToSignal (SIGINT, false); app.subscribeToSignal (SIGINT, false);
//app4.unsubscribeFromSignal (SIGINT); app4.unsubscribeFromSignal (SIGINT);
//app3.unsubscribeFromSignal (SIGINT); app3.unsubscribeFromSignal (SIGINT);
//app2.unsubscribeFromSignal (SIGINT); app2.unsubscribeFromSignal (SIGINT);
qse_printf (QSE_T("END OF %d\n"), (int)getpid());
return n; return n;
} }
@ -132,7 +134,7 @@ int main ()
} }
else else
{ {
sprintf (locale, ".%u", (unsigned int)codepage); qse_mbsxfmt (locale, QSE_COUNTOF(locale), ".%u", (unsigned int)codepage);
setlocale (LC_ALL, locale); setlocale (LC_ALL, locale);
/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/
} }
@ -141,6 +143,7 @@ int main ()
/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/
#endif #endif
qse_open_stdsios (); qse_open_stdsios ();
test1(); test1();
qse_close_stdsios (); qse_close_stdsios ();