added the ignore_if_unhandled parameter to App::neglectsignal().

added App::logfmt() and App::logfmtv()
added QSE::TcpServerFD<F,D> and  QSE::ThreadFD<F,D>
This commit is contained in:
hyung-hwan 2019-06-11 09:10:09 +00:00
parent 9a0f2e15b8
commit f95e9d36cf
8 changed files with 212 additions and 14 deletions

View File

@ -32,12 +32,20 @@
#include <qse/cmn/Mmged.hpp> #include <qse/cmn/Mmged.hpp>
#include <qse/cmn/Bitset.hpp> #include <qse/cmn/Bitset.hpp>
#include <qse/cmn/time.h> #include <qse/cmn/time.h>
#include <qse/si/Mutex.hpp>
#include <qse/si/os.h> #include <qse/si/os.h>
#include <stdarg.h>
///////////////////////////////// /////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE) 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 class App: public Uncopyable, public Types, public Mmged
{ {
public: public:
@ -94,19 +102,25 @@ public:
return this->setSignalSubscription(sig, SIGNAL_DISCARDED); 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); typedef void (*SignalHandler) (int sig);
static qse_size_t _sighrs[2][QSE_NSIGS]; static qse_size_t _sighrs[2][QSE_NSIGS];
// You may set a global signal handler with setSignalHandler(). // 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 // this function is doomed to fail. If a successful call to
// setSignalHandler() has been made withoutut unsetSingalHandler() called // setSignalHandler() has been made without unsetSingalHandler() called
// yet, a subsequence call to subscribeToSignal() is doomed to fail too. // yet, a subsequent call to subscribeToSignal() is doomed to fail too.
// These two different interfaces are mutually exclusive. // These two different interfaces are mutually exclusive.
static int setSignalHandler (int sig, SignalHandler sighr); static int setSignalHandler (int sig, SignalHandler sighr);
static int unsetSignalHandler (int sig, bool ignore = false); 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); 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: private:
App* _prev_app; App* _prev_app;
App* _next_app; App* _next_app;
@ -133,12 +195,26 @@ private:
_SigLink _sig[QSE_NSIGS]; _SigLink _sig[QSE_NSIGS];
long int _guarded_child_pid; 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 set_signal_handler_no_mutex (int sig, SignalHandler sighr);
static int unset_signal_handler_no_mutex (int sig, int ignore); 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); int set_signal_subscription_no_mutex (int sig, SignalState reqstate, bool ignore_if_unhandled);
void on_guard_signal (int sig); void on_guard_signal (int sig);
static void handle_signal (int sig); static void handle_signal (int sig);
static int put_char_to_log_buf (qse_char_t c, void* ctx);
}; };
///////////////////////////////// /////////////////////////////////

View File

@ -38,9 +38,9 @@ class Mutex: public Uncopyable
public: public:
friend class Condition; 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 ~Mutex() QSE_CPP_NOEXCEPT
{ {

View File

@ -256,7 +256,6 @@ protected:
friend class TcpServer::Worker; friend class TcpServer::Worker;
virtual int handle_worker (Worker* worker) = 0; virtual int handle_worker (Worker* worker) = 0;
private: private:
void delete_all_workers (Worker::State state) QSE_CPP_NOEXCEPT; 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)) {} TcpServerF (F&& f, Mmgr* mmgr = QSE_NULL) QSE_CPP_NOEXCEPT: TcpServer(mmgr), __lfunc(QSE_CPP_RVREF(f)) {}
#endif #endif
protected: private:
F __lfunc;
int handle_worker (Worker* worker)
{
return this->__lfunc(this, worker);
}
};
// functor + extra data in the functor
template <typename F, typename D>
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; F __lfunc;
int handle_worker (Worker* worker) int handle_worker (Worker* worker)
@ -346,7 +367,7 @@ public:
return 0; return 0;
} }
protected: private:
class Callable class Callable
{ {
public: public:

View File

@ -150,6 +150,33 @@ protected:
F __lfunc; F __lfunc;
}; };
template <typename F, typename D>
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<F,D>* t = (ThreadFD<F,D>*)ctx;
return t->__lfunc (t);
}
int start (int flags = 0) QSE_CPP_NOEXCEPT
{
return qse_thr_start (&this->thr, (qse_thr_rtn_t)ThreadFD<F,D>::call_func, this, flags);
}
protected:
F __lfunc;
};
#if defined(QSE_LANG_CPP11) #if defined(QSE_LANG_CPP11)
#if 0 #if 0

View File

@ -99,8 +99,10 @@ QSE_EXPORT int qse_wfmtout (
); );
#if defined(QSE_CHAR_IS_MCHAR) #if defined(QSE_CHAR_IS_MCHAR)
# define qse_fmtout_t qse_mfmtout_t
# define qse_fmtout(fmt,fo,ap) qse_mfmtout(fmt,fo,ap) # define qse_fmtout(fmt,fo,ap) qse_mfmtout(fmt,fo,ap)
#else #else
# define qse_fmtout_t qse_wfmtout_t
# define qse_fmtout(fmt,fo,ap) qse_wfmtout(fmt,fo,ap) # define qse_fmtout(fmt,fo,ap) qse_wfmtout(fmt,fo,ap)
#endif #endif

View File

@ -30,6 +30,7 @@
#include <qse/si/os.h> #include <qse/si/os.h>
#include "../cmn/syscall.h" #include "../cmn/syscall.h"
#include "../cmn/mem-prv.h" #include "../cmn/mem-prv.h"
#include "../cmn/fmt-prv.h"
#include <qse/cmn/mbwc.h> #include <qse/cmn/mbwc.h>
///////////////////////////////// /////////////////////////////////
@ -72,7 +73,7 @@ protected:
sigset_t oldsigset; 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); SigScopedMutexLocker sml(g_app_mutex);
if (!g_app_top) if (!g_app_top)
@ -467,6 +468,8 @@ int App::guardProcess (const SignalSet& signals, const qse_mchar_t* proc_name)
// child process // child process
this->_guarded_child_pid = -1; 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++) for (int i = 0; i < QSE_NSIGS; i++)
{ {
if (signals.isSet(i)) this->setSignalSubscription (i, old_ss[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. 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) QSE_END_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////

View File

@ -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); n = qse_mux_poll(this->listener_list.mux, QSE_NULL);
if (n <= -1) if (n <= -1)
{ {
this->setErrorCode (E_ESYSERR); // TODO: proper error code conversion qse_mux_errnum_t merr = qse_mux_geterrnum(this->listener_list.mux);
xret = -1; if (merr != QSE_MUX_EINTR)
break; {
this->setErrorCode (E_ESYSERR); // TODO: proper error code conversion
xret = -1;
break;
}
} }
} }

View File

@ -61,6 +61,12 @@ public:
} }
}; };
class FunctorWithI: public Functor
{
public:
FunctorWithI (int* x) {}
};
static int func_ptr (QSE::Thread* thr) static int func_ptr (QSE::Thread* thr)
{ {
int i = 0; int i = 0;
@ -185,6 +191,12 @@ static int test1 (void)
return -1; return -1;
} }
{
int t = 20;
QSE::ThreadFD<FunctorWithI, int*> thr7 (&t);
// just keep this here to see if QSE::ThreadFD<> can be instantiated syntatically
}
while (!g_stopreq) while (!g_stopreq)
{ {
if (thr1.getState() == QSE::Thread::TERMINATED && if (thr1.getState() == QSE::Thread::TERMINATED &&