enhancled the App class to support per-instance signal handler
This commit is contained in:
		| @ -38,8 +38,8 @@ QSE_BEGIN_NAMESPACE(QSE) | |||||||
| class App: public Uncopyable, public Types, public Mmged | class App: public Uncopyable, public Types, public Mmged | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false) {} | 	App (Mmgr* mmgr) QSE_CPP_NOEXCEPT; | ||||||
| 	~App () QSE_CPP_NOEXCEPT {} | 	virtual ~App () QSE_CPP_NOEXCEPT; | ||||||
|  |  | ||||||
| 	int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT; | 	int daemonize (bool chdir_to_root = true, int fork_count = 1) QSE_CPP_NOEXCEPT; | ||||||
|  |  | ||||||
| @ -51,14 +51,62 @@ public: | |||||||
| 	int restoreUser () QSE_CPP_NOEXCEPT; | 	int restoreUser () QSE_CPP_NOEXCEPT; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | 	virtual void on_signal (int sig) { } | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
| 	bool _root_only; | 	bool _root_only; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	App* _prev_app; | ||||||
|  | 	App* _next_app; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|  | 	struct _SigLink | ||||||
|  | 	{ | ||||||
|  | 		enum  | ||||||
|  | 		{ | ||||||
|  | 			UNHANDLED, | ||||||
|  | 			ACCEPTED, | ||||||
|  | 			IGNORED // handled but ignored | ||||||
|  | 		}; | ||||||
|  |  | ||||||
|  | 		_SigLink(): _prev(QSE_NULL), _next(QSE_NULL), _state(UNHANDLED) {} | ||||||
|  | 		App* _prev; | ||||||
|  | 		App* _next; | ||||||
|  | 		int  _state; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | 	_SigLink _sig[QSE_NSIGS];  | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
| 	typedef void (*SignalHandler) (int sig); | 	typedef void (*SignalHandler) (int sig); | ||||||
| 	static int setSignalHandler (int sig, SignalHandler sighr); | 	static int setSignalHandler (int sig, SignalHandler sighr); | ||||||
| 	static int unsetSignalHandler (int sig); | 	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); | ||||||
|  | 	void unhandleSignal (int sig); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // functor as a template parameter | ||||||
|  | template <typename F> | ||||||
|  | class QSE_EXPORT AppF: public App | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	AppF (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr) {} | ||||||
|  | 	AppF (const F& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr), __lfunc(f) {} | ||||||
|  | #if defined(QSE_CPP_ENABLE_CPP11_MOVE) | ||||||
|  | 	AppF (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: App(mmgr), __lfunc(QSE_CPP_RVREF(f)) {} | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	F __lfunc; | ||||||
|  |  | ||||||
|  | 	void on_signal (int sig) | ||||||
|  | 	{ | ||||||
|  | 		this->__lfunc(this, sig); | ||||||
|  | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include <qse/si/App.hpp> | #include <qse/si/App.hpp> | ||||||
|  | #include <qse/si/Mutex.hpp> | ||||||
| #include <qse/si/sinfo.h> | #include <qse/si/sinfo.h> | ||||||
| #include "../cmn/syscall.h" | #include "../cmn/syscall.h" | ||||||
| #include <qse/cmn/mbwc.h> | #include <qse/cmn/mbwc.h> | ||||||
| @ -33,6 +34,38 @@ | |||||||
| QSE_BEGIN_NAMESPACE(QSE) | QSE_BEGIN_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static Mutex g_app_mutex; | ||||||
|  | static App* g_app_top = QSE_NULL; // maintain the chain of application objects | ||||||
|  | static App* g_app_sig[QSE_NSIGS] = { QSE_NULL, }; | ||||||
|  | static struct | ||||||
|  | { | ||||||
|  | 	sigset_t sa_mask; | ||||||
|  | 	int      sa_flags; | ||||||
|  | } g_app_oldsi[QSE_NSIGS] = { { 0, 0 }, }; | ||||||
|  |  | ||||||
|  | App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _root_only(false), _prev_app(QSE_NULL), _next_app(QSE_NULL) | ||||||
|  | { | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	if (!g_app_top) | ||||||
|  | 	{ | ||||||
|  | 		g_app_top = this; | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		g_app_top->_prev_app = this; | ||||||
|  | 		this->_next_app = g_app_top; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | App::~App () QSE_CPP_NOEXCEPT  | ||||||
|  | { | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	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) 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 | ||||||
| { | { | ||||||
| 	if (this->_root_only && QSE_GETEUID() != 0) return -1; | 	if (this->_root_only && QSE_GETEUID() != 0) return -1; | ||||||
| @ -102,7 +135,6 @@ int App::daemonize (bool chdir_to_root, int fork_count) QSE_CPP_NOEXCEPT | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 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); | ||||||
| @ -169,14 +201,6 @@ static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // i don't want to use sigset_t in App.hpp. |  | ||||||
| // so i place oldsi here as a static variable instead of  |  | ||||||
| // static member variable of App |  | ||||||
| static struct |  | ||||||
| { |  | ||||||
| 	sigset_t sa_mask; |  | ||||||
| 	int      sa_flags; |  | ||||||
| } oldsi[QSE_NSIGS] = { { 0, 0 }, }; |  | ||||||
|  |  | ||||||
| int App::setSignalHandler (int sig, SignalHandler sighr) | int App::setSignalHandler (int sig, SignalHandler sighr) | ||||||
| { | { | ||||||
| @ -205,8 +229,8 @@ int App::setSignalHandler (int sig, SignalHandler sighr) | |||||||
|  |  | ||||||
| 	App::_sighrs[0][sig] = (qse_size_t)sighr; | 	App::_sighrs[0][sig] = (qse_size_t)sighr; | ||||||
| 	App::_sighrs[1][sig] = (qse_size_t)oldsa.sa_handler; | 	App::_sighrs[1][sig] = (qse_size_t)oldsa.sa_handler; | ||||||
| 	oldsi[sig].sa_mask = oldsa.sa_mask; | 	g_app_oldsi[sig].sa_mask = oldsa.sa_mask; | ||||||
| 	oldsi[sig].sa_flags = oldsa.sa_flags; | 	g_app_oldsi[sig].sa_flags = oldsa.sa_flags; | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -217,20 +241,97 @@ int App::unsetSignalHandler (int sig) | |||||||
|  |  | ||||||
| 	struct sigaction sa; | 	struct sigaction sa; | ||||||
|  |  | ||||||
| 	sa.sa_mask = oldsi[sig].sa_mask; | 	sa.sa_mask = g_app_oldsi[sig].sa_mask; | ||||||
| 	sa.sa_flags = oldsi[sig].sa_flags; | 	sa.sa_flags = g_app_oldsi[sig].sa_flags; | ||||||
| 	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]; | ||||||
|  |  | ||||||
| 	if (sigaction (sig, &sa, QSE_NULL) <= -1) return -1; | 	if (::sigaction (sig, &sa, QSE_NULL) <= -1) return -1; | ||||||
|  |  | ||||||
| 	App::_sighrs[0][sig] = 0; | 	App::_sighrs[0][sig] = 0; | ||||||
| 	App::_sighrs[1][sig] = 0; | 	App::_sighrs[1][sig] = 0; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void handle_signal (int sig) | ||||||
|  | { | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  | 	App* app = g_app_sig[sig]; | ||||||
|  | 	while (app) | ||||||
|  | 	{ | ||||||
|  | 		App::_SigLink& sl = app->_sig[sig]; | ||||||
|  | 		App* next = sl._next; | ||||||
|  | 		if (sl._state == App::_SigLink::ACCEPTED) app->on_signal (sig); | ||||||
|  | 		app = next; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void App::handleSignal (int sig, bool accept) | ||||||
|  | { | ||||||
|  | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
|  |  | ||||||
|  | 	int reqstate = accept? _SigLink::ACCEPTED: _SigLink::IGNORED; | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  |  | ||||||
|  | 	_SigLink& sl = this->_sig[sig]; | ||||||
|  | 	if (QSE_LIKELY(sl._state == _SigLink::UNHANDLED)) | ||||||
|  | 	{ | ||||||
|  | 		if (!g_app_sig[sig]) | ||||||
|  | 		{ | ||||||
|  | 			// no application is set to accept this signal. | ||||||
|  | 			// this is the first time to  | ||||||
|  | 			App::setSignalHandler (sig, handle_signal); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		sl._state = _SigLink::ACCEPTED; | ||||||
|  | 		sl._next = g_app_sig[sig]; | ||||||
|  | 		g_app_sig[sig] = this; | ||||||
|  | 	} | ||||||
|  | 	else  | ||||||
|  | 	{ | ||||||
|  | 		// already configured to receive the signal. | ||||||
|  | 		QSE_ASSERT (g_app_sig[sig] != QSE_NULL); | ||||||
|  | 		sl._state = reqstate; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void App::unhandleSignal (int sig) | ||||||
|  | { | ||||||
|  | 	QSE_ASSERT (sig >= 0 && sig < QSE_NSIGS); | ||||||
|  |  | ||||||
|  | 	ScopedMutexLocker sml(g_app_mutex); | ||||||
|  |  | ||||||
|  | 	_SigLink& sl = this->_sig[sig]; | ||||||
|  | 	if (QSE_UNLIKELY(sl._state == _SigLink::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) g_app_sig[sig] = sl._next; | ||||||
|  |  | ||||||
|  | 		if (sl._next)  | ||||||
|  | 		{ | ||||||
|  | 			sl._next->_sig[sig]._prev = sl._prev; | ||||||
|  | 			sl._next = QSE_NULL; | ||||||
|  | 		} | ||||||
|  | 		if (sl._prev) | ||||||
|  | 		{ | ||||||
|  | 			sl._prev->_sig[sig]._next = sl._next; | ||||||
|  | 			sl._prev = QSE_NULL; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (!g_app_sig[sig]) App::unsetSignalHandler (sig); | ||||||
|  | 		sl._state = _SigLink::UNHANDLED; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
| QSE_END_NAMESPACE(QSE) | QSE_END_NAMESPACE(QSE) | ||||||
| ///////////////////////////////// | ///////////////////////////////// | ||||||
|  | |||||||
| @ -18,10 +18,6 @@ | |||||||
|  |  | ||||||
| QSE::Mutex g_prt_mutex; | QSE::Mutex g_prt_mutex; | ||||||
|  |  | ||||||
| #if defined(QSE_LANG_CPP11) |  | ||||||
| QSE::TcpServerL<int(QSE::TcpServer::Worker*)>* g_server; |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| class ClientHandler | class ClientHandler | ||||||
| { | { | ||||||
| public: | public: | ||||||
| @ -55,10 +51,83 @@ public: | |||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #if defined(QSE_LANG_CPP11) | ||||||
|  | static QSE::TcpServerL<int(QSE::TcpServer::Worker*)>* g_server; | ||||||
|  | #else | ||||||
| static QSE::TcpServerF<ClientHandler>* g_server; | static QSE::TcpServerF<ClientHandler>* g_server; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MyApp: public QSE::App | ||||||
|  | { | ||||||
|  | public: | ||||||
|  | 	MyApp(QSE::Mmgr* mmgr): App(mmgr), server(mmgr) {} | ||||||
|  |  | ||||||
|  | 	void on_signal (int sig) | ||||||
|  | 	{ | ||||||
|  | 		switch (sig) | ||||||
|  | 		{ | ||||||
|  | 			case SIGINT: | ||||||
|  | 			case SIGTERM: | ||||||
|  | 			case SIGHUP: | ||||||
|  | 				this->server.stop(); | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	int run () | ||||||
|  | 	{ | ||||||
|  | 		this->server.setThreadStackSize (256000); | ||||||
|  | 		return this->server.start (QSE_T("[::]:9998,0.0.0.0:9998")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  | 	QSE::TcpServerF<ClientHandler> server; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int test1() | ||||||
|  | { | ||||||
|  | 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | ||||||
|  | 	MyApp app (&heap_mmgr); | ||||||
|  | 	app.handleSignal (SIGINT, true); | ||||||
|  | 	app.handleSignal (SIGTERM, true); | ||||||
|  | 	int n = app.run(); | ||||||
|  | 	app.handleSignal (SIGTERM, false); | ||||||
|  | 	app.handleSignal (SIGINT, false); | ||||||
|  | 	return n; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main () | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  |  	char locale[100]; | ||||||
|  | 	UINT codepage = GetConsoleOutputCP(); | ||||||
|  | 	if (codepage == CP_UTF8) | ||||||
|  | 	{ | ||||||
|  | 		/*SetConsoleOUtputCP (CP_UTF8);*/ | ||||||
|  | 		qse_setdflcmgrbyid (QSE_CMGR_UTF8); | ||||||
|  | 	} | ||||||
|  | 	else | ||||||
|  | 	{ | ||||||
|  | 		sprintf (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 (); | ||||||
|  | 	test1(); | ||||||
|  | 	qse_close_stdsios (); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if 0 //////////////////////// | ||||||
|  |  | ||||||
| static int test1 (void) | static int test1 (void) | ||||||
| { | { | ||||||
| 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | 	QSE::HeapMmgr heap_mmgr (QSE::Mmgr::getDFL(), 30000); | ||||||
| @ -96,7 +165,6 @@ static int test1 (void) | |||||||
| 		}), | 		}), | ||||||
|  |  | ||||||
| 		&heap_mmgr | 		&heap_mmgr | ||||||
|  |  | ||||||
| 	); | 	); | ||||||
| #else | #else | ||||||
| 	QSE::TcpServerF<ClientHandler> server (&heap_mmgr); | 	QSE::TcpServerF<ClientHandler> server (&heap_mmgr); | ||||||
| @ -139,12 +207,13 @@ int main () | |||||||
|  |  | ||||||
| 	qse_open_stdsios (); | 	qse_open_stdsios (); | ||||||
|  |  | ||||||
| 	QSE::App::setSignalHandler (SIGINT, handle_sigint); | 	//QSE::App::setSignalHandler (SIGINT, handle_sigint); | ||||||
| 	test1(); | 	test1(); | ||||||
| 	QSE::App::unsetSignalHandler (SIGINT); | 	//QSE::App::unsetSignalHandler (SIGINT); | ||||||
|  |  | ||||||
| 	qse_close_stdsios (); | 	qse_close_stdsios (); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #endif //////////////////////// | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user