ReMemoryAppender(int maxLines);
~ReMemoryAppender();
public:
- virtual void say(ReLogger* logger, const char* message);
ReByteBuffer& join(ReByteBuffer& buffer, bool append = false);
+ virtual void say(ReLogger* logger, const char* message);
protected:
int m_maxLines;
};
* This appender writes the messages to another logger.
*
* This is useful in multithreaded applications: There is one "normal logger"
- * in the main thread and each other thread have its own logger with a
- * <code>ReSlaveAppender</code> which write to the main logger.
+ * called "master logger" in the main thread and each other thread has its
+ * own logger with a <code>ReSlaveAppender</code> which write to the
+ * master logger.
*
* Reason: Because of the architecture of the argument handling
* (<code>say().arg().end()</code> it is not possible to protect the argument
public:
ReSlaveAppender(ReLogger* masterLogger, char charPrefix = '\0');
virtual ~ReSlaveAppender();
-public:
public:
virtual void say(ReLogger* logger, const char* message);
+ /** Sets the master logger.
+ * @param logger the master logger
+ */
+ void setMasterLogger(ReLogger* logger){
+ m_masterLogger = logger;
+ }
private:
ReLogger* m_masterLogger;
char m_charPrefix;
#include "base/rebase.hpp"
+enum RELOC_SEQARRAY {
+ LC_LOGGER_1 = LC_LOGGER + 1, // 50701
+};
#ifdef __linux__
extern size_t strftime (char* s, size_t maxsize, const char* format, const struct tm* tp);
#endif
m_stdConsoleAppender(NULL),
m_stdFileAppender(NULL),
m_locationOfOpenSayF(0),
- m_mutex(),
+ m_mutex(LC_LOGGER_1, 10),
m_charPrefix('\0') {
- sem_init(&m_mutex, 0, 1);
if (isGlobal) {
delete m_globalLogger;
m_globalLogger = this;
m_appenderListSize = 0;
if (m_globalLogger == this)
m_globalLogger = NULL;
- sem_destroy(&m_mutex);
}
/** @brief Issues a log message.
*
*/
bool ReLogger::say(ReClassCategoryGranularity mode, ReLogLocation location,
const char* message) {
- sem_wait(&m_mutex);
+ m_mutex.wait();
m_mode = mode;
m_location = location;
m_standardPrefix[0] = '\0';
if (app->accept(mode))
app->say(this, message);
}
- sem_post(&m_mutex);
+ m_mutex.release();
return true;
}
/** @brief Issues a log message.
*/
bool ReLogger::say(char prefix, ReClassCategoryGranularity mode,
ReLogLocation location, const char* message) {
- sem_wait(&m_mutex);
+ m_mutex.wait();
char safePrefix = m_charPrefix;
m_charPrefix = prefix;
m_mode = mode;
app->say(this, message);
}
m_charPrefix = safePrefix;
- sem_post(&m_mutex);
+ m_mutex.release();
return true;
}
*/
ReVarArgs& ReLogger::sayF(ReClassCategoryGranularity mode,
ReLogLocation location, const char* format) {
- sem_wait(&m_mutex);
+ m_mutex.wait();
if (m_locationOfOpenSayF != 0) {
char message[128];
_snprintf(message, sizeof message,
m_location = location;
m_standardPrefix[0] = '\0';
reset(format);
- sem_post(&m_mutex);
+ m_mutex.release();
return *this;
}
/** Adds an appender to the appender list.
ReAppender* m_stdConsoleAppender;
ReFileAppender* m_stdFileAppender;
int m_locationOfOpenSayF;
- ReMutex_t m_mutex;
+ ReMutex m_mutex;
char m_charPrefix;
private:
--- /dev/null
+/*
+ * ReMutex.cpp
+ *
+ * License: Public domain
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * The latest sources: https://github.com/republib
+ */
+
+#include "base/rebase.hpp"
+
+/**
+ * Constructor.
+ *
+ * @param maxWaitSec maximal timeout. If reached an error occurres
+ */
+ReMutex::ReMutex(int location, int maxWaitSec) :
+#if defined __linux__
+ m_mutex(),
+#elif defined __WIN32__
+ m_mutex(0),
+#endif
+ m_maxWaitSec(maxWaitSec){
+#if defined __linux__
+ sem_init(&m_mutex, 0, 0);
+#elif defined __WIN32__
+ m_mutex = CreateMutex(NULL, FALSE, NULL);
+#endif
+}
+
+/**
+ * Destructor.
+ */
+ReMutex::~ReMutex() {
+#if defined __linux__
+ sem_destroy(&m_mutex);
+#elif defined __WIN32__
+ CloseMutex(m_mutex);
+#endif
+}
+
+bool ReMutex::timedWait(int sec){
+ bool rc = true;
+#if defined __linux__
+ struct timespec time;
+ time.tv_sec = sec;
+ time.tv_nsec = 0;
+ rc = sem_timedwait(&m_mutex, &time) == 0;
+#elif defined __WIN32__
+
+#endif
+ return rc;
+}
--- /dev/null
+/*
+ * ReMutex.hpp
+ *
+ * License: Public domain
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * The latest sources: https://github.com/republib
+ */
+
+#ifndef BASE_REMUTEX_HPP_
+#define BASE_REMUTEX_HPP_
+
+class ReMutex {
+public:
+ ReMutex(int location, int maxWaitSec = -1);
+ virtual ~ReMutex();
+public:
+ inline void release(){
+#if defined __linux__
+ sem_post(&m_mutex);
+#elif defined __WIN32__
+#error "mutex in ReMutex missed"
+#endif
+ }
+ bool timedWait(int sec = -1);
+ inline void wait(){
+#if defined __linux__
+ sem_wait(&m_mutex);
+#elif defined __WIN32__
+#error "mutex in ReMutex missed"
+#endif
+ }
+private:
+#if defined __linux__
+ sem_t m_mutex;
+#elif defined __WIN32__
+ HANDLE m_mutex;
+#endif
+ int m_maxWaitSec;
+};
+
+#endif /* BASE_REMUTEX_HPP_ */
#include "base/rebase.hpp"\r
\r
enum RELOC_HASHLIST {\r
- LC_SET_MASTER_LOGGER_1 = LC_THREAD + 1, // 50601\r
+ LC_PREPARE_TO_RUN_1 = LC_THREAD + 1, // 50601\r
LC_START_THREAD_1, // 50602\r
+ LC_NE_1, // 50603\r
};\r
\r
+\r
/**\r
* Constructor.\r
+ *\r
+ * @param autodelete <code>true</code>: the <code>ReThreadStarter</code>\r
+ * deletes the instance when it is stopped\r
*/\r
-ReThread::ReThread() :\r
- m_logger(false),\r
- m_appender(NULL){\r
+ReThread::ReThread(bool autoDelete) :\r
+ m_threadId(-1),\r
+ m_threadLogger(false),\r
+ m_appender(NULL),\r
+ m_starter(NULL),\r
+#if defined __linux__\r
+ m_threadInfo(),\r
+#elif defined __WIN32__\r
+ m_threadInfo(UNDEF_HANDLE),\r
+#endif\r
+ m_shouldStop(false),\r
+ m_isStopped(false),\r
+ m_autoDelete(autoDelete){\r
+#if defined __linux__\r
+ memset(&m_threadInfo, 0, sizeof m_threadInfo);\r
+#endif\r
}\r
/**\r
* Destructor.\r
ReThread::~ReThread(){\r
}\r
\r
-void ReThread::setMasterLogger(ReLogger* masterLogger){\r
- if (m_appender == NULL){\r
- m_appender = new ReSlaveAppender(masterLogger);\r
+/**\r
+ * Prepares the thread for running.\r
+ *\r
+ * Should only called by <code>ReThredStarter()</code>\r
+ *\r
+ * @param id the thread id\r
+ * @param masterLogger the logger for error handling\r
+ * @param starter the instance which has started the thread\r
+ */\r
+bool ReThread::prepareToRun(int id, ReLogger* masterLogger,\r
+ ReThreadStarter* starter){\r
+ bool rc = false;\r
+ if (m_starter != NULL){\r
+ globalLogger()->say(LOG_ERROR | CAT_LIB, LC_PREPARE_TO_RUN_1,\r
+ i18n("setMasterLogger() is called multiple times"));\r
} else {\r
- globalLogger()->say(LOG_ERROR | CAT_LIB, LC_NEXT_1,\r
- i18n("setMasterLogger() is called multiple times"));\r
+ m_threadId = id;\r
+ m_appender->setMasterLogger(masterLogger);\r
+ m_starter = starter;\r
+ rc = true;\r
}\r
}\r
\r
/**\r
* Constructor.\r
+ *\r
+ * @param maxThreads the maximal number of threads\r
+ * @param logger the (master) logger for error handling\r
*/\r
-ReThreadStarter::ReThreadStarter(ReLogger* logger) :\r
- m_id(0),\r
- m_logger(logger){\r
+ReThreadStarter::ReThreadStarter(int maxThreads, ReLogger* logger) :\r
+ m_nextId(0),\r
+ m_logger(logger),\r
+ m_maxThreads(maxThreads){\r
+ m_threads = new ReThread*[maxThreads];\r
+ memset(m_threads, 0, maxThreads * sizeof *m_threads);\r
}\r
/**\r
* Destructor.\r
*\r
* @param thread the\r
*/\r
-void ReThreadStarter::startThread(ReThread& thread){\r
- thread.setId(++m_nextId);\r
- thread.setMasterLogger(m_logger);\r
- bool error;\r
+bool ReThreadStarter::startThread(ReThread& thread){\r
+ bool ok = false;\r
+ if (thread.prepareToRun(++m_nextId, m_logger, this)){\r
#if defined __linux__\r
- pthread_t sniffer_thread;\r
- error = (pthread_create(&sniffer_thread, NULL, starterFunction,\r
- (void*) thread) < 0;\r
-\r
-#else defined __WIN32__\r
- HANDLE threadHandle;\r
- error = (threadHandle = CreateThread(NULL, 0, starterFunction,\r
- &thread, 0)) == NULL;\r
+ pthread_t sniffer_thread;\r
+ ok = pthread_create(&sniffer_thread, NULL, starterFunction,\r
+ reinterpret_cast<void*>(&thread)) >= 0;\r
+#elif defined __WIN32__\r
+ HANDLE threadHandle;\r
+ ok = (threadHandle = CreateThread(NULL, 0, starterFunction,\r
+ &thread, 0)) != NULL;\r
#endif\r
- if (error)\r
- m_logger->sayF(LOG_ERROR | CAT_PROCESS,\r
- LC_START_THREAD_1,\r
- i18n("cannot create a thread: $1")).arg(\r
- getLastOSError()).end();\r
-\r
+ if (! ok)\r
+ m_logger->sayF(LOG_ERROR | CAT_PROCESS,\r
+ LC_START_THREAD_1,\r
+ i18n("cannot create a thread: $1")).arg(\r
+ getLastOSError()).end();\r
+ }\r
+ return ok;\r
}\r
#ifndef BASE_RETHREAD_HPP_\r
#define BASE_RETHREAD_HPP_\r
\r
+class ReThreadStarter;\r
+class ReSlaveAppender;\r
/**\r
* Abstract base class for threads\r
*\r
*/\r
class ReThread {\r
public:\r
- ReThread();\r
+ ReThread(bool autoDelete);\r
virtual ~ReThread();\r
private:\r
friend class ReThreadStarter;\r
- void setId(int id);\r
- void setMasterLogger(ReLogger* masterLogger);\r
+ bool prepareToRun(int id, ReLogger* masterLogger,\r
+ ReThreadStarter* starter);\r
public:\r
virtual void run() = 0;\r
+ /** Returns if the thread is stopped.\r
+ * @return <code>true</code>the thread is stopped\r
+ */\r
+ inline bool isStopped() const{\r
+ return m_isStopped;\r
+ }\r
+ /** Sets the wish for stopping the thread.\r
+ * @param value <code>true</code>: the thread should stop as soon as possible\r
+ */\r
+ inline bool setShouldStop(bool value){\r
+ m_shouldStop = value;\r
+ }\r
protected:\r
- int m_id;\r
- ReLogger m_logger;\r
+ int m_threadId;\r
+ ReLogger m_threadLogger;\r
ReSlaveAppender* m_appender;\r
+ ReThreadStarter* m_starter;\r
+#if defined __linux__\r
+ pthread_t m_threadInfo;\r
+#elif defined __WIN32__\r
+ HANDLE m_threadInfo;\r
+#endif\r
+ bool m_shouldStop;\r
+ bool m_isStopped;\r
+ bool m_autoDelete;\r
};\r
\r
/**\r
*/\r
class ReThreadStarter {\r
public:\r
- ReThreadStarter(ReLogger* logger);\r
+ ReThreadStarter(int maxThreads, ReLogger* logger);\r
virtual ~ReThreadStarter();\r
public:\r
- void startThread(ReThread& thread);\r
+ bool startThread(ReThread& thread);\r
+private:\r
+ bool insertThread(ReThread* thread);\r
private:\r
int m_nextId;\r
ReLogger* m_logger;\r
+ int m_maxThreads;\r
+ ReThread** m_threads;\r
};\r
#endif /* BASE_RETHREAD_HPP_ */\r
LC_TRAVERSER = 50400,
LC_TCP = 50500,
LC_THREAD = 50600,
+ LC_LOGGER = 50700,
};
enum RELOC_UDPCONNECTION {
LC_UDPCONNECTION_CONSTRUCT = 50101,
typedef u_int8_t uint8_t;\r
typedef __off_t ReFileSize_t;\r
typedef timespec ReFileTime_t;\r
-typedef sem_t ReMutex_t;\r
-#define reInitMutex(mutex)\r
# define _strdup strdup\r
# define _unlink unlink\r
# define _strnicmp(s1, s2, n) strncasecmp(s1, s2, n)\r
# define lstat stat\r
# define OS_SEPARATOR_CHAR '\\'\r
# define OS_SEPARATOR "\\"\r
-typedef HANDLE ReMutex_t;\r
-#define initMutex(mutex) mutex = CreateMutex(NULL, FALSE, NULL) \r
typedef _int64 int64_t;\r
typedef unsigned long long uint64_t;\r
typedef unsigned char uint8_t;\r
#endif\r
\r
#define RE_TESTUNIT\r
+#include "base/ReMutex.hpp"\r
#include "base/ReByteBuffer.hpp"\r
#include "base/ReVarArgs.hpp"\r
#include "base/ReLogger.hpp"\r
+#include "base/ReThread.hpp"\r
#include "base/ReTestUnit.hpp"\r
#include "base/ReCString.hpp"\r
#include "base/ReException.hpp"\r
#include "base/ReStringUtils.hpp"\r
#include "base/ReDirectory.hpp"\r
#include "base/ReSeqArray.hpp"\r
+#include "base/ReAppenders.hpp"\r
#include "base/ReStringList.hpp"\r
#include "base/ReHashList.hpp"\r
#include "base/ReConfigFile.hpp"\r
#include "base/ReI18N.hpp"\r
#include "base/ReProgramArgs.hpp"\r
-#include "base/ReAppenders.hpp"\r
\r
typedef unsigned char byte_t;\r
typedef int ReErrNo_t;\r
+++ /dev/null
-/*
- * remath.hpp
- *
- * License: Public domain
- * Do what you want.
- * No warranties and disclaimer of any damages.
- * The latest sources: https://github.com/republib
- */
-
-#ifndef REMATH_HPP_
-#define REMATH_HPP_
-
-#ifndef REBASE_HPP_
-#include "base/rebase.hpp"
-#endif
-#include "math/ReObfuscator.hpp"
-#include "math/ReRandomizer.hpp"
-
-#endif /* REMATH_HPP_ */
+++ /dev/null
-/*
- * renet.hpp
- *
- * License: Public domain
- * Do what you want.
- * No warranties and disclaimer of any damages.
- * The latest sources: https://github.com/republib
- */
-
-#ifndef RENET_HPP_
-#define RENET_HPP_
-
-#ifndef REBASE_HPP_
-#include "../base/rebase.hpp"
-#endif
-#include "net/ReUdpConnection.hpp"
-#endif /* RENET_HPP_ */
*/
#include "base/rebase.hpp"
-#include "base/remath.hpp"
+#include "math/remath.hpp"
/** @brief Constructor.
*
* @param id an identifier for logging
* @param logger the logger for error handling
*/
-ReTCPServerConnection::ReTCPServerConnection(int id, ReLogger* masterLogger,
- ReTCPServer* server) :
+ReTCPServerConnection::ReTCPServerConnection(int id, ReTCPServer* server) :
ReTCPConnection(id, new ReLogger(false)),
+ ReThread(true),
m_server(server),
- m_slaveAppender(masterLogger, '0' + id % ('z' - '0' + 1)) {
- m_logger->addAppender(&m_slaveAppender);
+ m_slaveAppender(NULL, '0' + id % ('z' - '0' + 1)) {
+ ReTCPConnection::m_logger->addAppender(&m_slaveAppender);
}
/**
/**
* Serves the commands of a single connection (in a single thread).
*/
-void ReTCPServerConnection::handleConnection() {
+void ReTCPServerConnection::run() {
ReByteBuffer command;
ReNetCommandHandler::ProcessingState rc = ReNetCommandHandler::PS_UNDEF;
do {
ReTCPServerConnection* rc = NULL;
for (int ii = 0; rc == NULL && ii < m_maxConnections; ii++) {
if (m_connections[ii] == NULL)
- m_connections[ii] = rc = new ReTCPServerConnection(id, m_logger,
- this);
+ m_connections[ii] = rc = new ReTCPServerConnection(id, this);
else if (m_connections[ii]->id() < 0) {
rc = m_connections[ii];
rc->setId(id);
return rc;
}
-/**
- * The start routine of pthread_start
- *
- * This will handle the connection for each client (in an own thread).
- *
- * @param pConnection a void* pointer to the ReTCPServerConnection instance
- * */
-static void* serverSlaveThread(void *pConnection) {
- ReTCPServerConnection* connection =
- reinterpret_cast<ReTCPServerConnection*>(pConnection);
- connection->handleConnection();
-}
-
/**
* Accepts connections and create a thread which will handle this connection.
*/
bool rc = false;
struct addrinfo hints;
struct addrinfo* addrInfo;
+ ReThreadStarter threadStarter(m_maxConnections + 1, m_logger);
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
reCloseSocket(clientSocket);
} else {
pthread_t sniffer_thread;
- ReTCPConnection* connection = createConnection(nextId++,
+ ReTCPServerConnection* connection = createConnection(nextId++,
clientSocket, addrClient);
- if (pthread_create(&sniffer_thread, NULL, serverSlaveThread,
- (void*) connection) < 0) {
+ if (! threadStarter.startThread(*connection)) {
m_logger->sayF(LOG_ERROR | CAT_PROCESS,
LC_LISTEN_FOR_ALL_6,
i18n("cannot create a thread: $1")).arg(
/**
* Implements a single server connection to a client (in a single thread).
*/
-class ReTCPServerConnection: public ReTCPConnection {
+class ReTCPServerConnection: public ReTCPConnection, public ReThread {
public:
- ReTCPServerConnection(int id, ReLogger* logger, ReTCPServer* server);
+ ReTCPServerConnection(int id, ReTCPServer* server);
virtual ~ReTCPServerConnection();
public:
- void handleConnection();
+ virtual void run();
private:
ReTCPServer* m_server;
ReSlaveAppender m_slaveAppender;
* Created on: 12.11.2010
* Author: wk
*/
-#include "../base/renet.hpp"
+#include "base/rebase.hpp"
+#include "net/renet.hpp"
/** @brief Constructor.
*