renamed some signal handling functions in the App class
This commit is contained in:
parent
c09a0161eb
commit
c467a28f18
@ -102,6 +102,7 @@ struct qse_cli_data_t
|
||||
const qse_char_t** optsta;
|
||||
const qse_char_t* optasn;
|
||||
qse_cli_opt_t* opts;
|
||||
void* ctx;
|
||||
|
||||
};
|
||||
typedef struct qse_cli_data_t qse_cli_data_t;
|
||||
|
@ -43,12 +43,11 @@ public:
|
||||
|
||||
enum SignalState
|
||||
{
|
||||
SIGNAL_UNHANDLED,
|
||||
SIGNAL_ACCEPTED,
|
||||
SIGNAL_IGNORED // handled but ignored
|
||||
SIGNAL_NEGLECTED, // signal is unhandled at the system level.
|
||||
SIGNAL_ACCEPTED, // on_signal callback is triggered
|
||||
SIGNAL_DISCARDED // handled but doesn't trigger the on_signal callback
|
||||
};
|
||||
|
||||
|
||||
App (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT;
|
||||
virtual ~App () QSE_CPP_NOEXCEPT;
|
||||
|
||||
@ -65,15 +64,21 @@ public:
|
||||
virtual void on_signal (int sig) { }
|
||||
|
||||
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);
|
||||
@ -96,7 +101,7 @@ private:
|
||||
|
||||
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* _next;
|
||||
SignalState _state;
|
||||
@ -105,15 +110,12 @@ private:
|
||||
_SigLink _sig[QSE_NSIGS];
|
||||
long int _guarded_child_pid;
|
||||
|
||||
protected:
|
||||
static int set_signal_handler_no_mutex (int sig, SignalHandler sighr);
|
||||
static int unset_signal_handler_no_mutex (int sig, int ignore);
|
||||
|
||||
int set_signal_subscription_no_mutex (int sig, SignalState reqstate);
|
||||
int set_signal_subscription_no_mutex (int sig, SignalState reqstate, bool ignore_if_unhandled);
|
||||
|
||||
void on_guard_signal (int sig);
|
||||
static void handle_signal (int sig);
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
||||
|
@ -85,8 +85,19 @@ App::~App () QSE_CPP_NOEXCEPT
|
||||
SigScopedMutexLocker sml(g_app_mutex);
|
||||
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->_prev_app) this->_prev_app->_next_app = this->_next_app;
|
||||
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)
|
||||
{
|
||||
// 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.
|
||||
if (app->_guarded_child_pid >= 0) app->on_guard_signal (sig);
|
||||
else app->on_signal (sig);
|
||||
app->on_signal (sig);
|
||||
}
|
||||
app = next;
|
||||
}
|
||||
@ -335,28 +346,28 @@ void App::on_guard_signal (int sig)
|
||||
::kill (this->_guarded_child_pid, sig);
|
||||
}
|
||||
|
||||
|
||||
App::SignalState App::getSignalSubscription (int sig) const
|
||||
{
|
||||
QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS);
|
||||
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);
|
||||
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];
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@ -375,9 +388,9 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
|
||||
sl._next = QSE_NULL;
|
||||
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);
|
||||
|
||||
App* xapp = g_app_sig[sig];
|
||||
@ -400,7 +413,7 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate)
|
||||
// roll back
|
||||
g_app_sig[sig] = xapp;
|
||||
if (xapp) xapp->_sig[sig]._prev = xapp_xprev;
|
||||
sl._state = SIGNAL_UNHANDLED;
|
||||
sl._state = SIGNAL_NEGLECTED;
|
||||
sl._next = QSE_NULL;
|
||||
QSE_ASSERT (sl._prev == QSE_NULL);
|
||||
return -1;
|
||||
@ -423,25 +436,36 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
|
||||
{
|
||||
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)
|
||||
{
|
||||
pid_t pid = ::fork();
|
||||
if (pid == -1) return -1;
|
||||
if (pid == 0)
|
||||
{
|
||||
::setpgid (0, 0); // change the process group id.
|
||||
break; // child
|
||||
}
|
||||
// child process
|
||||
this->_guarded_child_pid = -1;
|
||||
|
||||
for (int i = 0; i < QSE_NSIGS; i++)
|
||||
{
|
||||
if (signals.isSet(i))
|
||||
for (int i = 0; i < QSE_NSIGS; i++)
|
||||
{
|
||||
old_ss[i] = this->getSignalSubscription(i);
|
||||
this->setSignalSubscription (i, SIGNAL_ACCEPTED);
|
||||
if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]);
|
||||
}
|
||||
|
||||
::setpgid (0, 0); // change the process group id.
|
||||
break;
|
||||
}
|
||||
|
||||
// ===============================================
|
||||
// the guardian(parent) process
|
||||
// ===============================================
|
||||
this->_guarded_child_pid = pid;
|
||||
|
||||
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 (WEXITSTATUS(status) == 0)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ public:
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
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());
|
||||
this->server.stop();
|
||||
break;
|
||||
@ -103,20 +105,20 @@ MyApp app2 (&heap_mmgr);
|
||||
MyApp app3 (&heap_mmgr);
|
||||
MyApp app4 (&heap_mmgr);
|
||||
|
||||
app.subscribeToSignal (SIGINT, true);
|
||||
app.subscribeToSignal (SIGTERM, true);
|
||||
app.acceptSignal (SIGINT);
|
||||
app.acceptSignal (SIGTERM);
|
||||
|
||||
app4.subscribeToSignal (SIGINT, true);
|
||||
app3.subscribeToSignal (SIGINT, true);
|
||||
app2.subscribeToSignal (SIGINT, true);
|
||||
app4.acceptSignal (SIGINT);
|
||||
app3.acceptSignal (SIGINT);
|
||||
app2.acceptSignal (SIGINT);
|
||||
|
||||
int n = app.run();
|
||||
app.subscribeToSignal (SIGTERM, false);
|
||||
app.subscribeToSignal (SIGINT, false);
|
||||
app.discardSignal (SIGTERM);
|
||||
app.discardSignal (SIGINT);
|
||||
|
||||
app4.unsubscribeFromSignal (SIGINT);
|
||||
app3.unsubscribeFromSignal (SIGINT);
|
||||
app2.unsubscribeFromSignal (SIGINT);
|
||||
app4.neglectSignal (SIGINT);
|
||||
app3.neglectSignal (SIGINT);
|
||||
app2.neglectSignal (SIGINT);
|
||||
qse_printf (QSE_T("END OF %d\n"), (int)getpid());
|
||||
|
||||
return n;
|
||||
|
Loading…
Reference in New Issue
Block a user