fixed some bugs in the signal related functions of the QSE::App class
This commit is contained in:
		| @ -78,15 +78,27 @@ public: | |||||||
|  |  | ||||||
| 	_SigLink _sig[QSE_NSIGS];  | 	_SigLink _sig[QSE_NSIGS];  | ||||||
|  |  | ||||||
| public: |  | ||||||
|  |  | ||||||
| 	typedef void (*SignalHandler) (int sig); | 	typedef void (*SignalHandler) (int sig); | ||||||
| 	static int setSignalHandler (int sig, SignalHandler sighr); |  | ||||||
| 	static int unsetSignalHandler (int sig); |  | ||||||
| 	static qse_size_t _sighrs[2][QSE_NSIGS]; | 	static qse_size_t _sighrs[2][QSE_NSIGS]; | ||||||
|  |  | ||||||
| 	void handleSignal (int sig, bool accept); | 	int subscribeToSignal (int sig, bool accept); | ||||||
| 	void unhandleSignal (int sig); | 	void unsubscribeFromSignal (int sig); | ||||||
|  |  | ||||||
|  | 	// You may set a global signal handler with setSignalHandler(). | ||||||
|  | 	// If an application is subscribing to a single with subscribeToSignal(), | ||||||
|  | 	// this function is doomed to fail. If a successful call to  | ||||||
|  | 	// setSignalHandler() has been made withoutut unsetSingalHandler() called | ||||||
|  | 	// yet, a subsequence call to subscribeToSignal() is doomed to fail too. | ||||||
|  | 	// These two different interfaces are mutually exclusive. | ||||||
|  | 	static int setSignalHandler (int sig, SignalHandler sighr); | ||||||
|  | 	static int unsetSignalHandler (int sig); | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	static int set_signal_handler_no_mutex (int sig, SignalHandler sighr); | ||||||
|  | 	static int unset_signal_handler_no_mutex (int sig); | ||||||
|  |  | ||||||
|  | 	void unsubscribe_from_signal_no_mutex (int sig); | ||||||
|  | 	void unsubscribe_from_all_signals_no_mutex (); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // functor as a template parameter | // functor as a template parameter | ||||||
|  | |||||||
| @ -417,7 +417,7 @@ | |||||||
| #if defined(SYS_rename) && defined(QSE_USE_SYSCALL) | #if defined(SYS_rename) && defined(QSE_USE_SYSCALL) | ||||||
| #	define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath) | #	define QSE_RENAME(oldpath,newpath) syscall(SYS_rename,oldpath,newpath) | ||||||
| #else | #else | ||||||
| 	int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */ | 	extern int rename(const char *oldpath, const char *newpath); /* not to include stdio.h */ | ||||||
| #	define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath) | #	define QSE_RENAME(oldpath,newpath) rename(oldpath,newpath) | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -34,7 +34,6 @@ | |||||||
| QSE_BEGIN_NAMESPACE(QSE) | QSE_BEGIN_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  |  | ||||||
|  |  | ||||||
| static Mutex g_app_mutex; | static Mutex g_app_mutex; | ||||||
| static App* g_app_top = QSE_NULL; // maintain the chain of application objects | static App* g_app_top = QSE_NULL; // maintain the chain of application objects | ||||||
| static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, }; | static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, }; | ||||||
| @ -61,9 +60,14 @@ App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false), _prev_ap | |||||||
| App::~App () QSE_CPP_NOEXCEPT  | App::~App () QSE_CPP_NOEXCEPT  | ||||||
| { | { | ||||||
| 	ScopedMutexLocker sml(g_app_mutex); | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	this->unsubscribe_from_all_signals_no_mutex (); | ||||||
| 	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) g_app_top = this->_next_app; | 	if (this == g_app_top)  | ||||||
|  | 	{ | ||||||
|  | 		QSE_ASSERT (this->_prev_app == QSE_NULL); | ||||||
|  | 		g_app_top = this->_next_app; | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | ||||||
| @ -134,10 +138,9 @@ int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int App::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT | int App::chroot (const qse_mchar_t* mpath) QSE_CPP_NOEXCEPT | ||||||
| { | { | ||||||
| 	return QSE_CHROOT (mpath); | 	return QSE_CHROOT(mpath); | ||||||
| } | } | ||||||
|  |  | ||||||
| int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT | int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT | ||||||
| @ -145,7 +148,7 @@ int App::chroot (const qse_wchar_t* wpath) QSE_CPP_NOEXCEPT | |||||||
| 	qse_mchar_t* mpath; | 	qse_mchar_t* mpath; | ||||||
| 	mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr()); | 	mpath = qse_wcstombsdup (wpath, QSE_NULL, this->getMmgr()); | ||||||
| 	if (!mpath) return -1; | 	if (!mpath) return -1; | ||||||
| 	int n = App::chroot ((const qse_mchar_t*)mpath); | 	int n = App::chroot((const qse_mchar_t*)mpath); | ||||||
| 	this->getMmgr()->dispose (mpath); | 	this->getMmgr()->dispose (mpath); | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
| @ -201,8 +204,13 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| int App::setSignalHandler (int sig, SignalHandler sighr) | int App::setSignalHandler (int sig, SignalHandler sighr) | ||||||
|  | { | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	return App::set_signal_handler_no_mutex (sig, sighr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int App::set_signal_handler_no_mutex (int sig, SignalHandler sighr) | ||||||
| { | { | ||||||
| 	if (App::_sighrs[0][sig]) return -1; // already set | 	if (App::_sighrs[0][sig]) return -1; // already set | ||||||
|  |  | ||||||
| @ -236,6 +244,12 @@ int App::setSignalHandler (int sig, SignalHandler sighr) | |||||||
| } | } | ||||||
|  |  | ||||||
| int App::unsetSignalHandler (int sig) | int App::unsetSignalHandler (int sig) | ||||||
|  | { | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	return App::unset_signal_handler_no_mutex(sig); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int App::unset_signal_handler_no_mutex(int sig) | ||||||
| { | { | ||||||
| 	if (!App::_sighrs[0][sig]) return -1; | 	if (!App::_sighrs[0][sig]) return -1; | ||||||
|  |  | ||||||
| @ -268,7 +282,7 @@ static void handle_signal (int sig) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| void App::handleSignal (int sig, bool accept) | int App::subscribeToSignal (int sig, bool accept) | ||||||
| { | { | ||||||
| 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
|  |  | ||||||
| @ -278,31 +292,56 @@ void App::handleSignal (int sig, bool accept) | |||||||
| 	_SigLink& sl = this->_sig[sig]; | 	_SigLink& sl = this->_sig[sig]; | ||||||
| 	if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED)) | 	if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED)) | ||||||
| 	{ | 	{ | ||||||
| 		if (!g_app_sig[sig]) | 		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._next = xapp; | ||||||
|  | 		if (xapp)  | ||||||
|  | 		{ | ||||||
|  | 			xapp_xprev = xapp->_sig[sig]._prev; | ||||||
|  | 			xapp->_sig[sig]._prev = this; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
| 		{ | 		{ | ||||||
| 			// no application is set to accept this signal. | 			// no application is set to accept this signal. | ||||||
| 			// this is the first time to  | 			// this is the first time to  | ||||||
| 			App::setSignalHandler (sig, handle_signal); | 			if (App::set_signal_handler_no_mutex(sig, handle_signal) <= -1) | ||||||
|  | 			{ | ||||||
|  | 				// roll back  | ||||||
|  | 				g_app_sig[sig] = xapp; | ||||||
|  | 				if (xapp) xapp->_sig[sig]._prev = xapp_xprev; | ||||||
|  | 				sl._state = _SigLink::UNHANDLED; | ||||||
|  | 				sl._next = QSE_NULL; | ||||||
|  | 				QSE_ASSERT (sl._prev == QSE_NULL); | ||||||
|  | 				return -1; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		sl._state = _SigLink::ACCEPTED; | 		QSE_ASSERT (sl._prev == QSE_NULL); | ||||||
| 		sl._next = g_app_sig[sig]; |  | ||||||
| 		g_app_sig[sig] = this; |  | ||||||
| 	} | 	} | ||||||
| 	else  | 	else  | ||||||
| 	{ | 	{ | ||||||
| 		// already configured to receive the signal. | 		// already configured to receive the signal. change the state only | ||||||
| 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | ||||||
| 		sl._state = reqstate; | 		sl._state = reqstate; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| void App::unhandleSignal (int sig) | void App::unsubscribeFromSignal (int sig) | ||||||
| { | { | ||||||
| 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
|  |  | ||||||
| 	ScopedMutexLocker sml(g_app_mutex); | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	this->unsubscribe_from_signal_no_mutex (sig); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void App::unsubscribe_from_signal_no_mutex (int sig) | ||||||
|  | { | ||||||
| 	_SigLink& sl = this->_sig[sig]; | 	_SigLink& sl = this->_sig[sig]; | ||||||
| 	if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED)) | 	if (QSE_UNLIKELY(sl._state == _SigLink::UNHANDLED)) | ||||||
| 	{ | 	{ | ||||||
| @ -314,24 +353,29 @@ void App::unhandleSignal (int sig) | |||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | ||||||
|  |  | ||||||
| 		if (g_app_sig[sig] == this) g_app_sig[sig] = sl._next; | 		if (g_app_sig[sig] == this)  | ||||||
|  |  | ||||||
| 		if (sl._next)  |  | ||||||
| 		{ | 		{ | ||||||
| 			sl._next->_sig[sig]._prev = sl._prev; | 			QSE_ASSERT (sl._prev == QSE_NULL); | ||||||
| 			sl._next = QSE_NULL; | 			g_app_sig[sig] = sl._next; | ||||||
| 		} |  | ||||||
| 		if (sl._prev) |  | ||||||
| 		{ |  | ||||||
| 			sl._prev->_sig[sig]._next = sl._next; |  | ||||||
| 			sl._prev = QSE_NULL; |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (!g_app_sig[sig]) App::unsetSignalHandler (sig); | 		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; | ||||||
|  |  | ||||||
|  | 		if (!g_app_sig[sig]) App::unset_signal_handler_no_mutex (sig); | ||||||
| 		sl._state = _SigLink::UNHANDLED; | 		sl._state = _SigLink::UNHANDLED; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void App::unsubscribe_from_all_signals_no_mutex() | ||||||
|  | { | ||||||
|  | 	for (int i = 0; i < QSE_NSIGS; i++) | ||||||
|  | 	{ | ||||||
|  | 		this->unsubscribe_from_signal_no_mutex (i); | ||||||
|  | 	} | ||||||
|  | } | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
| QSE_END_NAMESPACE(QSE) | QSE_END_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  | |||||||
| @ -70,6 +70,9 @@ public: | |||||||
| 			case SIGINT: | 			case SIGINT: | ||||||
| 			case SIGTERM: | 			case SIGTERM: | ||||||
| 			case SIGHUP: | 			case SIGHUP: | ||||||
|  | 				g_prt_mutex.lock(); | ||||||
|  | 				qse_printf (QSE_T("requesting to stop server...app %p server %p\n"), this, &this->server); | ||||||
|  | 				g_prt_mutex.unlock(); | ||||||
| 				this->server.stop(); | 				this->server.stop(); | ||||||
| 				break; | 				break; | ||||||
| 		} | 		} | ||||||
| @ -89,11 +92,27 @@ 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); | ||||||
| 	app.handleSignal (SIGINT, true); |  | ||||||
| 	app.handleSignal (SIGTERM, true); | 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); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 	int n = app.run(); | 	int n = app.run(); | ||||||
| 	app.handleSignal (SIGTERM, false); | 	app.subscribeToSignal (SIGTERM, false); | ||||||
| 	app.handleSignal (SIGINT, false); | 	app.subscribeToSignal (SIGINT, false); | ||||||
|  |  | ||||||
|  | app4.unsubscribeFromSignal (SIGINT);  | ||||||
|  | app3.unsubscribeFromSignal (SIGINT); | ||||||
|  | app2.unsubscribeFromSignal (SIGINT); | ||||||
| 	return n; | 	return n; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user