renamed some signal handling functions in the App class

This commit is contained in:
hyung-hwan 2018-09-13 06:51:48 +00:00
parent c09a0161eb
commit c467a28f18
4 changed files with 78 additions and 51 deletions

View File

@ -102,6 +102,7 @@ struct qse_cli_data_t
const qse_char_t** optsta; const qse_char_t** optsta;
const qse_char_t* optasn; const qse_char_t* optasn;
qse_cli_opt_t* opts; qse_cli_opt_t* opts;
void* ctx;
}; };
typedef struct qse_cli_data_t qse_cli_data_t; typedef struct qse_cli_data_t qse_cli_data_t;

View File

@ -43,12 +43,11 @@ public:
enum SignalState enum SignalState
{ {
SIGNAL_UNHANDLED, SIGNAL_NEGLECTED, // signal is unhandled at the system level.
SIGNAL_ACCEPTED, SIGNAL_ACCEPTED, // on_signal callback is triggered
SIGNAL_IGNORED // handled but ignored SIGNAL_DISCARDED // handled but doesn't trigger the on_signal callback
}; };
App (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT; App (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT;
virtual ~App () QSE_CPP_NOEXCEPT; virtual ~App () QSE_CPP_NOEXCEPT;
@ -65,15 +64,21 @@ public:
virtual void on_signal (int sig) { } virtual void on_signal (int sig) { }
SignalState getSignalSubscription (int sig) const; SignalState getSignalSubscription (int sig) const;
int setSignalSubscription (int sig, SignalState ss); int setSignalSubscription (int sig, SignalState ss, bool ignore_if_unhandled = false);
int subscribeToSignal (int sig, bool accept) int acceptSignal (int sig)
{ {
return this->setSignalSubscription (sig, (accept? SIGNAL_ACCEPTED: SIGNAL_IGNORED)); return this->setSignalSubscription(sig, SIGNAL_ACCEPTED);
} }
int unsubscribeFromSignal (int sig)
int discardSignal (int sig)
{ {
return this->setSignalSubscription (sig, SIGNAL_UNHANDLED); return this->setSignalSubscription(sig, SIGNAL_DISCARDED);
}
int neglectSignal (int sig)
{
return this->setSignalSubscription(sig, SIGNAL_NEGLECTED);
} }
typedef void (*SignalHandler) (int sig); typedef void (*SignalHandler) (int sig);
@ -96,7 +101,7 @@ private:
struct _SigLink struct _SigLink
{ {
_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(SIGNAL_UNHANDLED) {} _SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(SIGNAL_NEGLECTED) {}
App* _prev; App* _prev;
App* _next; App* _next;
SignalState _state; SignalState _state;
@ -105,15 +110,12 @@ private:
_SigLink _sig[QSE_NSIGS]; _SigLink _sig[QSE_NSIGS];
long int _guarded_child_pid; long int _guarded_child_pid;
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, int ignore); static int unset_signal_handler_no_mutex (int sig, int ignore);
int set_signal_subscription_no_mutex (int sig, SignalState reqstate, bool ignore_if_unhandled);
int set_signal_subscription_no_mutex (int sig, SignalState reqstate);
void on_guard_signal (int sig); void on_guard_signal (int sig);
static void handle_signal (int sig); static void handle_signal (int sig);
}; };
///////////////////////////////// /////////////////////////////////

View File

@ -85,8 +85,19 @@ App::~App () QSE_CPP_NOEXCEPT
SigScopedMutexLocker sml(g_app_mutex); SigScopedMutexLocker sml(g_app_mutex);
for (int i = 0; i < QSE_NSIGS; i++) for (int i = 0; i < QSE_NSIGS; i++)
{ {
this->set_signal_subscription_no_mutex (i, SIGNAL_UNHANDLED); // if the signal handler has not been removed before this application
// is destroyed and this is the last application subscribing to
// a signal, i arrange to set the signal handler to SIG_IGN as indicated by
// the third argument 'true' to set_signal_subscription_no_mutex().
// if the signal is not ignored, the signal received after destruction
// of this application object may lead to program crash as the handler
// is still associated with the destructed object.
// if the signal handler has been removed, the following function
// actual does nothing.
this->set_signal_subscription_no_mutex (i, SIGNAL_NEGLECTED, true);
} }
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) if (this == g_app_top)
@ -321,10 +332,10 @@ int App::unset_signal_handler_no_mutex(int sig, int ignore)
if (sl._state == App::SIGNAL_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 acceptSingal()/discardSignal()neglectSingal()
// 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); app->on_signal (sig);
} }
app = next; app = next;
} }
@ -335,28 +346,28 @@ void App::on_guard_signal (int sig)
::kill (this->_guarded_child_pid, sig); ::kill (this->_guarded_child_pid, sig);
} }
App::SignalState App::getSignalSubscription (int sig) const App::SignalState App::getSignalSubscription (int sig) const
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
return this->_sig[sig]._state; return this->_sig[sig]._state;
} }
int App::setSignalSubscription (int sig, SignalState ss) int App::setSignalSubscription (int sig, SignalState ss, bool ignore_if_unhandled)
{ {
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
SigScopedMutexLocker sml(g_app_mutex); SigScopedMutexLocker sml(g_app_mutex);
return this->set_signal_subscription_no_mutex(sig, ss); return this->set_signal_subscription_no_mutex(sig, ss, ignore_if_unhandled);
} }
int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate) int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate, bool ignore_if_unhandled)
{ {
_SigLink& sl = this->_sig[sig]; _SigLink& sl = this->_sig[sig];
if (QSE_UNLIKELY(sl._state == reqstate)) return 0; // no change if (QSE_UNLIKELY(sl._state == reqstate)) return 0; // no change
if (reqstate == SIGNAL_UNHANDLED) if (reqstate == SIGNAL_NEGLECTED)
{ {
// accepted/ignored -> unhandled // accepted/discarded -> neglected(unhandled)
QSE_ASSERT (g_app_sig[sig] != QSE_NULL); QSE_ASSERT (g_app_sig[sig] != QSE_NULL);
if (g_app_sig[sig] == this) if (g_app_sig[sig] == this)
@ -364,7 +375,9 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
QSE_ASSERT (sl._prev == QSE_NULL); QSE_ASSERT (sl._prev == QSE_NULL);
if (!sl._next) if (!sl._next)
{ {
if (App::unset_signal_handler_no_mutex(sig, true) <= -1) return -1; // this is the last application subscribing to the signal.
// let's get rid of the signal handler
if (App::unset_signal_handler_no_mutex(sig, ignore_if_unhandled) <= -1) return -1;
} }
g_app_sig[sig] = sl._next; g_app_sig[sig] = sl._next;
} }
@ -375,9 +388,9 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
sl._next = QSE_NULL; sl._next = QSE_NULL;
sl._state = reqstate; sl._state = reqstate;
} }
else if (QSE_LIKELY(sl._state == SIGNAL_UNHANDLED)) else if (QSE_LIKELY(sl._state == SIGNAL_NEGLECTED))
{ {
// unhandled -> accepted/ignored // neglected(unhandled) -> accepted/discarded
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];
@ -400,7 +413,7 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState 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 = SIGNAL_UNHANDLED; sl._state = SIGNAL_NEGLECTED;
sl._next = QSE_NULL; sl._next = QSE_NULL;
QSE_ASSERT (sl._prev == QSE_NULL); QSE_ASSERT (sl._prev == QSE_NULL);
return -1; return -1;
@ -423,25 +436,36 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
{ {
SignalState old_ss[QSE_NSIGS]; SignalState old_ss[QSE_NSIGS];
for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i))
{
old_ss[i] = this->getSignalSubscription(i);
this->setSignalSubscription (i, SIGNAL_ACCEPTED);
}
}
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) if (pid == 0)
{ {
::setpgid (0, 0); // change the process group id. // child process
break; // child this->_guarded_child_pid = -1;
}
for (int i = 0; i < QSE_NSIGS; i++) for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i))
{ {
old_ss[i] = this->getSignalSubscription(i); if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]);
this->setSignalSubscription (i, SIGNAL_ACCEPTED);
} }
::setpgid (0, 0); // change the process group id.
break;
} }
// ===============================================
// the guardian(parent) process
// ===============================================
this->_guarded_child_pid = pid; this->_guarded_child_pid = pid;
int status; int status;
@ -455,17 +479,15 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
// ------------------------------------------------------ // ------------------------------------------------------
} }
this->_guarded_child_pid = -1;
for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]);
}
if (WIFEXITED(status)) if (WIFEXITED(status))
{ {
if (WEXITSTATUS(status) == 0) if (WEXITSTATUS(status) == 0)
{ {
// the child has terminated normally and successfully. // the child has terminated normally and successfully.
for (int i = 0; i < QSE_NSIGS; i++)
{
if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]);
}
return 0; return 0;
} }
} }

View File

@ -67,6 +67,8 @@ public:
case SIGINT: case SIGINT:
case SIGTERM: case SIGTERM:
case SIGHUP: case SIGHUP:
// TODO: don't call stop() if this processs is a guardian
// though it's no harm to call stop().
qse_printf (QSE_T("requesting to stop server...app %p server %p - pid %d\n"), this, &this->server, (int)getpid()); 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;
@ -103,20 +105,20 @@ 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.acceptSignal (SIGINT);
app.subscribeToSignal (SIGTERM, true); app.acceptSignal (SIGTERM);
app4.subscribeToSignal (SIGINT, true); app4.acceptSignal (SIGINT);
app3.subscribeToSignal (SIGINT, true); app3.acceptSignal (SIGINT);
app2.subscribeToSignal (SIGINT, true); app2.acceptSignal (SIGINT);
int n = app.run(); int n = app.run();
app.subscribeToSignal (SIGTERM, false); app.discardSignal (SIGTERM);
app.subscribeToSignal (SIGINT, false); app.discardSignal (SIGINT);
app4.unsubscribeFromSignal (SIGINT); app4.neglectSignal (SIGINT);
app3.unsubscribeFromSignal (SIGINT); app3.neglectSignal (SIGINT);
app2.unsubscribeFromSignal (SIGINT); app2.neglectSignal (SIGINT);
qse_printf (QSE_T("END OF %d\n"), (int)getpid()); qse_printf (QSE_T("END OF %d\n"), (int)getpid());
return n; return n;