Hello All,

I'd like to share some experience as well as some patches with regard to using log4cxx in timing-critical application. First few words about our requirements: it's a service which must generate some network packets with up to hundred of microseconds precision. Thus, it's very important to have predictable code timing. One can argue that log4cxx is not very well suited for such applications, but surprisingly it works pretty well after some light tuning.

So, what were the issues?
Basically from library user's point of view they looked the same: one of a sudden logging done with LOG4CXX_DEBUG() macro could take unexpectedly long time to complete. For example the same trace which takes several μs for 99% of the time would take hundreds microseconds and even few milliseconds sometimes. After further investigation this has been traced down to few of the root-causes:

1. Asyns logger (which we have been using of course) has internal queue to pass log entries to background disk-writer thread. This queue is mutex-protected which might seem fine unless you think a little bit more about it. First of all, someone calling LOG4CXX_DEBUG() to simply put something into the log might not expect to be blocked inside waiting for a mutex at all. Second point is that, although there were measures taken to minimize time disk-thread holds that lock, OS-schedulers often work in a way that thread which is blocked on a mutex gets de-scheduled. With normal OS-scheduler quantum that means that the logging thread can be preempted for milliseconds.

2. There are some mutexes protecting internal states of both loggers and appenders. This means that two separate threads calling LOG4CXX_DEBUG() can block each other. Even if they are using different loggers they would block on appender! This has the same consequences for execution timing and the performance as described above.

3. std::stringstream class constructor has some internal locks on it's own. Unfortunately each MessageBuffer has it's own instance of this class. And also unfortunately MessageBuffer is created inside LOG4CXX_DEBUG() macro. There is optimization to not create stringstream for logging simple strings, but as soon as your log statement has single '<<' operator it's created.

4. Dynamic memory allocations. Unfortunately there are still quite few of them even though memory pool is used in some other places. Thus, hidden calls to new and malloc induce unpredictable delays.

So, what we did to mitigate these problems?

1. Natural solution for this issue was to use atomic queue. There are few of them available, but we made use of boost::lockfree::queue as it can serve as a drop-in replacement allowing us to keep all present functionality.

2. After looking more into the code it has appeared that two concurrent calls to LOG4CXX_DEBUG() from within different threads are not harmful because internal structures of logger and appender are not being changed there. What only really requires protection is concurrency between logging and configuring. Thus, we came to a solution - read-write locks where logging calls act as readers and configuration/exiting calls are writers. With such approach multiple threads calling LOG4CXX_DEBUG() became free of any contention.

3. This problem also has one simple solution - make one static std::stringstream object per thread using std::thread_local. Unfortunately we found one drawback - thread_local memory is not released if thread is not detached or joined. As there is some code which does neither of this we made static stringstream a xml file configuration option. Also, there could be an issue with using multiple MessageBuffer instances from within single thread, but LOG4CXX_DEBUG() is not doing that.

4. At this time we didn't do anything to address dynamic memory allocation issue.

So, if you want to give our patch a try it is attached. It's based on log4cxx 0.10.0-12 as found in Debian. There are new SHARED_MUTEX and LOCK_R/LOCK_W macros defined in mutex.h and synchronized.h for easy switching between RW and convenient mutexes for benchmarking. Also, there is an test application which spawns two threads doing logging with some small sleep between iterations. It prints to stdout if trace statement took more than 500 microseconds. It might look familiar too you because it's based on one of the examples from StackOverflow.

In our testing modified log4cxx has about 20% better performance overall, but more importantly for us it has much less cases when log statement takes excessive time to complete. The second part is only true for CPUs with >2 cores where all threads can physically run in parallel. Unfortunately we still see rare cases with prolonged logging calls, we have traced that down to dynamic memory allocation issue.

Any thoughts?

Denys Smolianiuk

Senior SW Engineer
Harmonic Inc.


diff --git a/configure.in b/configure.in
index 5422e69..d873c25 100644
--- a/configure.in
+++ b/configure.in
@@ -60,6 +60,8 @@ case "$host" in
         ;;
 esac
 
+CXXFLAGS="$CXXFLAGS -std=c++11"
+
 # Doxygen
 
 AC_ARG_ENABLE(doxygen,
diff --git a/debian/control b/debian/control
index 83da92a..189218c 100644
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,8 @@ Build-Depends: debhelper (>= 10),
                libaprutil1-dev,
                zip,
                dh-autoreconf,
-               quilt
+               quilt,
+               libboost-dev (>= 1.55)
 Build-Depends-Indep: doxygen
 Standards-Version: 3.9.8
 
diff --git a/src/main/cpp/appenderskeleton.cpp b/src/main/cpp/appenderskeleton.cpp
index 43ab5a1..9a29394 100644
--- a/src/main/cpp/appenderskeleton.cpp
+++ b/src/main/cpp/appenderskeleton.cpp
@@ -40,9 +40,9 @@ AppenderSkeleton::AppenderSkeleton()
     headFilter(),
     tailFilter(),
     pool(), 
-    mutex(pool)
+    SHARED_MUTEX_INIT(mutex, pool)
 {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     closed = false;
 }
 
@@ -54,9 +54,9 @@ AppenderSkeleton::AppenderSkeleton(const LayoutPtr& layout1)
   headFilter(),
   tailFilter(),
   pool(),
-  mutex(pool)
+  SHARED_MUTEX_INIT(mutex, pool)
 {
-  synchronized sync(mutex);
+  LOCK_W sync(mutex);
   closed = false;
 }
 
@@ -82,7 +82,7 @@ void AppenderSkeleton::finalize()
 
 void AppenderSkeleton::addFilter(const spi::FilterPtr& newFilter)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         if(headFilter == 0)
         {
                 headFilter = tailFilter = newFilter;
@@ -96,7 +96,7 @@ void AppenderSkeleton::addFilter(const spi::FilterPtr& newFilter)
 
 void AppenderSkeleton::clearFilters()
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         headFilter = tailFilter = 0;
 }
 
@@ -107,9 +107,13 @@ bool AppenderSkeleton::isAsSevereAsThreshold(const LevelPtr& level) const
 
 void AppenderSkeleton::doAppend(const spi::LoggingEventPtr& event, Pool& pool1)
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
+        doAppendImpl(event, pool1);
+}
 
+void AppenderSkeleton::doAppendImpl(const spi::LoggingEventPtr& event, Pool& pool1)
+{
         if(closed)
         {
                 LogLog::error(((LogString) LOG4CXX_STR("Attempted to append to closed appender named ["))
@@ -144,7 +148,7 @@ void AppenderSkeleton::doAppend(const spi::LoggingEventPtr& event, Pool& pool1)
 
 void AppenderSkeleton::setErrorHandler(const spi::ErrorHandlerPtr& errorHandler1)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
 
         if(errorHandler1 == 0)
         {
@@ -160,7 +164,7 @@ void AppenderSkeleton::setErrorHandler(const spi::ErrorHandlerPtr& errorHandler1
 
 void AppenderSkeleton::setThreshold(const LevelPtr& threshold1)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         this->threshold = threshold1;
 }
 
diff --git a/src/main/cpp/asyncappender.cpp b/src/main/cpp/asyncappender.cpp
index 44732c2..62d1ab2 100644
--- a/src/main/cpp/asyncappender.cpp
+++ b/src/main/cpp/asyncappender.cpp
@@ -44,8 +44,8 @@ IMPLEMENT_LOG4CXX_OBJECT(AsyncAppender)
 
 AsyncAppender::AsyncAppender()
 : AppenderSkeleton(),
-  buffer(),
-  bufferMutex(pool),
+  buffer(DEFAULT_BUFFER_SIZE),
+  SHARED_MUTEX_INIT(bufferMutex, pool),
   bufferNotFull(pool),
   bufferNotEmpty(pool),
   discardMap(new DiscardMap()),
@@ -96,6 +96,13 @@ void AsyncAppender::setOption(const LogString& option,
 }
 
 
+void AsyncAppender::doAppend(const spi::LoggingEventPtr& event, Pool& pool1)
+{
+        LOCK_R sync(mutex);
+        
+        doAppendImpl(event, pool1);
+}
+
 void AsyncAppender::append(const spi::LoggingEventPtr& event, Pool& p) {
 #if APR_HAS_THREADS
        //
@@ -118,16 +125,19 @@ void AsyncAppender::append(const spi::LoggingEventPtr& event, Pool& p) {
 
 
         {
-             synchronized sync(bufferMutex);
+             LOCK_R sync(bufferMutex);
              while(true) {
-                 int previousSize = buffer.size();
-                 if (previousSize < bufferSize) {
-                     buffer.push_back(event);
-                     if (previousSize == 0) {
-                        bufferNotEmpty.signalAll();
-                     }
-                     break;
-                 }
+                
+                event->addRef();
+                if (buffer.bounded_push(event))
+                {
+                    bufferNotEmpty.signalAll();
+                    break;
+                }
+                else
+                {
+                    event->releaseRef();
+                }
              
                 //
                 //   Following code is only reachable if buffer is full
@@ -141,7 +151,7 @@ void AsyncAppender::append(const spi::LoggingEventPtr& event, Pool& p) {
                     && !Thread::interrupted()
                     && !dispatcher.isCurrentThread()) {
                     try {
-                        bufferNotFull.await(bufferMutex);
+                        bufferNotFull.await();
                         discard = false;
                     } catch (InterruptedException& e) {
                         //
@@ -157,14 +167,7 @@ void AsyncAppender::append(const spi::LoggingEventPtr& event, Pool& p) {
                 //   add event to discard map.
                 //
                 if (discard) {
-                    LogString loggerName = event->getLoggerName();
-                    DiscardMap::iterator iter = discardMap->find(loggerName);
-                    if (iter == discardMap->end()) {
-                        DiscardSummary summary(event);
-                        discardMap->insert(DiscardMap::value_type(loggerName, summary));
-                    } else {
-                        (*iter).second.add(event);
-                    }
+                    discardedCount++;
                     break;
                 }
             }
@@ -178,12 +181,13 @@ void AsyncAppender::append(const spi::LoggingEventPtr& event, Pool& p) {
 
 void AsyncAppender::close() {
     {
-        synchronized sync(bufferMutex);
+        LOCK_W sync(bufferMutex);
         closed = true;
-        bufferNotEmpty.signalAll();
-        bufferNotFull.signalAll();
     }
     
+    bufferNotEmpty.signalAll();
+    bufferNotFull.signalAll();
+    
 #if APR_HAS_THREADS
     try {
         dispatcher.join();
@@ -258,8 +262,12 @@ void AsyncAppender::setBufferSize(int size)
     if (size < 0) {
           throw IllegalArgumentException(LOG4CXX_STR("size argument must be non-negative"));
     }
-    synchronized sync(bufferMutex);
-    bufferSize = (size < 1) ? 1 : size;
+    
+    {
+        LOCK_W sync(bufferMutex);
+        bufferSize = (size < 1) ? 1 : size;
+        buffer.reserve_unsafe(bufferSize);
+    }
     bufferNotFull.signalAll();
 }
 
@@ -269,8 +277,10 @@ int AsyncAppender::getBufferSize() const
 }
 
 void AsyncAppender::setBlocking(bool value) {
-    synchronized sync(bufferMutex);
-    blocking = value;
+    {
+        LOCK_W sync(bufferMutex);
+        blocking = value;
+    }
     bufferNotFull.signalAll();
 }
 
@@ -311,41 +321,57 @@ LoggingEventPtr AsyncAppender::DiscardSummary::createEvent(Pool& p) {
               LocationInfo::getLocationUnavailable());
 }
 
+::log4cxx::spi::LoggingEventPtr
+AsyncAppender::DiscardSummary::createEvent(::log4cxx::helpers::Pool& p,
+                                           unsigned discardedCount)
+{
+    char msg[128];
+    
+    snprintf(msg, 128, LOG4CXX_STR("Discarded %u messages due to a full event buffer."), discardedCount);
+    
+    return new LoggingEvent(   
+              "",
+              log4cxx::Level::getError(),
+              msg,
+              LocationInfo::getLocationUnavailable());
+}
 
 #if APR_HAS_THREADS
 void* LOG4CXX_THREAD_FUNC AsyncAppender::dispatch(apr_thread_t* thread, void* data) {
     AsyncAppender* pThis = (AsyncAppender*) data;
-    bool isActive = true;
     try {
-        while (isActive) {
+        while (!pThis->closed) {
+             
+             pThis->bufferNotEmpty.await();
+             
              //
              //   process events after lock on buffer is released.
              //
             Pool p;
             LoggingEventList events;
             {
-                   synchronized sync(pThis->bufferMutex);
-                   size_t bufferSize = pThis->buffer.size();
-                   isActive = !pThis->closed;
-               
-                   while((bufferSize == 0) && isActive) {
-                       pThis->bufferNotEmpty.await(pThis->bufferMutex);
-                       bufferSize = pThis->buffer.size();
-                       isActive = !pThis->closed;
+                   LOCK_R sync(pThis->bufferMutex);
+                   
+                   unsigned count = 0;
+                   log4cxx::spi::LoggingEvent * logPtr = nullptr;
+                   while (pThis->buffer.pop(logPtr))
+                   {
+                        log4cxx::spi::LoggingEventPtr ptr(logPtr);
+                        events.push_back(ptr);
+                        logPtr->releaseRef();
+                        count++;
                    }
-                   for(LoggingEventList::iterator eventIter = pThis->buffer.begin();
-                       eventIter != pThis->buffer.end();
-                       eventIter++) {
-                       events.push_back(*eventIter);
+                   
+                   if (pThis->blocking) {
+                       pThis->bufferNotFull.signalAll();
                    }
-                   for(DiscardMap::iterator discardIter = pThis->discardMap->begin();
-                       discardIter != pThis->discardMap->end();
-                       discardIter++) {
-                       events.push_back(discardIter->second.createEvent(p));
+                   
+                   unsigned discarded = pThis->discardedCount.exchange(0);
+                   
+                   if (discarded != 0)
+                   {
+                       events.push_back(AsyncAppender::DiscardSummary::createEvent(p, discarded));
                    }
-                   pThis->buffer.clear();
-                   pThis->discardMap->clear();
-                   pThis->bufferNotFull.signalAll();
             }
             
             for (LoggingEventList::iterator iter = events.begin();
diff --git a/src/main/cpp/domconfigurator.cpp b/src/main/cpp/domconfigurator.cpp
index 8d66df4..07ef3b9 100644
--- a/src/main/cpp/domconfigurator.cpp
+++ b/src/main/cpp/domconfigurator.cpp
@@ -44,6 +44,7 @@
 #include <log4cxx/helpers/bytebuffer.h>
 #include <log4cxx/helpers/charsetdecoder.h>
 #include <log4cxx/net/smtpappender.h>
+#include <log4cxx/helpers/messagebuffer.h>
 
 using namespace log4cxx;
 using namespace log4cxx::xml;
@@ -100,6 +101,7 @@ IMPLEMENT_LOG4CXX_OBJECT(DOMConfigurator)
 #define REF_ATTR "ref"
 #define ADDITIVITY_ATTR "additivity"
 #define THRESHOLD_ATTR "threshold"
+#define STRINGSTREAM_ATTR "stringstream"
 #define CONFIG_DEBUG_ATTR "configDebug"
 #define INTERNAL_DEBUG_ATTR "debug"
 
@@ -373,7 +375,7 @@ void DOMConfigurator::parseLogger(
         // Setting up a logger needs to be an atomic operation, in order
         // to protect potential log operations while logger
         // configuration is in progress.
-        synchronized sync(logger->getMutex());
+        LOCK_W sync(logger->getMutex());
         bool additivity = OptionConverter::toBoolean(
                 subst(getAttribute(utf8Decoder, loggerElement, ADDITIVITY_ATTR)),
                 true);
@@ -431,7 +433,7 @@ void DOMConfigurator::parseRoot(
 {
         LoggerPtr root = repository->getRootLogger();
         // logger configuration needs to be atomic
-        synchronized sync(root->getMutex());
+        LOCK_W sync(root->getMutex());
         parseChildrenOfLoggerElement(p, utf8Decoder, rootElement, root, true, doc, appenders);
 }
 
@@ -910,6 +912,13 @@ void DOMConfigurator::parse(
                 repository->setThreshold(thresholdStr);
     }
 
+    LogString strstrValue = subst(getAttribute(utf8Decoder, element, STRINGSTREAM_ATTR));
+    LogLog::debug(LOG4CXX_STR("Stringstream =\"") + strstrValue +LOG4CXX_STR("\"."));
+    if(!strstrValue.empty() && strstrValue != NuLL)
+    {
+        MessageBufferUseStaticStream();
+    }
+
     apr_xml_elem* currentElement;
     for(currentElement = element->first_child;
         currentElement;
diff --git a/src/main/cpp/fileappender.cpp b/src/main/cpp/fileappender.cpp
index ae752ee..f8258a2 100644
--- a/src/main/cpp/fileappender.cpp
+++ b/src/main/cpp/fileappender.cpp
@@ -36,7 +36,7 @@ IMPLEMENT_LOG4CXX_OBJECT(FileAppender)
 
 
 FileAppender::FileAppender() {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     fileAppend = true;
     bufferedIO = false;
     bufferSize = 8 * 1024;
@@ -46,7 +46,7 @@ FileAppender::FileAppender(const LayoutPtr& layout1, const LogString& fileName1,
         bool append1, bool bufferedIO1, int bufferSize1) 
            : WriterAppender(layout1) {
         {  
-            synchronized sync(mutex);
+            LOCK_W sync(mutex);
             fileAppend = append1;
             fileName = fileName1;
             bufferedIO = bufferedIO1;
@@ -60,7 +60,7 @@ FileAppender::FileAppender(const LayoutPtr& layout1, const LogString& fileName1,
         bool append1)
 : WriterAppender(layout1) {
         {
-            synchronized sync(mutex);
+            LOCK_W sync(mutex);
             fileAppend = append1;
             fileName = fileName1;
             bufferedIO = false;
@@ -73,7 +73,7 @@ FileAppender::FileAppender(const LayoutPtr& layout1, const LogString& fileName1,
 FileAppender::FileAppender(const LayoutPtr& layout1, const LogString& fileName1)
 : WriterAppender(layout1) {
         {
-            synchronized sync(mutex);
+            LOCK_W sync(mutex);
             fileAppend = true;
             fileName = fileName1;
             bufferedIO = false;
@@ -89,13 +89,13 @@ FileAppender::~FileAppender()
 }
 
 void FileAppender::setAppend(bool fileAppend1) { 
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     this->fileAppend = fileAppend1; 
 }
 
 void FileAppender::setFile(const LogString& file)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         fileName = file;
 }
 
@@ -103,7 +103,7 @@ void FileAppender::setFile(const LogString& file)
 
 void FileAppender::setBufferedIO(bool bufferedIO1)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         this->bufferedIO = bufferedIO1;
         if(bufferedIO1)
         {
@@ -117,27 +117,27 @@ void FileAppender::setOption(const LogString& option,
         if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILE"), LOG4CXX_STR("file"))
                 || StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("FILENAME"), LOG4CXX_STR("filename")))
         {
-                synchronized sync(mutex);
+                LOCK_W sync(mutex);
                 fileName = stripDuplicateBackslashes(value);
         }
         else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("APPEND"), LOG4CXX_STR("append")))
         {
-                synchronized sync(mutex);
+                LOCK_W sync(mutex);
                 fileAppend = OptionConverter::toBoolean(value, true);
         }
         else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFEREDIO"), LOG4CXX_STR("bufferedio")))
         {
-                synchronized sync(mutex);
+                LOCK_W sync(mutex);
                 bufferedIO = OptionConverter::toBoolean(value, true);
         }
         else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("IMMEDIATEFLUSH"), LOG4CXX_STR("immediateflush")))
         {
-                synchronized sync(mutex);
+                LOCK_W sync(mutex);
                 bufferedIO = !OptionConverter::toBoolean(value, false);
         }
         else if (StringHelper::equalsIgnoreCase(option, LOG4CXX_STR("BUFFERSIZE"), LOG4CXX_STR("buffersize")))
         {
-                synchronized sync(mutex);
+                LOCK_W sync(mutex);
                 bufferSize = OptionConverter::toFileSize(value, 8*1024);
         }
         else
@@ -148,7 +148,7 @@ void FileAppender::setOption(const LogString& option,
 
 void FileAppender::activateOptions(Pool& p)
 {
-  synchronized sync(mutex);
+  LOCK_W sync(mutex);
   int errors = 0;
   if (!fileName.empty()) {
     try {
@@ -240,7 +240,7 @@ void FileAppender::setFile(
       bool bufferedIO1,
       size_t bufferSize1,
       Pool& p) {
-  synchronized sync(mutex);
+  LOCK_W sync(mutex);
 
   // It does not make sense to have immediate flush and bufferedIO.
   if (bufferedIO1) {
diff --git a/src/main/cpp/logger.cpp b/src/main/cpp/logger.cpp
index 2fcb044..4431c6d 100644
--- a/src/main/cpp/logger.cpp
+++ b/src/main/cpp/logger.cpp
@@ -43,9 +43,9 @@ IMPLEMENT_LOG4CXX_OBJECT(Logger)
 
 Logger::Logger(Pool& p, const LogString& name1)
 : pool(&p), name(), level(), parent(), resourceBundle(),
-repository(), aai(), mutex(p)
+repository(), aai(), SHARED_MUTEX_INIT(mutex, p)
 {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     name = name1;
     additive = true;
 }
@@ -64,7 +64,7 @@ void Logger::releaseRef() const {
 
 void Logger::addAppender(const AppenderPtr& newAppender)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
 
         if (aai == 0)
         {
@@ -86,7 +86,7 @@ void Logger::callAppenders(const spi::LoggingEventPtr& event, Pool& p) const
          logger = logger->parent)
         {
                 // Protected against simultaneous call to addAppender, removeAppender,...
-                synchronized sync(logger->mutex);
+                LOCK_R sync(logger->mutex);
 
                 if (logger->aai != 0)
                 {
@@ -150,8 +150,8 @@ bool Logger::getAdditivity() const
 
 AppenderList Logger::getAllAppenders() const
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
         if (aai == 0)
         {
                 return AppenderList();
@@ -164,8 +164,8 @@ AppenderList Logger::getAllAppenders() const
 
 AppenderPtr Logger::getAppender(const LogString& name1) const
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
         if (aai == 0 || name1.empty())
         {
                 return 0;
@@ -250,8 +250,8 @@ LevelPtr Logger::getLevel() const
 
 bool Logger::isAttached(const AppenderPtr& appender) const
 {
-        synchronized sync(mutex);
-
+        LOCK_R sync(mutex);
+        
         if (appender == 0 || aai == 0)
         {
                 return false;
@@ -434,8 +434,8 @@ void Logger::l7dlog(const LevelPtr& level1, const std::string& key,
 
 void Logger::removeAllAppenders()
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
         if(aai != 0)
         {
                 aai->removeAllAppenders();
@@ -445,8 +445,8 @@ void Logger::removeAllAppenders()
 
 void Logger::removeAppender(const AppenderPtr& appender)
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
         if(appender == 0 || aai == 0)
         {
                 return;
@@ -457,8 +457,8 @@ void Logger::removeAppender(const AppenderPtr& appender)
 
 void Logger::removeAppender(const LogString& name1)
 {
-        synchronized sync(mutex);
-
+        LOCK_W sync(mutex);
+        
         if(name1.empty() || aai == 0)
         {
                 return;
@@ -469,7 +469,7 @@ void Logger::removeAppender(const LogString& name1)
 
 void Logger::setAdditivity(bool additive1)
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         this->additive = additive1;
 }
 
diff --git a/src/main/cpp/messagebuffer.cpp b/src/main/cpp/messagebuffer.cpp
index 42a6439..eddf0d9 100644
--- a/src/main/cpp/messagebuffer.cpp
+++ b/src/main/cpp/messagebuffer.cpp
@@ -20,10 +20,46 @@
 
 using namespace log4cxx::helpers;
 
-CharMessageBuffer::CharMessageBuffer() : stream(0) {}
+static bool gMessageBufferUseStaticStream = false;
+
+namespace log4cxx {
+namespace helpers {
+      void MessageBufferUseStaticStream()
+      {
+         gMessageBufferUseStaticStream = true;
+      }
+   }
+}
+
+template <typename T>
+void ResetStream(std::basic_ostringstream<T> &stream)
+{
+   stream.seekp(0);
+   stream.str(std::basic_string<T>());
+   stream.clear();
+}
+
+CharMessageBuffer::CharMessageBuffer() : stream(0) {
+   if (gMessageBufferUseStaticStream)
+   {
+      thread_local static char ossBuf[8192];
+      thread_local static std::basic_ostringstream<char> sStream;
+      thread_local static bool inited = false;
+      if (!inited)
+      {
+         inited = true;
+         sStream.rdbuf()->pubsetbuf(ossBuf, 8192); 
+         
+         ResetStream(sStream);
+      }
+      stream = &sStream;
+   }
+}
 
 CharMessageBuffer::~CharMessageBuffer() {
-   delete stream;
+   if (!gMessageBufferUseStaticStream) {
+      delete stream;
+   }
 }
 
 CharMessageBuffer& CharMessageBuffer::operator<<(const std::basic_string<char>& msg) {
@@ -73,6 +109,9 @@ CharMessageBuffer::operator std::basic_ostream<char>&() {
 
 const std::basic_string<char>& CharMessageBuffer::str(std::basic_ostream<char>&) {
    buf = stream->str();
+   
+   ResetStream(*stream);
+   
    return buf;
 }
 
@@ -103,10 +142,27 @@ std::ostream& CharMessageBuffer::operator<<(void* val) { return ((std::ostream&)
 
 
 #if LOG4CXX_WCHAR_T_API
-WideMessageBuffer::WideMessageBuffer() : stream(0) {}
+WideMessageBuffer::WideMessageBuffer() : stream(0) {
+   if (gMessageBufferUseStaticStream)
+   {
+      thread_local static wchar_t ossBuf[8192];
+      thread_local static std::basic_ostringstream<wchar_t> sStream;
+      thread_local static bool inited = false;
+      if (!inited)
+      {
+         inited = true;
+         sStream.rdbuf()->pubsetbuf(ossBuf, 8192); 
+         
+         ResetStream(sStream);
+      }
+      stream = &sStream;
+   }
+}
 
 WideMessageBuffer::~WideMessageBuffer() {
-   delete stream;
+   if (!gMessageBufferUseStaticStream) {
+      delete stream;
+   }
 }
 
 WideMessageBuffer& WideMessageBuffer::operator<<(const std::basic_string<wchar_t>& msg) {
@@ -157,6 +213,9 @@ WideMessageBuffer::operator std::basic_ostream<wchar_t>&() {
 
 const std::basic_string<wchar_t>& WideMessageBuffer::str(std::basic_ostream<wchar_t>&) {
    buf = stream->str();
+   
+   ResetStream(*stream);
+   
    return buf;
 }
 
@@ -312,10 +371,27 @@ const std::basic_string<log4cxx::UniChar>& MessageBuffer::str(std::basic_ostream
 }
 
 
-UniCharMessageBuffer::UniCharMessageBuffer() : stream(0) {}
+UniCharMessageBuffer::UniCharMessageBuffer() : stream(0) {
+   if (gMessageBufferUseStaticStream)
+   {
+      thread_local static log4cxx::UniChar ossBuf[8192];
+      thread_local static std::basic_ostringstream<log4cxx::UniChar> sStream;
+      thread_local static bool inited = false;
+      if (!inited)
+      {
+         inited = true;
+         sStream.rdbuf()->pubsetbuf(ossBuf, 8192); 
+         
+         ResetStream(sStream);
+      }
+      stream = &sStream;
+   }
+}
 
 UniCharMessageBuffer::~UniCharMessageBuffer() {
-   delete stream;
+   if (!gMessageBufferUseStaticStream) {
+      delete stream;
+   }
 }
 
 
@@ -366,7 +442,8 @@ UniCharMessageBuffer::operator UniCharMessageBuffer::uostream&() {
 }
 
 const std::basic_string<log4cxx::UniChar>& UniCharMessageBuffer::str(UniCharMessageBuffer::uostream&) {
-    buf = stream->str();
+   buf = stream->str();
+   ResetStream(*stream);
    return buf;
 }
 
diff --git a/src/main/cpp/mutex.cpp b/src/main/cpp/mutex.cpp
index 2fa836e..9803c62 100644
--- a/src/main/cpp/mutex.cpp
+++ b/src/main/cpp/mutex.cpp
@@ -19,12 +19,15 @@
 #include <log4cxx/helpers/mutex.h>
 #include <log4cxx/helpers/exception.h>
 #include <apr_thread_mutex.h>
+#include <apr_thread_rwlock.h>
 #include <assert.h>
 #if !defined(LOG4CXX)
 #define LOG4CXX 1
 #endif
 #include <log4cxx/helpers/aprinitializer.h>
 
+#include <semaphore.h>
+
 using namespace log4cxx::helpers;
 using namespace log4cxx;
 
@@ -59,3 +62,139 @@ Mutex::~Mutex() {
 apr_thread_mutex_t* Mutex::getAPRMutex() const {
     return mutex;
 }
+
+RWMutex::RWMutex(Pool& p) 
+        : id((apr_os_thread_t)-1)
+        , count(0)
+{
+#if APR_HAS_THREADS
+        apr_status_t stat = apr_thread_rwlock_create(&mutex,
+                p.getAPRPool());
+        if (stat != APR_SUCCESS) {
+                throw MutexException(stat);
+        }
+#endif
+}
+
+RWMutex::RWMutex(apr_pool_t* p) 
+        : id((apr_os_thread_t)-1)
+        , count(0)
+{
+#if APR_HAS_THREADS
+        apr_status_t stat = apr_thread_rwlock_create(&mutex, p);
+        if (stat != APR_SUCCESS) {
+                throw MutexException(stat);
+        }
+#endif
+}
+
+
+RWMutex::~RWMutex() {
+#if APR_HAS_THREADS
+        apr_thread_rwlock_destroy(mutex);
+#endif
+}
+
+void RWMutex::rdLock() const
+{
+#if APR_HAS_THREADS
+        apr_status_t stat = apr_thread_rwlock_rdlock(mutex);
+#endif
+}
+
+void RWMutex::rdUnlock() const
+{
+#if APR_HAS_THREADS
+        apr_status_t stat = apr_thread_rwlock_unlock(mutex);
+#endif
+}
+
+void RWMutex::wrLock() const
+{
+#if APR_HAS_THREADS
+         apr_os_thread_t self = apr_os_thread_current();
+         if (id == self)
+         {
+             ++count;
+         }
+         else
+         {
+             apr_status_t stat = apr_thread_rwlock_wrlock(mutex);
+             id = self;
+             count = 1;
+         }
+#endif
+}
+
+void RWMutex::wrUnlock() const
+{
+#if APR_HAS_THREADS
+         if (--count == 0)
+         {
+             id = (apr_os_thread_t)-1;  // id_ = "not a thread"
+             apr_status_t stat = apr_thread_rwlock_unlock(mutex);
+         }
+         else
+         {
+         }
+#endif
+}
+
+
+
+
+namespace log4cxx {
+    namespace helpers {
+        struct SemaphoreImpl
+        {
+            sem_t semaphore;
+        };
+    }
+}
+
+Semaphore::Semaphore(log4cxx::helpers::Pool& p)
+    : impl(nullptr)
+{
+#if APR_HAS_THREADS
+    impl = (SemaphoreImpl*)p.palloc(sizeof(SemaphoreImpl));
+    if (nullptr == impl) {
+        throw MutexException(APR_ENOMEM);
+    }
+    
+    int stat = sem_init(&impl->semaphore, 0, 0);
+    if (stat != 0) {
+        throw MutexException(APR_ENOSHMAVAIL);
+    }
+#endif
+}
+
+Semaphore::~Semaphore()
+{
+#if APR_HAS_THREADS
+    if (impl)
+    {
+        int stat = sem_destroy(&impl->semaphore);
+    }
+#endif
+}
+
+void Semaphore::await() const
+{
+#if APR_HAS_THREADS
+    int stat = sem_wait(&impl->semaphore);
+    if (stat != 0) {
+        throw MutexException(stat);
+    }
+#endif
+}
+
+void Semaphore::signalAll() const
+{
+#if APR_HAS_THREADS
+    int stat = sem_post(&impl->semaphore);
+    if (stat != 0) {
+        throw MutexException(stat);
+    }
+#endif
+}
+
diff --git a/src/main/cpp/propertyconfigurator.cpp b/src/main/cpp/propertyconfigurator.cpp
index d0950b8..ae31e2c 100644
--- a/src/main/cpp/propertyconfigurator.cpp
+++ b/src/main/cpp/propertyconfigurator.cpp
@@ -164,7 +164,14 @@ void PropertyConfigurator::doConfigure(helpers::Properties& properties,
                     + hierarchy->getThreshold()->toString()
                     + LOG4CXX_STR("]."));
         }
-
+        
+        static const LogString STRINGSTREAM_KEY(LOG4CXX_STR("log4j.stringstream"));
+        LogString strstrValue(properties.getProperty(STRINGSTREAM_KEY));
+        if (strstrValue == LOG4CXX_STR("static"))
+        {
+            MessageBufferUseStaticStream();
+        }
+        
         configureRootLogger(properties, hierarchy);
         configureLoggerFactory(properties);
         parseCatsAndRenderers(properties, hierarchy);
@@ -223,7 +230,7 @@ void PropertyConfigurator::configureRootLogger(helpers::Properties& props,
         {
                 LoggerPtr root = hierarchy->getRootLogger();
 
-                synchronized sync(root->getMutex());
+                LOCK_W sync(root->getMutex());
                 static const LogString INTERNAL_ROOT_NAME(LOG4CXX_STR("root"));
                 parseLogger(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
         }
@@ -259,7 +266,7 @@ void PropertyConfigurator::parseCatsAndRenderers(helpers::Properties& props,
                         LogString value = OptionConverter::findAndSubst(key, props);
                         LoggerPtr logger = hierarchy->getLogger(loggerName, loggerFactory);
 
-                        synchronized sync(logger->getMutex());
+                        LOCK_W sync(logger->getMutex());
                         parseLogger(props, logger, key, loggerName, value);
                         parseAdditivityForLogger(props, logger, loggerName);
                 }
diff --git a/src/main/cpp/rollingfileappender.cpp b/src/main/cpp/rollingfileappender.cpp
index 5acab77..4ae03da 100644
--- a/src/main/cpp/rollingfileappender.cpp
+++ b/src/main/cpp/rollingfileappender.cpp
@@ -72,7 +72,7 @@ void RollingFileAppenderSkeleton::activateOptions(Pool &p) {
   }
 
   {
-     synchronized sync(mutex);
+     LOCK_W sync(mutex);
      triggeringPolicy->activateOptions(p);
      rollingPolicy->activateOptions(p);
 
@@ -140,7 +140,7 @@ bool RollingFileAppenderSkeleton::rollover(Pool& p) {
   if (rollingPolicy != NULL) {
 
 {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
       try {
         RolloverDescriptionPtr rollover1(rollingPolicy->rollover(getFile(), p));
 
diff --git a/src/main/cpp/socketappender.cpp b/src/main/cpp/socketappender.cpp
index 833ee4a..6c4fc60 100644
--- a/src/main/cpp/socketappender.cpp
+++ b/src/main/cpp/socketappender.cpp
@@ -75,7 +75,7 @@ int SocketAppender::getDefaultPort() const {
 }
 
 void SocketAppender::setSocket(log4cxx::helpers::SocketPtr& socket, Pool& p) {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     oos = new ObjectOutputStream(new SocketOutputStream(socket), p);
 }
 
diff --git a/src/main/cpp/socketappenderskeleton.cpp b/src/main/cpp/socketappenderskeleton.cpp
index 822e4ac..6a28a9d 100644
--- a/src/main/cpp/socketappenderskeleton.cpp
+++ b/src/main/cpp/socketappenderskeleton.cpp
@@ -74,7 +74,7 @@ void SocketAppenderSkeleton::activateOptions(Pool& p)
 }
 
 void SocketAppenderSkeleton::close() {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     if (closed) return;
     closed = true;
     cleanUp(pool);
@@ -129,7 +129,7 @@ void SocketAppenderSkeleton::setOption(const LogString& option, const LogString&
 
 void SocketAppenderSkeleton::fireConnector()
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         if (thread.isActive()) {
                 thread.run(monitor, this);
         }
diff --git a/src/main/cpp/sockethubappender.cpp b/src/main/cpp/sockethubappender.cpp
index 8b92d5e..d439624 100644
--- a/src/main/cpp/sockethubappender.cpp
+++ b/src/main/cpp/sockethubappender.cpp
@@ -85,7 +85,7 @@ void SocketHubAppender::setOption(const LogString& option,
 void SocketHubAppender::close()
 {
         {
-            synchronized sync(mutex);
+            LOCK_W sync(mutex);
             if (closed) {
                 return;
             }
@@ -98,7 +98,7 @@ void SocketHubAppender::close()
         //
         thread.join();
 
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         // close all of the connections
         LogLog::debug(LOG4CXX_STR("closing client connections"));
         for (std::vector<helpers::ObjectOutputStreamPtr>::iterator iter = streams.begin();
@@ -218,7 +218,7 @@ void* APR_THREAD_FUNC SocketHubAppender::monitor(apr_thread_t* /* thread */, voi
                                        + LOG4CXX_STR(")"));
 
                                 // add it to the oosList.
-                                synchronized sync(pThis->mutex);
+                                LOCK_W sync(pThis->mutex);
                                 OutputStreamPtr os(new SocketOutputStream(socket));
                                 Pool p;
                                 ObjectOutputStreamPtr oos(new ObjectOutputStream(os, p));
diff --git a/src/main/cpp/synchronized.cpp b/src/main/cpp/synchronized.cpp
index cab2715..210bf1f 100644
--- a/src/main/cpp/synchronized.cpp
+++ b/src/main/cpp/synchronized.cpp
@@ -47,3 +47,27 @@ synchronized::~synchronized()
         }
 #endif
 }
+
+
+synchronized_read::synchronized_read(const RWMutex& mutex1)
+        : mutex(mutex1)
+{
+        mutex.rdLock();
+}
+
+synchronized_read::~synchronized_read()
+{
+        mutex.rdUnlock();
+}
+
+synchronized_write::synchronized_write(const RWMutex& mutex1)
+        : mutex(mutex1)
+{
+        mutex.wrLock();
+}
+
+synchronized_write::~synchronized_write()
+{
+        mutex.wrUnlock();
+}
+
diff --git a/src/main/cpp/telnetappender.cpp b/src/main/cpp/telnetappender.cpp
index b8bf951..abd6122 100644
--- a/src/main/cpp/telnetappender.cpp
+++ b/src/main/cpp/telnetappender.cpp
@@ -46,7 +46,7 @@ TelnetAppender::TelnetAppender()
     encoder(CharsetEncoder::getUTF8Encoder()), 
     serverSocket(NULL), sh()
 {
-   synchronized sync(mutex);
+   LOCK_W sync(mutex);
    activeConnections = 0;
 }
 
@@ -83,12 +83,12 @@ void TelnetAppender::setOption(const LogString& option,
 }
 
 LogString TelnetAppender::getEncoding() const {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     return encoding;
 }
 
 void TelnetAppender::setEncoding(const LogString& value) {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     encoder = CharsetEncoder::getEncoder(value);
     encoding = value;
 }
@@ -96,7 +96,7 @@ void TelnetAppender::setEncoding(const LogString& value) {
 
 void TelnetAppender::close()
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
         if (closed) return;
         closed = true;
 
@@ -171,7 +171,7 @@ void TelnetAppender::append(const spi::LoggingEventPtr& event, Pool& p)
                 LogString::const_iterator msgIter(msg.begin());
                 ByteBuffer buf(bytes, bytesSize);
 
-                synchronized sync(this->mutex);
+                LOCK_W sync(this->mutex);
                 while(msgIter != msg.end()) {
                     log4cxx_status_t stat = encoder->encode(msg, msgIter, buf);
                     buf.flip();
@@ -216,7 +216,7 @@ void* APR_THREAD_FUNC TelnetAppender::acceptConnections(apr_thread_t* /* thread
                         //
                         //   find unoccupied connection
                         //
-                        synchronized sync(pThis->mutex);
+                        LOCK_W sync(pThis->mutex);
                         for(ConnectionList::iterator iter = pThis->connections.begin();
                                 iter != pThis->connections.end();
                                 iter++) {
diff --git a/src/main/cpp/writerappender.cpp b/src/main/cpp/writerappender.cpp
index c54c5fe..734e667 100644
--- a/src/main/cpp/writerappender.cpp
+++ b/src/main/cpp/writerappender.cpp
@@ -28,7 +28,7 @@ using namespace log4cxx::spi;
 IMPLEMENT_LOG4CXX_OBJECT(WriterAppender)
 
 WriterAppender::WriterAppender() {
-   synchronized sync(mutex);
+   LOCK_W sync(mutex);
    immediateFlush = true;
 }
 
@@ -36,14 +36,14 @@ WriterAppender::WriterAppender(const LayoutPtr& layout1,
                log4cxx::helpers::WriterPtr& writer1)
     : AppenderSkeleton(layout1), writer(writer1) {
       Pool p;
-      synchronized sync(mutex);
+      LOCK_W sync(mutex);
       immediateFlush = true;
       activateOptions(p);
 }
 
 WriterAppender::WriterAppender(const LayoutPtr& layout1)
     : AppenderSkeleton(layout1) {
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     immediateFlush = true;
 }
 
@@ -132,7 +132,7 @@ bool WriterAppender::checkEntryConditions() const {
    */
 void WriterAppender::close()
 {
-        synchronized sync(mutex);
+        LOCK_W sync(mutex);
 
         if(closed)
         {
@@ -207,7 +207,7 @@ void WriterAppender::subAppend(const spi::LoggingEventPtr& event, Pool& p)
         LogString msg;
         layout->format(msg, event, p);
         {
-           synchronized sync(mutex);
+           LOCK_W sync(mutex);
          if (writer != NULL) {
            writer->write(msg, p);
               if (immediateFlush) {
@@ -223,7 +223,7 @@ void WriterAppender::writeFooter(Pool& p)
         if (layout != NULL) {
           LogString foot;
           layout->appendFooter(foot, p);
-          synchronized sync(mutex);
+          LOCK_W sync(mutex);
           writer->write(foot, p);
         }
 }
@@ -233,14 +233,14 @@ void WriterAppender::writeHeader(Pool& p)
         if(layout != NULL) {
           LogString header;
           layout->appendHeader(header, p);
-          synchronized sync(mutex);
+          LOCK_W sync(mutex);
           writer->write(header, p);
         }
 }
 
 
 void WriterAppender::setWriter(const WriterPtr& newWriter) {
-   synchronized sync(mutex);
+   LOCK_W sync(mutex);
    writer = newWriter;
 }
 
@@ -259,6 +259,6 @@ void WriterAppender::setOption(const LogString& option, const LogString& value)
 
 
 void WriterAppender::setImmediateFlush(bool value) { 
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     immediateFlush = value; 
 }
diff --git a/src/main/cpp/xmlsocketappender.cpp b/src/main/cpp/xmlsocketappender.cpp
index c5ce1a9..4a3a521 100644
--- a/src/main/cpp/xmlsocketappender.cpp
+++ b/src/main/cpp/xmlsocketappender.cpp
@@ -82,7 +82,7 @@ int XMLSocketAppender::getDefaultPort() const {
 void XMLSocketAppender::setSocket(log4cxx::helpers::SocketPtr& socket, Pool& p) {
     OutputStreamPtr os(new SocketOutputStream(socket));
     CharsetEncoderPtr charset(CharsetEncoder::getUTF8Encoder());
-    synchronized sync(mutex);
+    LOCK_W sync(mutex);
     writer = new OutputStreamWriter(os, charset);
 }
 
diff --git a/src/main/include/log4cxx/appenderskeleton.h b/src/main/include/log4cxx/appenderskeleton.h
index 16242bd..d91a640 100644
--- a/src/main/include/log4cxx/appenderskeleton.h
+++ b/src/main/include/log4cxx/appenderskeleton.h
@@ -76,7 +76,7 @@ namespace log4cxx
                 bool closed;
 
                 log4cxx::helpers::Pool pool;
-                log4cxx::helpers::Mutex mutex;
+                mutable SHARED_MUTEX mutex;
 
         public:
                 DECLARE_ABSTRACT_LOG4CXX_OBJECT(AppenderSkeleton)
@@ -117,6 +117,8 @@ namespace log4cxx
         protected:
                 virtual void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) = 0;
 
+                void doAppendImpl(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool);
+                
                 /**
                 Clear the filters chain.
                 */
@@ -171,7 +173,7 @@ namespace log4cxx
                 * delegating actual logging to the subclasses specific
                 * AppenderSkeleton#append method.
                 * */
-                void doAppend(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool);
+                virtual void doAppend(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& pool);
 
                 /**
                 Set the {@link spi::ErrorHandler ErrorHandler} for this Appender.
diff --git a/src/main/include/log4cxx/asyncappender.h b/src/main/include/log4cxx/asyncappender.h
index cbe9b3c..8c2ff28 100644
--- a/src/main/include/log4cxx/asyncappender.h
+++ b/src/main/include/log4cxx/asyncappender.h
@@ -32,6 +32,7 @@
 #include <log4cxx/helpers/mutex.h>
 #include <log4cxx/helpers/condition.h>
 
+#include <boost/lockfree/queue.hpp>
 
 namespace log4cxx
 {
@@ -81,6 +82,9 @@ namespace log4cxx
                  * @param newAppender appender to add, may not be null.
                 */
                 void addAppender(const AppenderPtr& newAppender);
+                
+                virtual void doAppend(const spi::LoggingEventPtr& event,
+                                      log4cxx::helpers::Pool& pool1);
 
                 void append(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p);
 
@@ -194,16 +198,15 @@ namespace log4cxx
                 /**
                  * Event buffer.
                 */
-                LOG4CXX_LIST_DEF(LoggingEventList, log4cxx::spi::LoggingEventPtr);
-                LoggingEventList buffer;
-
+                boost::lockfree::queue<log4cxx::spi::LoggingEvent* > buffer;
+                std::atomic<unsigned> discardedCount;
                 /**
                  *  Mutex used to guard access to buffer and discardMap.
                  */
-                ::log4cxx::helpers::Mutex bufferMutex;
-                ::log4cxx::helpers::Condition bufferNotFull;
-                ::log4cxx::helpers::Condition bufferNotEmpty;
-    
+                SHARED_MUTEX bufferMutex;
+                SEMAPHORE bufferNotFull;
+                SEMAPHORE bufferNotEmpty;
+                
                 class DiscardSummary {
                 private:
                     /**
@@ -241,6 +244,10 @@ namespace log4cxx
                      * @return new event.
                      */
                      ::log4cxx::spi::LoggingEventPtr createEvent(::log4cxx::helpers::Pool& p);
+                     
+                     static
+                     ::log4cxx::spi::LoggingEventPtr createEvent(::log4cxx::helpers::Pool& p,
+                                                                 unsigned discardedCount);
                 };
 
                 /**
diff --git a/src/main/include/log4cxx/helpers/messagebuffer.h b/src/main/include/log4cxx/helpers/messagebuffer.h
index c026dc5..d83879e 100644
--- a/src/main/include/log4cxx/helpers/messagebuffer.h
+++ b/src/main/include/log4cxx/helpers/messagebuffer.h
@@ -27,6 +27,8 @@ namespace log4cxx {
 
    namespace helpers {
    
+   void MessageBufferUseStaticStream();
+   
    typedef std::ios_base& (*ios_base_manip)(std::ios_base&);
 
    /**
diff --git a/src/main/include/log4cxx/helpers/mutex.h b/src/main/include/log4cxx/helpers/mutex.h
index d26487b..dba7f9f 100644
--- a/src/main/include/log4cxx/helpers/mutex.h
+++ b/src/main/include/log4cxx/helpers/mutex.h
@@ -20,9 +20,14 @@
 
 #include <log4cxx/log4cxx.h>
 
+#include <apr-1.0/apr_portable.h>
+
+#include <atomic>
+
 extern "C" {
    struct apr_thread_mutex_t;
    struct apr_pool_t;
+   struct apr_thread_rwlock_t;
 }
 
 
@@ -48,4 +53,74 @@ namespace log4cxx
         } // namespace helpers
 } // namespace log4cxx
 
+
+namespace log4cxx
+{
+        namespace helpers
+        {
+                class Pool;
+
+                class LOG4CXX_EXPORT RWMutex
+                {
+                public:
+                        RWMutex(log4cxx::helpers::Pool& p);
+                        RWMutex(apr_pool_t* p);
+                        ~RWMutex();
+                        
+                        void rdLock() const;
+                        void rdUnlock() const;
+                        
+                        void wrLock() const;
+                        void wrUnlock() const;
+                        
+                private:
+                        mutable std::atomic<apr_os_thread_t> id;
+                        mutable unsigned count;
+                        RWMutex(const RWMutex&);
+                        RWMutex& operator=(const RWMutex&);
+                        apr_thread_rwlock_t* mutex;
+                };
+        } // namespace helpers
+} // namespace log4cxx
+
+//#define SHARED_MUTEX_INIT(mutex, p) mutex()
+//#define SHARED_MUTEX shared_mutex_recursive
+
+//#define SHARED_MUTEX std::shared_mutex
+
+//#define SHARED_MUTEX_INIT(mutex, p) mutex(p)
+//#define SHARED_MUTEX log4cxx::helpers::Mutex
+
+
+#define SHARED_MUTEX log4cxx::helpers::RWMutex
+#define SHARED_MUTEX_INIT(mutex, p) mutex(p)
+
+namespace log4cxx
+{
+    namespace helpers
+    {
+        struct SemaphoreImpl;
+        
+        class LOG4CXX_EXPORT Semaphore
+        {
+            public:
+                Semaphore(log4cxx::helpers::Pool& p);
+                ~Semaphore();
+                
+                void await() const;
+                void signalAll() const;
+                
+            private:
+                Semaphore(const Semaphore&);
+                Semaphore& operator=(const Semaphore&);
+                
+                SemaphoreImpl *impl;
+        };
+    } // namespace helpers
+} // namespace log4cxx
+
+#define SEMAPHORE log4cxx::helpers::Semaphore
+
+//#define SEMAPHORE log4cxx::helpers::Condition
+
 #endif //_LOG4CXX_HELPERS_MUTEX_H
diff --git a/src/main/include/log4cxx/helpers/synchronized.h b/src/main/include/log4cxx/helpers/synchronized.h
index 05476db..e3486c5 100644
--- a/src/main/include/log4cxx/helpers/synchronized.h
+++ b/src/main/include/log4cxx/helpers/synchronized.h
@@ -41,4 +41,61 @@ namespace log4cxx
         }
 }
 
+namespace log4cxx
+{
+        namespace helpers {
+                class RWMutex;
+
+                // utility class for objects multi-thread synchronization.
+                class LOG4CXX_EXPORT synchronized_read
+                {
+                public:
+                synchronized_read(const RWMutex& mutex);
+                ~synchronized_read();
+
+
+                private:
+                const RWMutex & mutex;
+                //  prevent use of copy and assignment
+                synchronized_read(const synchronized_read&);
+                synchronized_read& operator=(const synchronized_read&);
+                };
+        }
+}
+
+namespace log4cxx
+{
+        namespace helpers {
+                class RWMutex;
+
+                // utility class for objects multi-thread synchronization.
+                class LOG4CXX_EXPORT synchronized_write
+                {
+                public:
+                synchronized_write(const RWMutex& mutex);
+                ~synchronized_write();
+
+
+                private:
+                const RWMutex & mutex;
+                //  prevent use of copy and assignment
+                synchronized_write(const synchronized_write&);
+                synchronized_write& operator=(const synchronized_write&);
+                };
+        }
+}
+
+//#define LOCK_R std::shared_lock<shared_mutex_recursive>
+//#define LOCK_W std::unique_lock<shared_mutex_recursive>
+
+//#define LOCK std::lock_guard<std::recursive_mutex>
+
+//#define LOCK synchronized
+
+#define LOCK_R synchronized_read
+#define LOCK_W synchronized_write
+
+//#define LOCK_R synchronized
+//#define LOCK_W synchronized
+
 #endif //_LOG4CXX_HELPERS_SYNCHRONIZED_H
diff --git a/src/main/include/log4cxx/logger.h b/src/main/include/log4cxx/logger.h
index d5b5007..ef6a713 100644
--- a/src/main/include/log4cxx/logger.h
+++ b/src/main/include/log4cxx/logger.h
@@ -1707,14 +1707,14 @@ namespace log4cxx
         */
         void trace(const std::string& msg) const;
 
-        inline const log4cxx::helpers::Mutex& getMutex() const { return mutex; }
-
+        inline SHARED_MUTEX & getMutex() { return mutex; }
+        
         private:
                 //
         //  prevent copy and assignment
         Logger(const Logger&);
         Logger& operator=(const Logger&);
-        log4cxx::helpers::Mutex mutex;
+        mutable SHARED_MUTEX mutex;
         friend class log4cxx::helpers::synchronized;
    };
    LOG4CXX_LIST_DEF(LoggerList, LoggerPtr);

Attachment: config.xml
Description: XML document

#include "log4cxx/logger.h"
#include "log4cxx/xml/domconfigurator.h"
//#include <boost/timer/timer.hpp>


#include <iostream>
#include <thread>

#include <unistd.h>

using namespace log4cxx;
using namespace log4cxx::helpers;

LoggerPtr logger(Logger::getRootLogger());

const int thread_count = 2;

static long time_diff_nanosecs(struct timespec &begin, struct timespec &end)
{
    
    long nanosecs = ( end.tv_nsec - begin.tv_nsec )
        + ( end.tv_sec - begin.tv_sec ) * 1000000000L;    
    
    return nanosecs;
}


void printer(void)
{
    long total = 0;
    long total2 = 0;

    struct timespec begin = {0};
    struct timespec end = {0};
    
    for (int i = 0; i < 20000; i++)
    {
        clock_gettime(CLOCK_MONOTONIC, &begin);    
        
        LOG4CXX_DEBUG(logger, "Logging performance check: " << i);

        clock_gettime(CLOCK_MONOTONIC, &end);    
        
        total += time_diff_nanosecs(begin, end);
        
        if (time_diff_nanosecs(begin, end) > 500000)
        {
            total2 += time_diff_nanosecs(begin, end);
            
            std::cout << "long iteration: " << std::dec << i 
                << ", (begin, end): " << time_diff_nanosecs(begin, end) << std::endl; 
        }
        
      usleep(1);
        
//         struct timespec ns = {0, 1000};
//         nanosleep(&ns, NULL);
    }

    std::cout << "total: " << total << ", total2: " << total2 << std::endl;
}

int main(int argc, char **argv)
{
//    boost::timer::auto_cpu_timer t;
    xml::DOMConfigurator::configure("config.xml");
    
    std::vector<std::thread> grp;
    grp.reserve(thread_count);
    
    for (int i = 0; i != thread_count; ++i)
    {
        grp.emplace_back(printer);
//        grp[i].detach();
    }
    
    for (auto& thread : grp)
    {
        if (thread.joinable())
        {
            thread.join();
        }
    }
    
//     std::cout << t.elapsed().user << std::endl;
//     std::cout << t.elapsed().wall << std::endl;
//     std::cout << t.elapsed().system << std::endl;
    return 0;
}

Reply via email to