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
{
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;
virtual ~App () QSE_CPP_NOEXCEPT;
@ -56,10 +64,18 @@ public:
virtual void on_signal (int sig) { }
int subscribeToSignal (int sig, bool accept);
int subscribeToAllSignals (bool accept);
void unsubscribeFromSignal (int sig);
void unsubscribeFromAllSignals ();
SignalState getSignalSubscription (int sig) const;
int setSignalSubscription (int sig, SignalState ss);
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);
static qse_size_t _sighrs[2][QSE_NSIGS];
@ -73,7 +89,7 @@ public:
static int setSignalHandler (int sig, SignalHandler sighr);
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:
App* _prev_app;
@ -81,17 +97,10 @@ private:
struct _SigLink
{
enum State
{
UNHANDLED,
ACCEPTED,
IGNORED // handled but ignored
};
_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(UNHANDLED) {}
_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(SIGNAL_UNHANDLED) {}
App* _prev;
App* _next;
State _state;
SignalState _state;
};
_SigLink _sig[QSE_NSIGS];
@ -101,7 +110,9 @@ protected:
static int set_signal_handler_no_mutex (int sig, SignalHandler sighr);
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_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)
sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))App::_sighrs[1][sig];
else
{
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;
@ -279,7 +283,7 @@ int App::unset_signal_handler_no_mutex(int sig)
{
App::_SigLink& sl = app->_sig[sig];
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.
// it must not call subscribeToSingal() or unsubscribeFromSingal()
@ -297,73 +301,68 @@ printf ("relaying %d to %d\n", sig, (int)this->_guarded_child_pid);
::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);
_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED;
ScopedMutexLocker sml(g_app_mutex);
return this->subscribe_to_signal_no_mutex(sig, reqstate);
return this->_sig[sig]._state;
}
int App::subscribeToAllSignals (bool accept)
{
_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED;
_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:
case _SigLink::IGNORED:
this->subscribe_to_signal_no_mutex (i, _old_state[i]);
break;
}
}
return -1;
}
}
return 0;
}
void App::unsubscribeFromSignal (int sig)
int App::setSignalSubscription (int sig, SignalState ss)
{
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
sigset_t sigset;
::sigemptyset (&sigset);
::sigaddset (&sigset, sig);
::sigprocmask (SIG_BLOCK, &sigset, QSE_NULL);
int n;
{
ScopedMutexLocker sml(g_app_mutex);
this->unsubscribe_from_signal_no_mutex (sig);
n = this->set_signal_subscription_no_mutex(sig, ss);
}
::sigprocmask (SIG_UNBLOCK, &sigset, QSE_NULL);
return n;
}
void App::unsubscribeFromAllSignals ()
int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
{
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];
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);
App* xapp = g_app_sig[sig];
App* xapp_xprev = QSE_NULL;
g_app_sig[sig] = this;
sl._state = _SigLink::ACCEPTED;
sl._state = SIGNAL_ACCEPTED;
sl._next = xapp;
if (xapp)
{
@ -379,10 +378,58 @@ int App::subscribe_to_signal_no_mutex (int sig, _SigLink::State reqstate)
// roll back
g_app_sig[sig] = xapp;
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;
QSE_ASSERT (sl._prev == QSE_NULL);
if (errno == EINVAL) return 0; /// dirty hack???
return -1;
}
}
@ -397,14 +444,15 @@ if (errno == EINVAL) return 0; /// dirty hack???
}
return 0;
#endif
}
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];
if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED))
if (QSE_UNLIKELY(sl._state == SIGNAL_UNHANDLED))
{
QSE_ASSERT (g_app_sig[sig] != this);
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;
sl._prev = QSE_NULL;
sl._next = QSE_NULL;
sl._state = _SigLink::UNHANDLED;
sl._state = SIGNAL_UNHANDLED;
}
#endif
}
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)
{
pid_t pid = ::fork();
if (pid == -1) return -1;
if (pid == 0) break; // child
//int _SigLink::State old_sig_states[QSE_NSIGS];
//this->subscribeToAllSignals(true);
for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i))
{
old_ss[i] = this->getSignalSubscription(i);
this->setSignalSubscription (i, SIGNAL_ACCEPTED);
}
}
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;
// 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)
{
return 0;

View File

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