diff --git a/qse/include/qse/si/App.hpp b/qse/include/qse/si/App.hpp index f041b4a4..8899cccf 100644 --- a/qse/include/qse/si/App.hpp +++ b/qse/include/qse/si/App.hpp @@ -39,7 +39,15 @@ QSE_BEGIN_NAMESPACE(QSE) class App: public Uncopyable, public Types, public Mmged { public: - typedef QSE::Bitset Sigset; + typedef QSE::Bitset 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 (); diff --git a/qse/lib/si/App.cpp b/qse/lib/si/App.cpp index 61a7301e..7aac162a 100644 --- a/qse/lib/si/App.cpp +++ b/qse/lib/si/App.cpp @@ -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; diff --git a/qse/samples/si/tcpsvr01.cpp b/qse/samples/si/tcpsvr01.cpp index beb34859..d905361d 100644 --- a/qse/samples/si/tcpsvr01.cpp +++ b/qse/samples/si/tcpsvr01.cpp @@ -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 ();