From f95e9d36cf87bb6c63f029ca814b416a959a59a9 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Tue, 11 Jun 2019 09:10:09 +0000 Subject: [PATCH] added the ignore_if_unhandled parameter to App::neglectsignal(). added App::logfmt() and App::logfmtv() added QSE::TcpServerFD and QSE::ThreadFD --- qse/include/qse/si/App.hpp | 86 ++++++++++++++++++++++++++++++-- qse/include/qse/si/Mutex.hpp | 4 +- qse/include/qse/si/TcpServer.hpp | 27 ++++++++-- qse/include/qse/si/Thread.hpp | 27 ++++++++++ qse/lib/cmn/fmt-prv.h | 2 + qse/lib/si/App.cpp | 58 ++++++++++++++++++++- qse/lib/si/TcpServer.cpp | 10 ++-- qse/samples/si/thr02.cpp | 12 +++++ 8 files changed, 212 insertions(+), 14 deletions(-) diff --git a/qse/include/qse/si/App.hpp b/qse/include/qse/si/App.hpp index 9d54f976..e612ea18 100644 --- a/qse/include/qse/si/App.hpp +++ b/qse/include/qse/si/App.hpp @@ -32,12 +32,20 @@ #include #include #include +#include #include +#include ///////////////////////////////// QSE_BEGIN_NAMESPACE(QSE) ///////////////////////////////// +#define QSE_APP_LOG_ENABLED(app, mask) (((app)->getLogMask() & mask) == mask) +#define QSE_APP_LOG0(app, mask, fmt) do { if (QSE_APP_LOG_ENABLED(app, mask)) app->logfmt(mask, fmt); } while(0) +#define QSE_APP_LOG1(app, mask, fmt, a1) do { if (QSE_APP_LOG_ENABLED(app, mask)) app->logfmt(mask, fmt, a1); } while(0) +#define QSE_APP_LOG2(app, mask, fmt, a1, a2) do { if (QSE_APP_LOG_ENABLED(app, mask)) app->logfmt(mask, fmt, a1, a2); } while(0) +#define QSE_APP_LOG3(app, mask, fmt, a1, a2, a3) do { if (QSE_APP_LOG_ENABLED(app, mask)) app->logfmt(mask, fmt, a1, a2, a3); } while(0) + class App: public Uncopyable, public Types, public Mmged { public: @@ -94,19 +102,25 @@ public: return this->setSignalSubscription(sig, SIGNAL_DISCARDED); } - int neglectSignal (int sig) + // The neglectSignal() function restored the signal handler + // to the previous signal handler remembered. If no signal + // handler was set up before this application object has been + // initialized, no signal handler is established for the given + // signal. the ignore_if_unhandled is true, this function + // sets up signal handle to ignore the handler instead. + int neglectSignal (int sig, bool ignore_if_unhandled = false) { - return this->setSignalSubscription(sig, SIGNAL_NEGLECTED); + return this->setSignalSubscription(sig, SIGNAL_NEGLECTED, ignore_if_unhandled); } typedef void (*SignalHandler) (int sig); static qse_size_t _sighrs[2][QSE_NSIGS]; // You may set a global signal handler with setSignalHandler(). - // If an application is subscribing to a single with subscribeToSignal(), + // If an application is subscribing to a signal 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. + // setSignalHandler() has been made without unsetSingalHandler() called + // yet, a subsequent 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, bool ignore = false); @@ -118,6 +132,54 @@ public: int guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name = QSE_NULL); + + // ============================================================= + // LOGGING SUPPORT + // ============================================================= + + enum log_mask_t + { + LOG_DEBUG = (1 << 0), + LOG_INFO = (1 << 1), + LOG_WARN = (1 << 2), + LOG_ERROR = (1 << 3), + LOG_FATAL = (1 << 4), + + LOG_TYPE_0 = (1 << 6), + LOG_TYPE_1 = (1 << 7), + LOG_TYPE_2 = (1 << 8), + LOG_TYPE_3 = (1 << 9), + LOG_TYPE_4 = (1 << 10), + LOG_TYPE_5 = (1 << 11), + LOG_TYPE_6 = (1 << 12), + LOG_TYPE_7 = (1 << 13), + LOG_TYPE_8 = (1 << 14), + LOG_TYPE_9 = (1 << 15), + + LOG_ALL_LEVELS = (LOG_DEBUG | LOG_INFO | LOG_WARN | LOG_ERROR | LOG_FATAL), + LOG_ALL_TYPES = (LOG_TYPE_0 | LOG_TYPE_1 | LOG_TYPE_2 | LOG_TYPE_3 | LOG_TYPE_4 | LOG_TYPE_5 | LOG_TYPE_6 | LOG_TYPE_7 | LOG_TYPE_8 | LOG_TYPE_9) + }; + + void setLogMask (int mask) { this->_log.mask = mask; } + int getLogMask () const { return this->_log.mask; } + + void logfmt (int mask, const qse_char_t* fmt, ...) + { + va_list ap; + va_start (ap, fmt); + logfmtv (mask, fmt, ap); + va_end (ap); + } + + void logfmtv (int mask, const qse_char_t* fmt, va_list ap); + +protected: + virtual void log_write (int mask, const qse_char_t* msg, qse_size_t len) + { + // do nothing + // subclasses should override this if needed. + } + private: App* _prev_app; App* _next_app; @@ -133,12 +195,26 @@ private: _SigLink _sig[QSE_NSIGS]; long int _guarded_child_pid; + struct log_t + { + log_t (App* app): mask(0), last_mask(0), len(0), mtx(app->getMmgr()) + { + } + + int mask, last_mask; + qse_size_t len; + qse_char_t buf[256]; + QSE::Mutex mtx; + } _log; + 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, bool ignore_if_unhandled); void on_guard_signal (int sig); static void handle_signal (int sig); + + static int put_char_to_log_buf (qse_char_t c, void* ctx); }; ///////////////////////////////// diff --git a/qse/include/qse/si/Mutex.hpp b/qse/include/qse/si/Mutex.hpp index 90dfeb5a..969c46dc 100644 --- a/qse/include/qse/si/Mutex.hpp +++ b/qse/include/qse/si/Mutex.hpp @@ -38,9 +38,9 @@ class Mutex: public Uncopyable public: friend class Condition; - Mutex() QSE_CPP_NOEXCEPT + Mutex (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT { - qse_mtx_init (&this->mtx, QSE_NULL); + qse_mtx_init (&this->mtx, mmgr); } ~Mutex() QSE_CPP_NOEXCEPT { diff --git a/qse/include/qse/si/TcpServer.hpp b/qse/include/qse/si/TcpServer.hpp index 13ada45d..175eec2f 100644 --- a/qse/include/qse/si/TcpServer.hpp +++ b/qse/include/qse/si/TcpServer.hpp @@ -256,7 +256,6 @@ protected: friend class TcpServer::Worker; virtual int handle_worker (Worker* worker) = 0; - private: void delete_all_workers (Worker::State state) QSE_CPP_NOEXCEPT; @@ -283,7 +282,29 @@ public: TcpServerF (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(QSE_CPP_RVREF(f)) {} #endif -protected: +private: + F __lfunc; + + int handle_worker (Worker* worker) + { + return this->__lfunc(this, worker); + } +}; + +// functor + extra data in the functor +template +class QSE_EXPORT TcpServerFD: public TcpServer +{ +public: + TcpServerFD (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr) {} + TcpServerFD (const F& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(f) {} + TcpServerFD (const D& d, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(d) {} +#if defined(QSE_CPP_ENABLE_CPP11_MOVE) + TcpServerFD (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(QSE_CPP_RVREF(f)) {} + TcpServerFD (D&& d, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(QSE_CPP_RVREF(d)) {} +#endif + +private: F __lfunc; int handle_worker (Worker* worker) @@ -346,7 +367,7 @@ public: return 0; } -protected: +private: class Callable { public: diff --git a/qse/include/qse/si/Thread.hpp b/qse/include/qse/si/Thread.hpp index 69eec4e2..6b71a9dd 100644 --- a/qse/include/qse/si/Thread.hpp +++ b/qse/include/qse/si/Thread.hpp @@ -150,6 +150,33 @@ protected: F __lfunc; }; +template +class QSE_EXPORT ThreadFD: public Thread +{ +public: + ThreadFD (Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: Thread(mmgr) {} + ThreadFD (const F& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: Thread(mmgr), __lfunc(f) {} + ThreadFD (const D& d, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: Thread(mmgr), __lfunc(d) {} +#if defined(QSE_CPP_ENABLE_CPP11_MOVE) + ThreadFD (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: Thread(mmgr), __lfunc(QSE_CPP_RVREF(f)) {} + ThreadFD (D&& d, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: Thread(mmgr), __lfunc(QSE_CPP_RVREF(d)) {} +#endif + + static int call_func (qse_thr_t* thr, void* ctx) + { + ThreadFD* t = (ThreadFD*)ctx; + return t->__lfunc (t); + } + + int start (int flags = 0) QSE_CPP_NOEXCEPT + { + return qse_thr_start (&this->thr, (qse_thr_rtn_t)ThreadFD::call_func, this, flags); + } + +protected: + F __lfunc; +}; + #if defined(QSE_LANG_CPP11) #if 0 diff --git a/qse/lib/cmn/fmt-prv.h b/qse/lib/cmn/fmt-prv.h index 0c31aafb..1b54803e 100644 --- a/qse/lib/cmn/fmt-prv.h +++ b/qse/lib/cmn/fmt-prv.h @@ -99,8 +99,10 @@ QSE_EXPORT int qse_wfmtout ( ); #if defined(QSE_CHAR_IS_MCHAR) +# define qse_fmtout_t qse_mfmtout_t # define qse_fmtout(fmt,fo,ap) qse_mfmtout(fmt,fo,ap) #else +# define qse_fmtout_t qse_wfmtout_t # define qse_fmtout(fmt,fo,ap) qse_wfmtout(fmt,fo,ap) #endif diff --git a/qse/lib/si/App.cpp b/qse/lib/si/App.cpp index 2dabdd5f..ccc50aaf 100644 --- a/qse/lib/si/App.cpp +++ b/qse/lib/si/App.cpp @@ -30,6 +30,7 @@ #include #include "../cmn/syscall.h" #include "../cmn/mem-prv.h" +#include "../cmn/fmt-prv.h" #include ///////////////////////////////// @@ -72,7 +73,7 @@ protected: sigset_t oldsigset; }; -App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _prev_app(QSE_NULL), _next_app(QSE_NULL), _guarded_child_pid(-1) +App::App (Mmgr* mmgr) QSE_CPP_NOEXCEPT: Mmged(mmgr), _prev_app(QSE_NULL), _next_app(QSE_NULL), _guarded_child_pid(-1), _log(this) { SigScopedMutexLocker sml(g_app_mutex); if (!g_app_top) @@ -467,6 +468,8 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name) // child process this->_guarded_child_pid = -1; + // the child process has inherited the signal handlers. + // restore the signal handlers of the child process to the original handlers. for (int i = 0; i < QSE_NSIGS; i++) { if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[i]); @@ -519,6 +522,59 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name) return seq; // the caller must execute the actual work. } + +int App::put_char_to_log_buf (qse_char_t c, void* ctx) +{ + App* app = (App*)ctx; + if (app->_log.len >= QSE_COUNTOF(app->_log.buf) - 1) // -1 for the lien terminator appending in App::logfmtv() + { + app->log_write (app->_log.last_mask, app->_log.buf, app->_log.len); + app->_log.len = 0; + } + + app->_log.buf[app->_log.len++] = c; + if (c == QSE_T('\n')) + { + app->log_write (app->_log.last_mask, app->_log.buf, app->_log.len); + app->_log.len = 0; + } + + return 1; +} + +void App::logfmtv (int mask, const qse_char_t* fmt, va_list ap) +{ + /*if (this->threaded)*/ this->_log.mtx.lock (); + + if (this->_log.len > 0 && this->_log.last_mask != mask) + { + if (this->_log.buf[this->_log.len - 1] != QSE_T('\n')) + { + // no line ending - append a line terminator + this->_log.buf[this->_log.len++] = QSE_T('\n'); + } + this->log_write (this->_log.last_mask, this->_log.buf, this->_log.len); + this->_log.len = 0; + } + + qse_fmtout_t fo; + + fo.count = 0; + fo.limit = QSE_TYPE_MAX(qse_size_t) - 1; + fo.ctx = this; + fo.put = put_char_to_log_buf; +#if defined(QSE_CHAR_IS_WCHAR) + fo.conv = QSE_NULL; +#else + fo.conv = QSE_NULL; +#endif + + this->_log.last_mask = mask; + qse_fmtout(fmt, &fo, ap); + + /*if (this->threaded)*/ this->_log.mtx.unlock (); +} + ///////////////////////////////// QSE_END_NAMESPACE(QSE) ///////////////////////////////// diff --git a/qse/lib/si/TcpServer.cpp b/qse/lib/si/TcpServer.cpp index 7479fdbe..c25ee168 100644 --- a/qse/lib/si/TcpServer.cpp +++ b/qse/lib/si/TcpServer.cpp @@ -401,9 +401,13 @@ int TcpServer::start (const qse_char_t* addrs) QSE_CPP_NOEXCEPT n = qse_mux_poll(this->listener_list.mux, QSE_NULL); if (n <= -1) { - this->setErrorCode (E_ESYSERR); // TODO: proper error code conversion - xret = -1; - break; + qse_mux_errnum_t merr = qse_mux_geterrnum(this->listener_list.mux); + if (merr != QSE_MUX_EINTR) + { + this->setErrorCode (E_ESYSERR); // TODO: proper error code conversion + xret = -1; + break; + } } } diff --git a/qse/samples/si/thr02.cpp b/qse/samples/si/thr02.cpp index a241e0ea..166d775f 100644 --- a/qse/samples/si/thr02.cpp +++ b/qse/samples/si/thr02.cpp @@ -61,6 +61,12 @@ public: } }; +class FunctorWithI: public Functor +{ +public: + FunctorWithI (int* x) {} +}; + static int func_ptr (QSE::Thread* thr) { int i = 0; @@ -185,6 +191,12 @@ static int test1 (void) return -1; } + { + int t = 20; + QSE::ThreadFD thr7 (&t); + // just keep this here to see if QSE::ThreadFD<> can be instantiated syntatically + } + while (!g_stopreq) { if (thr1.getState() == QSE::Thread::TERMINATED &&