renamed some signal handling functions in the App class
This commit is contained in:
		| @ -102,6 +102,7 @@ struct qse_cli_data_t | ||||
| 	const qse_char_t** optsta; | ||||
| 	const qse_char_t*  optasn; | ||||
| 	qse_cli_opt_t*     opts; | ||||
| 	void*              ctx; | ||||
|  | ||||
| }; | ||||
| typedef struct qse_cli_data_t qse_cli_data_t; | ||||
|  | ||||
| @ -43,12 +43,11 @@ public: | ||||
|  | ||||
| 	enum SignalState | ||||
| 	{ | ||||
| 		SIGNAL_UNHANDLED, | ||||
| 		SIGNAL_ACCEPTED, | ||||
| 		SIGNAL_IGNORED // handled but ignored | ||||
| 		SIGNAL_NEGLECTED, // signal is unhandled at the system level. | ||||
| 		SIGNAL_ACCEPTED,  // on_signal callback is triggered | ||||
| 		SIGNAL_DISCARDED  // handled but doesn't trigger the on_signal callback | ||||
| 	}; | ||||
|  | ||||
|  | ||||
| 	App (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT; | ||||
| 	virtual ~App () QSE_CPP_NOEXCEPT; | ||||
|  | ||||
| @ -65,15 +64,21 @@ public: | ||||
| 	virtual void on_signal (int sig) { } | ||||
|  | ||||
| 	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); | ||||
| @ -96,7 +101,7 @@ private: | ||||
|  | ||||
| 	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* _next; | ||||
| 		SignalState _state; | ||||
| @ -105,15 +110,12 @@ private: | ||||
| 	_SigLink _sig[QSE_NSIGS];  | ||||
| 	long int _guarded_child_pid; | ||||
|  | ||||
| protected: | ||||
| 	static int set_signal_handler_no_mutex (int sig, SignalHandler sighr); | ||||
| 	static int unset_signal_handler_no_mutex (int sig, int ignore); | ||||
|  | ||||
| 	int set_signal_subscription_no_mutex (int sig, SignalState reqstate); | ||||
| 	int set_signal_subscription_no_mutex (int sig, SignalState reqstate, bool ignore_if_unhandled); | ||||
|  | ||||
| 	void on_guard_signal (int sig); | ||||
| 	static void handle_signal (int sig); | ||||
|  | ||||
| }; | ||||
|  | ||||
| ///////////////////////////////// | ||||
|  | ||||
| @ -85,8 +85,19 @@ App::~App () QSE_CPP_NOEXCEPT | ||||
| 	SigScopedMutexLocker sml(g_app_mutex); | ||||
| 	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->_prev_app) this->_prev_app->_next_app = this->_next_app; | ||||
| 	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)  | ||||
| 		{ | ||||
| 			// 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. | ||||
| 			if (app->_guarded_child_pid >= 0) app->on_guard_signal (sig); | ||||
| 			else app->on_signal (sig); | ||||
| 			app->on_signal (sig); | ||||
| 		} | ||||
| 		app = next; | ||||
| 	} | ||||
| @ -335,28 +346,28 @@ void App::on_guard_signal (int sig) | ||||
| 	::kill (this->_guarded_child_pid, sig); | ||||
| } | ||||
|  | ||||
|  | ||||
| App::SignalState App::getSignalSubscription (int sig) const | ||||
| { | ||||
| 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||
| 	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); | ||||
| 	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]; | ||||
|  | ||||
| 	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); | ||||
|  | ||||
| 		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); | ||||
| 			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; | ||||
| 		} | ||||
| @ -375,9 +388,9 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate) | ||||
| 		sl._next = QSE_NULL; | ||||
| 		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); | ||||
|  | ||||
| 		App* xapp = g_app_sig[sig]; | ||||
| @ -400,7 +413,7 @@ int App::set_signal_subscription_no_mutex (int sig, SignalState reqstate) | ||||
| 				// roll back  | ||||
| 				g_app_sig[sig] = xapp; | ||||
| 				if (xapp) xapp->_sig[sig]._prev = xapp_xprev; | ||||
| 				sl._state = SIGNAL_UNHANDLED; | ||||
| 				sl._state = SIGNAL_NEGLECTED; | ||||
| 				sl._next = QSE_NULL; | ||||
| 				QSE_ASSERT (sl._prev == QSE_NULL); | ||||
| 				return -1; | ||||
| @ -423,25 +436,36 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name) | ||||
| { | ||||
| 	SignalState old_ss[QSE_NSIGS]; | ||||
|  | ||||
| 	for (int i = 0; i < QSE_NSIGS; i++) | ||||
| 	{ | ||||
| 		if (signals.isSet(i))  | ||||
| 		{ | ||||
| 			old_ss[i] = this->getSignalSubscription(i); | ||||
| 			this->setSignalSubscription (i, SIGNAL_ACCEPTED); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		pid_t pid = ::fork(); | ||||
| 		if (pid == -1) return -1; | ||||
| 		if (pid == 0)  | ||||
| 		{ | ||||
| 			::setpgid (0, 0); // change the process group id.  | ||||
| 			break; // child | ||||
| 		} | ||||
| 			// child process | ||||
| 			this->_guarded_child_pid = -1; | ||||
|  | ||||
| 		for (int i = 0; i < QSE_NSIGS; i++) | ||||
| 		{ | ||||
| 			if (signals.isSet(i))  | ||||
| 			for (int i = 0; i < QSE_NSIGS; i++) | ||||
| 			{ | ||||
| 				old_ss[i] = this->getSignalSubscription(i); | ||||
| 				this->setSignalSubscription (i, SIGNAL_ACCEPTED); | ||||
| 				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; | ||||
|  | ||||
| 		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 (WEXITSTATUS(status) == 0)  | ||||
| 			{ | ||||
| 				// 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;  | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @ -67,6 +67,8 @@ public: | ||||
| 			case SIGINT: | ||||
| 			case SIGTERM: | ||||
| 			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()); | ||||
| 				this->server.stop(); | ||||
| 				break; | ||||
| @ -103,20 +105,20 @@ MyApp app2 (&heap_mmgr); | ||||
| MyApp app3 (&heap_mmgr); | ||||
| MyApp app4 (&heap_mmgr); | ||||
|  | ||||
| 	app.subscribeToSignal (SIGINT, true); | ||||
| 	app.subscribeToSignal (SIGTERM, true); | ||||
| 	app.acceptSignal (SIGINT); | ||||
| 	app.acceptSignal (SIGTERM); | ||||
|  | ||||
| app4.subscribeToSignal (SIGINT, true);  | ||||
| app3.subscribeToSignal (SIGINT, true); | ||||
| app2.subscribeToSignal (SIGINT, true); | ||||
| app4.acceptSignal (SIGINT); | ||||
| app3.acceptSignal (SIGINT); | ||||
| app2.acceptSignal (SIGINT); | ||||
|  | ||||
| 	int n = app.run(); | ||||
| 	app.subscribeToSignal (SIGTERM, false); | ||||
| 	app.subscribeToSignal (SIGINT, false); | ||||
| 	app.discardSignal (SIGTERM); | ||||
| 	app.discardSignal (SIGINT); | ||||
|  | ||||
| app4.unsubscribeFromSignal (SIGINT);  | ||||
| app3.unsubscribeFromSignal (SIGINT); | ||||
| app2.unsubscribeFromSignal (SIGINT); | ||||
| app4.neglectSignal (SIGINT);  | ||||
| app3.neglectSignal (SIGINT); | ||||
| app2.neglectSignal (SIGINT); | ||||
| qse_printf (QSE_T("END OF %d\n"), (int)getpid()); | ||||
|  | ||||
| 	return n; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user