Author: carnold
Date: Fri Feb 15 13:51:36 2008
New Revision: 628179

URL: http://svn.apache.org/viewvc?rev=628179&view=rev
Log:
LOGCXX-117: Memory leak with ThreadSpecificData

Modified:
    logging/log4cxx/trunk/src/main/cpp/loggingevent.cpp
    logging/log4cxx/trunk/src/main/cpp/mdc.cpp
    logging/log4cxx/trunk/src/main/cpp/ndc.cpp
    logging/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp
    logging/log4cxx/trunk/src/main/include/log4cxx/helpers/threadspecificdata.h
    logging/log4cxx/trunk/src/main/include/log4cxx/ndc.h

Modified: logging/log4cxx/trunk/src/main/cpp/loggingevent.cpp
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/loggingevent.cpp?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/loggingevent.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/loggingevent.cpp Fri Feb 15 13:51:36 2008
@@ -144,12 +144,13 @@
         }
         else
         {
-                MDC::Map& m = ThreadSpecificData::getCurrentThreadMap();
+                ThreadSpecificData* data = 
ThreadSpecificData::getCurrentData();
+                if (data != 0) {
+                    MDC::Map& m = data->getMap();
 
-                MDC::Map::const_iterator it;
-                for (it = m.begin(); it != m.end(); it++)
-                {
+                    for(MDC::Map::const_iterator it = m.begin(); it != 
m.end(); it++) {
                         set.push_back(it->first);
+                    }
                 }
         }
 
@@ -162,8 +163,13 @@
         {
                 mdcCopyLookupRequired = false;
                 // the clone call is required for asynchronous logging.
-                mdcCopy = new 
MDC::Map(ThreadSpecificData::getCurrentThreadMap());
-        }
+                ThreadSpecificData* data = 
ThreadSpecificData::getCurrentData();
+                if (data != 0) {
+                    mdcCopy = new MDC::Map(data->getMap());
+                } else {
+                    mdcCopy = new MDC::Map();
+                }
+       }
 }
 
 bool LoggingEvent::getProperty(const LogString& key, LogString& dest) const

Modified: logging/log4cxx/trunk/src/main/cpp/mdc.cpp
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/mdc.cpp?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/mdc.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/mdc.cpp Fri Feb 15 13:51:36 2008
@@ -42,8 +42,7 @@
 
 void MDC::putLS(const LogString& key, const LogString& value)
 {
-        Map& map = ThreadSpecificData::getCurrentThreadMap();
-        map[key] = value;
+        ThreadSpecificData::put(key, value);
 }
 
 void MDC::put(const std::string& key, const std::string& value)
@@ -55,12 +54,16 @@
 
 bool MDC::get(const LogString& key, LogString& value)
 {
-        Map& map = ThreadSpecificData::getCurrentThreadMap();
+        ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+        if (data != 0) {
+            Map& map = data->getMap();
 
-        Map::iterator it = map.find(key);
-        if (it != map.end()) {
+            Map::iterator it = map.find(key);
+            if (it != map.end()) {
                 value.append(it->second);
                 return true;
+            }
+            data->recycle();
         }
         return false;
 }
@@ -78,13 +81,16 @@
 
 bool MDC::remove(const LogString& key, LogString& value)
 {
-        Map::iterator it;
-        Map& map = ThreadSpecificData::getCurrentThreadMap();
-        if ((it = map.find(key)) != map.end())
-        {
+        ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+        if (data != 0) {
+            Map& map = data->getMap();
+            Map::iterator it;
+            if ((it = map.find(key)) != map.end()) {
                 value = it->second;
                 map.erase(it);
+                data->recycle();
                 return true;
+            }
         }
         return false;
 }
@@ -103,8 +109,12 @@
 
 void MDC::clear()
 {
-        Map& map = ThreadSpecificData::getCurrentThreadMap();
-        map.erase(map.begin(), map.end());
+        ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+        if (data != 0) {
+            Map& map = data->getMap();
+            map.erase(map.begin(), map.end());
+            data->recycle();
+        }
 }
 
 

Modified: logging/log4cxx/trunk/src/main/cpp/ndc.cpp
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/ndc.cpp?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/ndc.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/ndc.cpp Fri Feb 15 13:51:36 2008
@@ -27,33 +27,6 @@
 using namespace log4cxx;
 using namespace log4cxx::helpers;
 
-NDC::DiagnosticContext::DiagnosticContext(const LogString& message1,
-        const DiagnosticContext * parent)
-        : fullMessage(message1), message(message1)
-{
-        if (parent != 0)
-        {
-                fullMessage.insert(0, LOG4CXX_STR(" "));
-                fullMessage.insert(0, parent->fullMessage);
-        }
-}
-
-NDC::DiagnosticContext::~DiagnosticContext() {
-}
-
-NDC::DiagnosticContext::DiagnosticContext(const DiagnosticContext& src)
-        : fullMessage(src.fullMessage), message(src.message) {
-}
-
-NDC::DiagnosticContext& NDC::DiagnosticContext::operator=(
-        const DiagnosticContext& src)
-{
-        message.assign(src.message);
-        fullMessage.assign(src.fullMessage);
-        return *this;
-}
-
-
 NDC::NDC(const std::string& message)
 {
         push(message);
@@ -65,88 +38,118 @@
 }
 
 
+LogString& NDC::getMessage(NDC::DiagnosticContext& ctx) {
+    return ctx.first;
+}
+
+LogString& NDC::getFullMessage(NDC::DiagnosticContext& ctx) {
+    return ctx.second;
+}
+
 void NDC::clear()
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         while(!stack.empty()) {
           stack.pop();
         }
+        data->recycle();
+    }
 }
 
 bool NDC::get(LogString& dest)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
-        if(!stack.empty())
-        {
-                dest.append(stack.top().fullMessage);
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
+        if(!stack.empty()) {
+                dest.append(getFullMessage(stack.top()));
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
-int NDC::getDepth()
-{
-  return ThreadSpecificData::getCurrentThreadStack().size();
+int NDC::getDepth() {
+    int size = 0;
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        size = data->getStack().size();
+        if (size == 0) {
+            data->recycle();
+        }
+    }
+    return size;
 }
 
 LogString NDC::pop()
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                LogString value(stack.top().message);
+                LogString value(getMessage(stack.top()));
                 stack.pop();
+                data->recycle();
                 return value;
         }
-        return LogString();
+        data->recycle();
+    }
+    return LogString();
 }
 
 bool NDC::pop(std::string& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    bool retval = false;
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                Transcoder::encode(stack.top().message, dst);
+                Transcoder::encode(getMessage(stack.top()), dst);
                 stack.pop();
-                return true;
+                retval = true;
         }
-        return false;
+        data->recycle();
+    }
+    return retval;
 }
 
 LogString NDC::peek()
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                return stack.top().message;
+                return getMessage(stack.top());
         }
-        return LogString();
+        data->recycle();
+    }
+    return LogString();
 }
 
 bool NDC::peek(std::string& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                Transcoder::encode(stack.top().message, dst);
+                Transcoder::encode(getMessage(stack.top()), dst);
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 void NDC::pushLS(const LogString& message)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
-
-        if (stack.empty())
-        {
-                stack.push(DiagnosticContext(message, 0));
-        }
-        else
-        {
-                DiagnosticContext& parent = stack.top();
-                stack.push(DiagnosticContext(message, &parent));
-        }
+    ThreadSpecificData::push(message);
 }
 
 void NDC::push(const std::string& message)
@@ -161,8 +164,16 @@
 }
 
 bool NDC::empty() {
-    Stack& stack = ThreadSpecificData::getCurrentThreadStack();
-    return stack.empty();
+    bool empty = true;
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
+        empty = stack.empty();
+        if (empty) {
+            data->recycle();
+        }
+    }
+    return empty;
 }
 
 #if LOG4CXX_WCHAR_T_API
@@ -179,25 +190,34 @@
 
 bool NDC::pop(std::wstring& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                Transcoder::encode(stack.top().message, dst);
+                Transcoder::encode(getMessage(stack.top()), dst);
                 stack.pop();
+                data->recycle();
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 bool NDC::peek(std::wstring& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
-                Transcoder::encode(stack.top().message, dst);
+                Transcoder::encode(getMessage(stack.top()), dst);
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 #endif
@@ -217,25 +237,34 @@
 
 bool NDC::pop(std::basic_string<UniChar>& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
                 Transcoder::encode(stack.top().message, dst);
                 stack.pop();
+                data->recycle();
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 bool NDC::peek(std::basic_string<UniChar>& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
                 Transcoder::encode(stack.top().message, dst);
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 #endif
@@ -255,25 +284,34 @@
 
 bool NDC::pop(CFStringRef& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
                 dst = Transcoder::encode(stack.top().message);
                 stack.pop();
+                data->recycle();
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 bool NDC::peek(CFStringRef& dst)
 {
-        Stack& stack = ThreadSpecificData::getCurrentThreadStack();
+    ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
+    if (data != 0) {
+        Stack& stack = data->getStack();
         if(!stack.empty())
         {
                 dst = Transcoder::encode(stack.top().message);
                 return true;
         }
-        return false;
+        data->recycle();
+    }
+    return false;
 }
 
 #endif

Modified: logging/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp (original)
+++ logging/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp Fri Feb 15 
13:51:36 2008
@@ -34,33 +34,85 @@
 }
 
 
-log4cxx::NDC::Stack& ThreadSpecificData::getCurrentThreadStack() {
-  return getCurrentData().ndcStack;
+log4cxx::NDC::Stack& ThreadSpecificData::getStack() {
+  return ndcStack;
 }
 
-log4cxx::MDC::Map& ThreadSpecificData::getCurrentThreadMap() {
-  return getCurrentData().mdcMap;
+log4cxx::MDC::Map& ThreadSpecificData::getMap() {
+  return mdcMap;
 }
 
-ThreadSpecificData& ThreadSpecificData::getCurrentData() {
+ThreadSpecificData& ThreadSpecificData::getDataNoThreads() {
+    static ThreadSpecificData noThreadData;
+    return noThreadData;
+}
+
+ThreadSpecificData* ThreadSpecificData::getCurrentData() {
 #if APR_HAS_THREADS
   void* pData = NULL;
-  apr_status_t stat = apr_threadkey_private_get(&pData, 
APRInitializer::getTlsKey());
-  if (stat != APR_SUCCESS) {
-    throw ThreadException(stat);
-  }
-  if (pData == NULL) {
+  apr_threadkey_private_get(&pData, APRInitializer::getTlsKey());
+  return (ThreadSpecificData*) pData;
+#else
+  return &getDataNoThreads();  
+#endif
+}
+
+void ThreadSpecificData::recycle() {
+    if(ndcStack.empty() && mdcMap.empty()) {
+        void* pData = NULL;
+        apr_status_t stat = apr_threadkey_private_get(&pData, 
APRInitializer::getTlsKey());
+        if (stat == APR_SUCCESS && pData == this) {
+            stat = apr_threadkey_private_set(0, APRInitializer::getTlsKey());
+            if (stat == APR_SUCCESS) {
+                delete this;
+            }
+        }
+    }
+}
+
+void ThreadSpecificData::put(const LogString& key, const LogString& val) {
+    ThreadSpecificData* data = getCurrentData();
+    if (data == 0) {
+        data = createCurrentData();
+    }
+    if (data != 0) {
+        data->getMap().insert(log4cxx::MDC::Map::value_type(key, val));
+    }
+}
+
+
+
+
+void ThreadSpecificData::push(const LogString& val) {
+    ThreadSpecificData* data = getCurrentData();
+    if (data == 0) {
+        data = createCurrentData();
+    }
+    if (data != 0) {
+        NDC::Stack& stack = data->getStack();
+        if(stack.empty()) {
+            stack.push(NDC::DiagnosticContext(val, val));
+        } else {
+            LogString fullMessage(stack.top().second);
+            fullMessage.append(1, (logchar) 0x20);
+            fullMessage.append(val);
+            stack.push(NDC::DiagnosticContext(val, fullMessage));
+        }
+    }
+}
+
+
+
+ThreadSpecificData* ThreadSpecificData::createCurrentData() {
+#if APR_HAS_THREADS
     ThreadSpecificData* newData = new ThreadSpecificData();
-    stat = apr_threadkey_private_set(newData, APRInitializer::getTlsKey());
+    apr_status_t stat = apr_threadkey_private_set(newData, 
APRInitializer::getTlsKey());
     if (stat != APR_SUCCESS) {
       delete newData;
-      throw ThreadException(stat);
+      newData = NULL;
     }
-    return *newData;
-  }
-  return *((ThreadSpecificData*) pData);
+    return newData;
 #else
-  static ThreadSpecificData data;
-  return data;
+    return 0;
 #endif
 }

Modified: 
logging/log4cxx/trunk/src/main/include/log4cxx/helpers/threadspecificdata.h
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/include/log4cxx/helpers/threadspecificdata.h?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/include/log4cxx/helpers/threadspecificdata.h 
(original)
+++ logging/log4cxx/trunk/src/main/include/log4cxx/helpers/threadspecificdata.h 
Fri Feb 15 13:51:36 2008
@@ -36,11 +36,26 @@
                         ThreadSpecificData();
                         ~ThreadSpecificData();
 
-                        static log4cxx::NDC::Stack& getCurrentThreadStack();
-                        static log4cxx::MDC::Map& getCurrentThreadMap();
+                        /**
+                         *  Gets current thread specific data.
+                         *  @return thread specific data, may be null.
+                         */
+                        static ThreadSpecificData* getCurrentData();
+                        /**
+                         *  Release this ThreadSpecficData if empty.
+                         */
+                        void recycle();
+                        
+                        static void put(const LogString& key, const LogString& 
val);
+                        static void push(const LogString& val);
+                        
+                        log4cxx::NDC::Stack& getStack();
+                        log4cxx::MDC::Map& getMap();
+                        
 
                 private:
-                        static ThreadSpecificData& getCurrentData();
+                        static ThreadSpecificData& getDataNoThreads();
+                        static ThreadSpecificData* createCurrentData();
                         log4cxx::NDC::Stack ndcStack;
                         log4cxx::MDC::Map mdcMap;
                 };

Modified: logging/log4cxx/trunk/src/main/include/log4cxx/ndc.h
URL: 
http://svn.apache.org/viewvc/logging/log4cxx/trunk/src/main/include/log4cxx/ndc.h?rev=628179&r1=628178&r2=628179&view=diff
==============================================================================
--- logging/log4cxx/trunk/src/main/include/log4cxx/ndc.h (original)
+++ logging/log4cxx/trunk/src/main/include/log4cxx/ndc.h Fri Feb 15 13:51:36 
2008
@@ -98,21 +98,11 @@
         */
         class LOG4CXX_EXPORT NDC
         {
-        private:
-                class DiagnosticContext
-                {
-                public:
-                        LogString fullMessage;
-                        LogString message;
-
-                        DiagnosticContext(const LogString& message,
-                                const DiagnosticContext * parent);
-                        virtual ~DiagnosticContext();
-                        DiagnosticContext(const DiagnosticContext& src);
-                        DiagnosticContext& operator=(const DiagnosticContext& 
src);
-                };
-
         public:
+                /**
+                 *  Pair of Message and FullMessage.
+                 */
+                typedef std::pair<LogString, LogString> DiagnosticContext;
                 typedef std::stack<DiagnosticContext> Stack;
 
                 /**
@@ -265,6 +255,8 @@
         private:
                 NDC(const NDC&);
                 NDC& operator=(const NDC&);
+                static LogString& getMessage(DiagnosticContext& ctx);
+                static LogString& getFullMessage(DiagnosticContext& ctx);
         }; // class NDC;
 }  // namespace log4cxx
 


Reply via email to