stablized the signal functions in the App class
This commit is contained in:
		| @ -76,7 +76,6 @@ public: | ||||
| 		return this->setSignalSubscription (sig, SIGNAL_UNHANDLED); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	typedef void (*SignalHandler) (int sig); | ||||
| 	static qse_size_t _sighrs[2][QSE_NSIGS]; | ||||
|  | ||||
| @ -87,7 +86,7 @@ public: | ||||
| 	// 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); | ||||
| 	static int unsetSignalHandler (int sig, bool ignore = false); | ||||
|  | ||||
| 	int guardProcess (const qse_mchar_t* proc_name, const SignalSet& signals); | ||||
|  | ||||
| @ -108,14 +107,10 @@ private: | ||||
|  | ||||
| protected: | ||||
| 	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 ignore); | ||||
|  | ||||
| 	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 (); | ||||
|  | ||||
| 	void on_guard_signal (int sig); | ||||
| 	static void handle_signal (int sig); | ||||
|  | ||||
|  | ||||
| @ -43,10 +43,34 @@ static struct | ||||
| 	sigset_t sa_mask; | ||||
| 	int      sa_flags; | ||||
| } g_app_oldsi[QSE_NSIGS] = { { 0, 0 }, }; | ||||
| static bool g_app_sigign_on_exit = false; | ||||
|  | ||||
| class SigScopedMutexLocker | ||||
| { | ||||
| public: | ||||
| 	SigScopedMutexLocker (Mutex& mutex): mutex(mutex) | ||||
| 	{ | ||||
| 		sigset_t sigset; | ||||
| 		::sigfillset (&sigset); | ||||
| 		::sigprocmask (SIG_BLOCK, &sigset, &this->oldsigset); | ||||
| // TODO: would this work properly if this is called within a thread? | ||||
| //       do i need to use pthread_sigmask() conditionally? | ||||
| 		this->mutex.lock (); | ||||
| 	} | ||||
|  | ||||
| 	~SigScopedMutexLocker () | ||||
| 	{ | ||||
| 		this->mutex.unlock (); | ||||
| 		::sigprocmask (SIG_SETMASK, &this->oldsigset, QSE_NULL); | ||||
| 	} | ||||
| protected: | ||||
| 	Mutex& mutex; | ||||
| 	sigset_t oldsigset; | ||||
| }; | ||||
|  | ||||
| App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _prev_app(QSE_NULL), _next_app(QSE_NULL), _guarded_child_pid(-1) | ||||
| { | ||||
| 	ScopedMutexLocker sml(g_app_mutex); | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	if (!g_app_top) | ||||
| 	{ | ||||
| 		g_app_top = this; | ||||
| @ -60,8 +84,11 @@ App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _prev_app(QSE_NULL), _next_ | ||||
|  | ||||
| App::~App () QSE_CPP_NOEXCEPT  | ||||
| { | ||||
| 	ScopedMutexLocker sml(g_app_mutex); | ||||
| 	this->unsubscribe_from_all_signals_no_mutex (); | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	for (int i = 0; i < QSE_NSIGS; i++) | ||||
| 	{ | ||||
| 		this->set_signal_subscription_no_mutex (i, SIGNAL_UNHANDLED); | ||||
| 	} | ||||
| 	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)  | ||||
| @ -207,7 +234,7 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx) | ||||
|  | ||||
| int App::setSignalHandler (int sig, SignalHandler sighr) | ||||
| { | ||||
| 	ScopedMutexLocker sml(g_app_mutex); | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	return App::set_signal_handler_no_mutex (sig, sighr); | ||||
| } | ||||
|  | ||||
| @ -222,13 +249,13 @@ int App::set_signal_handler_no_mutex (int sig, SignalHandler sighr) | ||||
| 	if (oldsa.sa_flags & SA_SIGINFO) | ||||
| 	{ | ||||
| 		sa.sa_sigaction = dispatch_siginfo; | ||||
| 		sigemptyset (&sa.sa_mask); | ||||
| 		::sigfillset (&sa.sa_mask); // block all signals while the handler is being executed | ||||
| 		sa.sa_flags |= SA_SIGINFO; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		sa.sa_handler = dispatch_signal; | ||||
| 		sigemptyset (&sa.sa_mask); | ||||
| 		::sigfillset (&sa.sa_mask);  | ||||
| 		sa.sa_flags = 0; | ||||
| 		//sa.sa_flags |= SA_INTERUPT; | ||||
| 		//sa.sa_flags |= SA_RESTART; | ||||
| @ -244,13 +271,13 @@ int App::set_signal_handler_no_mutex (int sig, SignalHandler sighr) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int App::unsetSignalHandler (int sig) | ||||
| int App::unsetSignalHandler (int sig, bool ignore) | ||||
| { | ||||
| 	ScopedMutexLocker sml(g_app_mutex); | ||||
| 	return App::unset_signal_handler_no_mutex(sig); | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	return App::unset_signal_handler_no_mutex(sig, ignore); | ||||
| } | ||||
|  | ||||
| int App::unset_signal_handler_no_mutex(int sig) | ||||
| int App::unset_signal_handler_no_mutex(int sig, int ignore) | ||||
| { | ||||
| 	if (!App::_sighrs[0][sig]) return -1; | ||||
|  | ||||
| @ -258,13 +285,18 @@ int App::unset_signal_handler_no_mutex(int sig) | ||||
|  | ||||
| 	sa.sa_mask = g_app_oldsi[sig].sa_mask; | ||||
| 	sa.sa_flags = g_app_oldsi[sig].sa_flags; | ||||
| 	if (sa.sa_flags & SA_SIGINFO) | ||||
| 	if (ignore) | ||||
| 	{ | ||||
| 		sa.sa_handler = SIG_IGN; | ||||
| 		sa.sa_flags &= ~SA_SIGINFO; | ||||
| 	} | ||||
| 	else 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; | ||||
| @ -274,10 +306,15 @@ sa.sa_handler = SIG_IGN; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /*static*/ void App::handle_signal (int sig) | ||||
| { | ||||
| 	ScopedMutexLocker sml(g_app_mutex); | ||||
| 	// Note: i use ScopedMutexLocker in the signal handler | ||||
| 	//       whereas I use SigScopedMutexLocker in other functions.  | ||||
| 	//       as SigScopedMutexLock blocks all signals, this signal handler | ||||
| 	//       is not called while those other functions are holding on to | ||||
| 	//       this mutex object. | ||||
| 	ScopedMutexLocker sml(g_app_mutex);  | ||||
|  | ||||
| 	App* app = g_app_sig[sig]; | ||||
| 	while (app) | ||||
| 	{ | ||||
| @ -311,20 +348,8 @@ App::SignalState App::getSignalSubscription (int sig) const | ||||
| int App::setSignalSubscription (int sig, SignalState ss) | ||||
| { | ||||
| 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
|  | ||||
| 	::sigprocmask (SIG_UNBLOCK, &sigset, QSE_NULL); | ||||
| 	return n; | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	return this->set_signal_subscription_no_mutex(sig, ss); | ||||
| } | ||||
|  | ||||
| int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate) | ||||
| @ -342,7 +367,7 @@ 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) <= -1) return -1; | ||||
| 				if (App::unset_signal_handler_no_mutex(sig, true) <= -1) return -1; | ||||
| 			} | ||||
| 			g_app_sig[sig] = sl._next; | ||||
| 		} | ||||
| @ -372,7 +397,7 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate) | ||||
| 		else | ||||
| 		{ | ||||
| 			// no application is set to accept this signal. | ||||
| 			// this is the first time to  | ||||
| 			// it is the first time to set the system-level signal handler. | ||||
| 			if (App::set_signal_handler_no_mutex(sig, App::handle_signal) <= -1) | ||||
| 			{ | ||||
| 				// roll back  | ||||
| @ -397,95 +422,6 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState 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); | ||||
| 				return -1; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		QSE_ASSERT (sl._prev == QSE_NULL); | ||||
| 	} | ||||
| 	else  | ||||
| 	{ | ||||
| 		// already configured to receive the signal. change the state only | ||||
| 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | ||||
| 		sl._state = reqstate; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void App::unsubscribe_from_signal_no_mutex (int sig) | ||||
| { | ||||
| 	this->set_signal_subscription_no_mutex (sig, SIGNAL_UNHANDLED); | ||||
| #if 0 | ||||
| 	_SigLink& sl = this->_sig[sig]; | ||||
| 	if (QSE_UNLIKELY(sl._state == SIGNAL_UNHANDLED)) | ||||
| 	{ | ||||
| 		QSE_ASSERT (g_app_sig[sig] != this); | ||||
| 		QSE_ASSERT (sl._prev == QSE_NULL && sl._next == QSE_NULL); | ||||
| 		// nothing to do | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | ||||
|  | ||||
| 		if (g_app_sig[sig] == this)  | ||||
| 		{ | ||||
| 			QSE_ASSERT (sl._prev == QSE_NULL); | ||||
| 			if (!sl._next) App::unset_signal_handler_no_mutex (sig); | ||||
| 			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 = SIGNAL_UNHANDLED; | ||||
| 	} | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void App::unsubscribe_from_all_signals_no_mutex() | ||||
| { | ||||
| 	for (int i = 0; i < QSE_NSIGS; i++) | ||||
| 	{ | ||||
| 		this->unsubscribe_from_signal_no_mutex (i); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int App::guardProcess (const qse_mchar_t* proc_name, const SignalSet& signals) | ||||
| { | ||||
| 	SignalState old_ss[QSE_NSIGS]; | ||||
|  | ||||
| @ -147,7 +147,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -274,7 +274,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -129,7 +129,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
| @ -150,96 +150,3 @@ int main () | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| #if 0 //////////////////////// | ||||
|  | ||||
| static int test1 (void) | ||||
| { | ||||
| 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | ||||
|  | ||||
| #if defined(QSE_LANG_CPP11) | ||||
| 	QSE::TcpServerL<int(QSE::TcpServer::Worker*)> server ( | ||||
|  | ||||
| 		// workload by lambda | ||||
| 		([&server](QSE::TcpServer::Worker* worker) { | ||||
| 			qse_char_t addrbuf[128]; | ||||
| 			qse_uint8_t bb[256]; | ||||
| 			qse_ssize_t n; | ||||
|  | ||||
| 			worker->address.toStrBuf(addrbuf, QSE_COUNTOF(addrbuf)); | ||||
| 			g_prt_mutex.lock(); | ||||
| 			qse_printf (QSE_T("hello word..from %s -> wid %zu\n"), addrbuf, worker->getWid()); | ||||
| 			g_prt_mutex.unlock(); | ||||
|  | ||||
| 			while (!server.isStopRequested()) | ||||
| 			{ | ||||
| 				if ((n = worker->socket.receive(bb, QSE_COUNTOF(bb))) <= 0)  | ||||
| 				{ | ||||
| 					g_prt_mutex.lock(); | ||||
| 					qse_printf (QSE_T("%zd bytes received from %s\n"), n, addrbuf); | ||||
| 					g_prt_mutex.unlock(); | ||||
| 					break; | ||||
| 				} | ||||
| 				worker->socket.send (bb, n); | ||||
| 			} | ||||
|  | ||||
| 			g_prt_mutex.lock(); | ||||
| 			qse_printf (QSE_T("byte to %s -> wid %zu\n"), addrbuf, worker->getWid()); | ||||
| 			g_prt_mutex.unlock(); | ||||
| 			return 0; | ||||
| 		}), | ||||
|  | ||||
| 		&heap_mmgr | ||||
| 	); | ||||
| #else | ||||
| 	QSE::TcpServerF<ClientHandler> server (&heap_mmgr); | ||||
| #endif | ||||
|  | ||||
| 	server.setThreadStackSize (256000); | ||||
| 	g_server = &server; | ||||
| 	//server.start (QSE_T("0.0.0.0:9998")); | ||||
| 	server.start (QSE_T("[::]:9998,0.0.0.0:9998")); | ||||
| 	//server.start (QSE_T("[fe80::1c4:a90d:a0f0:d52%wlan0]:9998,0.0.0.0:9998")); | ||||
| 	g_server = QSE_NULL; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void handle_sigint (int sig) | ||||
| { | ||||
| 	if (g_server) g_server->stop (); | ||||
| } | ||||
|   | ||||
| int main () | ||||
| { | ||||
| #if defined(_WIN32) | ||||
|  	char locale[100]; | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		qse_mbsxfmt (locale, QSE_COUNTOF(locale), ".%u", (unsigned int)codepage); | ||||
| 		setlocale (LC_ALL, locale); | ||||
| 		/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | ||||
| 	} | ||||
| #else | ||||
| 	setlocale (LC_ALL, ""); | ||||
| 	/*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ | ||||
| #endif | ||||
|  | ||||
| 	qse_open_stdsios (); | ||||
|  | ||||
| 	//QSE::App::setSignalHandler (SIGINT, handle_sigint); | ||||
| 	test1(); | ||||
| 	//QSE::App::unsetSignalHandler (SIGINT); | ||||
|  | ||||
| 	qse_close_stdsios (); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| #endif //////////////////////// | ||||
|  | ||||
| @ -126,7 +126,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -117,7 +117,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -263,7 +263,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
| @ -158,7 +158,7 @@ int main () | ||||
| 	UINT codepage = GetConsoleOutputCP(); | ||||
| 	if (codepage == CP_UTF8) | ||||
| 	{ | ||||
| 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||
| 		/*SetConsoleOutputCP (CP_UTF8);*/ | ||||
| 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||
| 	} | ||||
| 	else | ||||
|  | ||||
		Reference in New Issue
	
	Block a user