From 6504a889e106d58eaccd1a9be9eebd90d29d9655 Mon Sep 17 00:00:00 2001 From: Max-Wilhelm Bruker Date: Wed, 6 Apr 2011 14:46:54 +0200 Subject: [PATCH] threaded logging; sigsegv handler to flush logfile before crashing --- servatrice/src/main.cpp | 22 +++++++++- servatrice/src/server_logger.cpp | 70 ++++++++++++++++++++++++++++---- servatrice/src/server_logger.h | 25 +++++++++++- 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index 9c4c25e5..e3eee892 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -32,6 +32,7 @@ RNG_Abstract *rng; ServerLogger *logger; +ServerLoggerThread *loggerThread; void testRNG() { @@ -72,6 +73,14 @@ void myMessageOutput(QtMsgType /*type*/, const char *msg) logger->logMessage(msg); } +void sigSegvHandler(int sig) +{ + logger->logMessage("SIGSEGV"); + usleep(1000); + delete loggerThread; + raise(sig); +} + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); @@ -86,7 +95,12 @@ int main(int argc, char *argv[]) QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); - logger = new ServerLogger(settings->value("server/logfile").toString()); + + loggerThread = new ServerLoggerThread(settings->value("server/logfile").toString()); + loggerThread->start(); + loggerThread->waitForInit(); + logger = loggerThread->getLogger(); + qInstallMsgHandler(myMessageOutput); #ifdef Q_OS_UNIX struct sigaction hup; @@ -95,6 +109,12 @@ int main(int argc, char *argv[]) hup.sa_flags = 0; hup.sa_flags |= SA_RESTART; sigaction(SIGHUP, &hup, 0); + + struct sigaction segv; + segv.sa_handler = sigSegvHandler; + segv.sa_flags = SA_RESETHAND; + sigemptyset(&segv.sa_mask); + sigaction(SIGSEGV, &segv, 0); #endif rng = new RNG_SFMT; diff --git a/servatrice/src/server_logger.cpp b/servatrice/src/server_logger.cpp index a8f7fed0..07ba4278 100644 --- a/servatrice/src/server_logger.cpp +++ b/servatrice/src/server_logger.cpp @@ -3,17 +3,14 @@ #include #include #include -#include -#ifdef Q_OS_UNIX #include #include -#endif ServerLogger::ServerLogger(const QString &logFileName, QObject *parent) - : QObject(parent) + : QObject(parent), flushRunning(false) { if (!logFileName.isEmpty()) { - logFile = new QFile(logFileName, this); + logFile = new QFile("server.log", this); logFile->open(QIODevice::Append); #ifdef Q_OS_UNIX ::socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFD); @@ -22,6 +19,8 @@ ServerLogger::ServerLogger(const QString &logFileName, QObject *parent) connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup())); } else logFile = 0; + + connect(this, SIGNAL(sigFlushBuffer()), this, SLOT(flushBuffer()), Qt::QueuedConnection); } ServerLogger::~ServerLogger() @@ -33,11 +32,33 @@ void ServerLogger::logMessage(QString message) if (!logFile) return; - logFileMutex.lock(); + bufferMutex.lock(); + buffer.append(QDateTime::currentDateTime().toString() + " " + QString::number((qulonglong) QThread::currentThread(), 16) + " " + message); + bufferMutex.unlock(); + + emit sigFlushBuffer(); +} + +void ServerLogger::flushBuffer() +{ + if (flushRunning) + return; + + flushRunning = true; QTextStream stream(logFile); - stream << QDateTime::currentDateTime().toString() << " " << ((void *) QThread::currentThread()) << " " << message << "\n"; - stream.flush(); - logFileMutex.unlock(); + forever { + bufferMutex.lock(); + if (buffer.isEmpty()) { + bufferMutex.unlock(); + flushRunning = false; + return; + } + QString message = buffer.takeFirst(); + bufferMutex.unlock(); + + stream << message << "\n"; + stream.flush(); + } } void ServerLogger::hupSignalHandler(int /*unused*/) @@ -66,3 +87,34 @@ void ServerLogger::handleSigHup() QFile *ServerLogger::logFile; int ServerLogger::sigHupFD[2]; + +ServerLoggerThread::ServerLoggerThread(const QString &_fileName, QObject *parent) + : QThread(parent), fileName(_fileName) +{ +} + +ServerLoggerThread::~ServerLoggerThread() +{ + quit(); + wait(); +} + +void ServerLoggerThread::run() +{ + logger = new ServerLogger(fileName); + + usleep(100); + initWaitCondition.wakeAll(); + + exec(); + + delete logger; +} + +void ServerLoggerThread::waitForInit() +{ + QMutex mutex; + mutex.lock(); + initWaitCondition.wait(&mutex); + mutex.unlock(); +} diff --git a/servatrice/src/server_logger.h b/servatrice/src/server_logger.h index 9ee519a7..3d3d4683 100644 --- a/servatrice/src/server_logger.h +++ b/servatrice/src/server_logger.h @@ -2,7 +2,10 @@ #define SERVER_LOGGER_H #include +#include #include +#include +#include class QSocketNotifier; class QFile; @@ -17,11 +20,31 @@ public slots: void logMessage(QString message); private slots: void handleSigHup(); + void flushBuffer(); +signals: + void sigFlushBuffer(); private: static int sigHupFD[2]; QSocketNotifier *snHup; static QFile *logFile; - QMutex logFileMutex; + bool flushRunning; + QStringList buffer; + QMutex bufferMutex; +}; + +class ServerLoggerThread : public QThread { + Q_OBJECT +private: + QString fileName; + ServerLogger *logger; + QWaitCondition initWaitCondition; +protected: + void run(); +public: + ServerLoggerThread(const QString &_fileName, QObject *parent = 0); + ~ServerLoggerThread(); + ServerLogger *getLogger() const { return logger; } + void waitForInit(); }; #endif