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** 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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
@ -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,16 +436,6 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
|
|||||||
{
|
{
|
||||||
SignalState old_ss[QSE_NSIGS];
|
SignalState old_ss[QSE_NSIGS];
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
pid_t pid = ::fork();
|
|
||||||
if (pid == -1) return -1;
|
|
||||||
if (pid == 0)
|
|
||||||
{
|
|
||||||
::setpgid (0, 0); // change the process group id.
|
|
||||||
break; // child
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < QSE_NSIGS; i++)
|
for (int i = 0; i < QSE_NSIGS; i++)
|
||||||
{
|
{
|
||||||
if (signals.isSet(i))
|
if (signals.isSet(i))
|
||||||
@ -442,6 +445,27 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
pid_t pid = ::fork();
|
||||||
|
if (pid == -1) return -1;
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
// child process
|
||||||
|
this->_guarded_child_pid = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < QSE_NSIGS; i++)
|
||||||
|
{
|
||||||
|
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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user