attempted to fix various problems related to signals in App
This commit is contained in:
		| @ -39,7 +39,15 @@ QSE_BEGIN_NAMESPACE(QSE) | |||||||
| class App: public Uncopyable, public Types, public Mmged | class App: public Uncopyable, public Types, public Mmged | ||||||
| { | { | ||||||
| public: | 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; | 	App (Mmgr* mmgr) QSE_CPP_NOEXCEPT; | ||||||
| 	virtual ~App () QSE_CPP_NOEXCEPT; | 	virtual ~App () QSE_CPP_NOEXCEPT; | ||||||
| @ -56,10 +64,18 @@ public: | |||||||
|  |  | ||||||
| 	virtual void on_signal (int sig) { } | 	virtual void on_signal (int sig) { } | ||||||
|  |  | ||||||
| 	int subscribeToSignal (int sig, bool accept); | 	SignalState getSignalSubscription (int sig) const; | ||||||
| 	int subscribeToAllSignals (bool accept); | 	int setSignalSubscription (int sig, SignalState ss); | ||||||
| 	void unsubscribeFromSignal (int sig); |  | ||||||
| 	void unsubscribeFromAllSignals (); | 	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); | 	typedef void (*SignalHandler) (int sig); | ||||||
| 	static qse_size_t _sighrs[2][QSE_NSIGS]; | 	static qse_size_t _sighrs[2][QSE_NSIGS]; | ||||||
| @ -73,7 +89,7 @@ public: | |||||||
| 	static int setSignalHandler (int sig, SignalHandler sighr); | 	static int setSignalHandler (int sig, SignalHandler sighr); | ||||||
| 	static int unsetSignalHandler (int sig); | 	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: | private: | ||||||
| 	App* _prev_app; | 	App* _prev_app; | ||||||
| @ -81,17 +97,10 @@ private: | |||||||
|  |  | ||||||
| 	struct _SigLink | 	struct _SigLink | ||||||
| 	{ | 	{ | ||||||
| 		enum State | 		_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(SIGNAL_UNHANDLED) {} | ||||||
| 		{ |  | ||||||
| 			UNHANDLED, |  | ||||||
| 			ACCEPTED, |  | ||||||
| 			IGNORED // handled but ignored |  | ||||||
| 		}; |  | ||||||
|  |  | ||||||
| 		_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(UNHANDLED) {} |  | ||||||
| 		App* _prev; | 		App* _prev; | ||||||
| 		App* _next; | 		App* _next; | ||||||
| 		State _state; | 		SignalState _state; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	_SigLink _sig[QSE_NSIGS];  | 	_SigLink _sig[QSE_NSIGS];  | ||||||
| @ -101,7 +110,9 @@ 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); | 	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_signal_no_mutex (int sig); | ||||||
| 	void unsubscribe_from_all_signals_no_mutex (); | 	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) | 	if (sa.sa_flags & SA_SIGINFO) | ||||||
| 		sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))App::_sighrs[1][sig]; | 		sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))App::_sighrs[1][sig]; | ||||||
| 	else | 	else | ||||||
|  | 	{ | ||||||
| 		sa.sa_handler = (SignalHandler)App::_sighrs[1][sig]; | 		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; | 	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::_SigLink& sl = app->_sig[sig]; | ||||||
| 		App* next = sl._next; | 		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. | 			// the actual signal handler is called with the mutex locked. | ||||||
| 			// it must not call subscribeToSingal() or unsubscribeFromSingal() | 			// it must not call subscribeToSingal() or unsubscribeFromSingal() | ||||||
| 			// 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); | 			else app->on_signal (sig); | ||||||
| 		} | 		} | ||||||
| 		app = next; | 		app = next; | ||||||
| 	} | 	} | ||||||
| @ -297,73 +301,68 @@ printf ("relaying %d to %d\n", sig, (int)this->_guarded_child_pid); | |||||||
| 	::kill (this->_guarded_child_pid, sig); | 	::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); | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
| 	_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED; | 	return this->_sig[sig]._state; | ||||||
| 	ScopedMutexLocker sml(g_app_mutex); |  | ||||||
| 	return this->subscribe_to_signal_no_mutex(sig, reqstate); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int App::subscribeToAllSignals (bool accept) | int App::setSignalSubscription (int sig, SignalState ss) | ||||||
| { | { | ||||||
| 	_SigLink::State reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED; | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
| 	_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; |  | ||||||
|  |  | ||||||
| 					case _SigLink::ACCEPTED: | 	sigset_t sigset; | ||||||
| 					case _SigLink::IGNORED: | 	::sigemptyset (&sigset); | ||||||
| 						this->subscribe_to_signal_no_mutex (i, _old_state[i]); | 	::sigaddset (&sigset, sig); | ||||||
| 						break; | 	::sigprocmask (SIG_BLOCK, &sigset, QSE_NULL); | ||||||
| 				} |  | ||||||
| 			} | 	int n; | ||||||
| 			return -1;  | 	{ | ||||||
| 		} | 		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]; | 	_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); | 		QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL); | ||||||
|  |  | ||||||
| 		App* xapp = g_app_sig[sig]; | 		App* xapp = g_app_sig[sig]; | ||||||
| 		App* xapp_xprev = QSE_NULL; | 		App* xapp_xprev = QSE_NULL; | ||||||
|  |  | ||||||
| 		g_app_sig[sig] = this; | 		g_app_sig[sig] = this; | ||||||
| 		sl._state = _SigLink::ACCEPTED; | 		sl._state = SIGNAL_ACCEPTED; | ||||||
| 		sl._next = xapp; | 		sl._next = xapp; | ||||||
| 		if (xapp)  | 		if (xapp)  | ||||||
| 		{ | 		{ | ||||||
| @ -379,10 +378,58 @@ int App::subscribe_to_signal_no_mutex (int sig, _SigLink::State 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 = _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; | 				sl._next = QSE_NULL; | ||||||
| 				QSE_ASSERT (sl._prev == QSE_NULL); | 				QSE_ASSERT (sl._prev == QSE_NULL); | ||||||
| if (errno == EINVAL) return 0; /// dirty hack??? |  | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -397,14 +444,15 @@ if (errno == EINVAL) return 0; /// dirty hack??? | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| void App::unsubscribe_from_signal_no_mutex (int sig) | 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]; | 	_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 (g_app_sig[sig] != this); | ||||||
| 		QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL); | 		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; | 		if (sl._prev) sl._prev->_sig[sig]._next = sl._next; | ||||||
| 		sl._prev = QSE_NULL; | 		sl._prev = QSE_NULL; | ||||||
| 		sl._next = QSE_NULL; | 		sl._next = QSE_NULL; | ||||||
| 		sl._state = _SigLink::UNHANDLED; | 		sl._state = SIGNAL_UNHANDLED; | ||||||
| 	} | 	} | ||||||
|  | #endif | ||||||
| } | } | ||||||
|  |  | ||||||
| void App::unsubscribe_from_all_signals_no_mutex() | 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) | 	while (1) | ||||||
| 	{ | 	{ | ||||||
| 		pid_t pid = ::fork(); | 		pid_t pid = ::fork(); | ||||||
| 		if (pid == -1) return -1; | 		if (pid == -1) return -1; | ||||||
| 		if (pid == 0) break; // child | 		if (pid == 0) break; // child | ||||||
|  |  | ||||||
| //int _SigLink::State old_sig_states[QSE_NSIGS]; | 		for (int i = 0; i < QSE_NSIGS; i++) | ||||||
| //this->subscribeToAllSignals(true); | 		{ | ||||||
|  | 			if (signals.isSet(i))  | ||||||
|  | 			{ | ||||||
|  | 				old_ss[i] = this->getSignalSubscription(i); | ||||||
|  | 				this->setSignalSubscription (i, SIGNAL_ACCEPTED); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
| 		this->_guarded_child_pid = pid; | 		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; | 		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)  | 		if (WIFEXITED(status) && WEXITSTATUS(status) == 0)  | ||||||
| 		{ | 		{ | ||||||
| 			return 0;  | 			return 0;  | ||||||
|  | |||||||
| @ -67,7 +67,7 @@ public: | |||||||
| 			case SIGINT: | 			case SIGINT: | ||||||
| 			case SIGTERM: | 			case SIGTERM: | ||||||
| 			case SIGHUP: | 			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(); | 				this->server.stop(); | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| @ -75,7 +75,7 @@ public: | |||||||
|  |  | ||||||
| 	int run () | 	int run () | ||||||
| 	{ | 	{ | ||||||
| 		QSE::App::Sigset signals; | 		QSE::App::SignalSet signals; | ||||||
| 		signals.set (SIGINT); | 		signals.set (SIGINT); | ||||||
| 		signals.set (SIGHUP); | 		signals.set (SIGHUP); | ||||||
| 		signals.set (SIGTERM); | 		signals.set (SIGTERM); | ||||||
| @ -99,24 +99,26 @@ static int test1() | |||||||
| 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | ||||||
| 	MyApp app (&heap_mmgr); | 	MyApp app (&heap_mmgr); | ||||||
|  |  | ||||||
| //MyApp app2 (&heap_mmgr); | 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.subscribeToSignal (SIGINT, true); | ||||||
| 	app.subscribeToSignal (SIGTERM, true); | 	app.subscribeToSignal (SIGTERM, true); | ||||||
|  |  | ||||||
| //app4.subscribeToSignal (SIGINT, true);  | app4.subscribeToSignal (SIGINT, true);  | ||||||
| //app3.subscribeToSignal (SIGINT, true); | app3.subscribeToSignal (SIGINT, true); | ||||||
| //app2.subscribeToSignal (SIGINT, true); | app2.subscribeToSignal (SIGINT, true); | ||||||
|  |  | ||||||
| 	int n = app.run(); | 	int n = app.run(); | ||||||
| 	app.subscribeToSignal (SIGTERM, false); | 	app.subscribeToSignal (SIGTERM, false); | ||||||
| 	app.subscribeToSignal (SIGINT, false); | 	app.subscribeToSignal (SIGINT, false); | ||||||
|  |  | ||||||
| //app4.unsubscribeFromSignal (SIGINT);  | app4.unsubscribeFromSignal (SIGINT);  | ||||||
| //app3.unsubscribeFromSignal (SIGINT); | app3.unsubscribeFromSignal (SIGINT); | ||||||
| //app2.unsubscribeFromSignal (SIGINT); | app2.unsubscribeFromSignal (SIGINT); | ||||||
|  | qse_printf (QSE_T("END OF %d\n"), (int)getpid()); | ||||||
|  |  | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -132,7 +134,7 @@ int main () | |||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		sprintf (locale, ".%u", (unsigned int)codepage); | 		qse_mbsxfmt (locale, QSE_COUNTOF(locale), ".%u", (unsigned int)codepage); | ||||||
| 		setlocale (LC_ALL, locale); | 		setlocale (LC_ALL, locale); | ||||||
| 		/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | 		/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | ||||||
| 	} | 	} | ||||||
| @ -141,6 +143,7 @@ int main () | |||||||
| 	/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | 	/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| 	qse_open_stdsios (); | 	qse_open_stdsios (); | ||||||
| 	test1(); | 	test1(); | ||||||
| 	qse_close_stdsios (); | 	qse_close_stdsios (); | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user