attempted to fix various problems related to signals in App
This commit is contained in:
parent
7bfba716f6
commit
9764d448af
@ -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 ();
|
||||
|
||||
|
@ -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,13 +283,13 @@ 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()
|
||||
// from within the handler.
|
||||
if (app->_guarded_child_pid >= 0) app->on_guard_signal (sig);
|
||||
else app->on_signal (sig);
|
||||
else app->on_signal (sig);
|
||||
}
|
||||
app = next;
|
||||
}
|
||||
@ -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)
|
||||
int App::setSignalSubscription (int sig, SignalState ss)
|
||||
{
|
||||
_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;
|
||||
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
|
||||
|
||||
case _SigLink::ACCEPTED:
|
||||
case _SigLink::IGNORED:
|
||||
this->subscribe_to_signal_no_mutex (i, _old_state[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
sigset_t sigset;
|
||||
::sigemptyset (&sigset);
|
||||
::sigaddset (&sigset, sig);
|
||||
::sigprocmask (SIG_BLOCK, &sigset, QSE_NULL);
|
||||
|
||||
int n;
|
||||
{
|
||||
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];
|
||||
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;
|
||||
|
@ -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 ();
|
||||
|
Loading…
Reference in New Issue
Block a user