Update of /cvsroot/boost/boost/libs/thread/src
In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv8244/libs/thread/src

Modified Files:
      Tag: RC_1_34_0
        tss.cpp 
Log Message:
Removed the "intentional memory leak" of the TSS implementation.


Index: tss.cpp
===================================================================
RCS file: /cvsroot/boost/boost/libs/thread/src/tss.cpp,v
retrieving revision 1.16.10.3
retrieving revision 1.16.10.4
diff -u -d -r1.16.10.3 -r1.16.10.4
--- tss.cpp     14 Sep 2006 21:51:00 -0000      1.16.10.3
+++ tss.cpp     1 Oct 2006 12:57:18 -0000       1.16.10.4
@@ -1,5 +1,5 @@
-// Copyright (C) 2001-2003
-// William E. Kempf
+// Copyright (C) 2001-2003 William E. Kempf
+// Copyright (C) 2006 Roland Schwarz
 //
 //  Distributed under the Boost Software License, Version 1.0. (See 
accompanying 
 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -25,63 +25,98 @@
 namespace {
 
 typedef std::vector<void*> tss_slots;
+typedef std::vector<boost::function1<void, void*>*> 
tss_data_cleanup_handlers_type;
 
-struct tss_data_t
-{
-    boost::mutex mutex;
-    std::vector<boost::function1<void, void*>*> cleanup_handlers;
+boost::once_flag tss_data_once = BOOST_ONCE_INIT;
+boost::mutex* tss_data_mutex = 0;
+tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
 #if defined(BOOST_HAS_WINTHREADS)
-    DWORD native_key;
+    DWORD tss_data_native_key;
 #elif defined(BOOST_HAS_PTHREADS)
-    pthread_key_t native_key;
+    pthread_key_t tss_data_native_key;
 #elif defined(BOOST_HAS_MPTASKS)
-    TaskStorageIndex native_key;
+    TaskStorageIndex tss_data_native_key;
 #endif
-};
+int tss_data_use = 0;
 
-tss_data_t* tss_data = 0;
-boost::once_flag tss_data_once = BOOST_ONCE_INIT;
+void tss_data_inc_use(boost::mutex::scoped_lock& lk)
+{
+    ++tss_data_use;
+}
+
+void tss_data_dec_use(boost::mutex::scoped_lock& lk)
+{
+    if (0 == --tss_data_use)
+    {
+        tss_data_cleanup_handlers_type::size_type i;
+        for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
+        {
+            delete (*tss_data_cleanup_handlers)[i];
+        }
+        delete tss_data_cleanup_handlers;
+        tss_data_cleanup_handlers = 0;
+        lk.unlock();
+        delete tss_data_mutex;
+        tss_data_mutex = 0;
+#if defined(BOOST_HAS_WINTHREADS)
+        TlsFree(tss_data_native_key);
+#elif defined(BOOST_HAS_PTHREADS)
+        pthread_key_delete(tss_data_native_key);
+#elif defined(BOOST_HAS_MPTASKS)
+        // Don't know what to put here.
+        // But MPTASKS isn't currently maintained anyways...
+#endif
+    }
+}
 
 extern "C" void cleanup_slots(void* p)
 {
     tss_slots* slots = static_cast<tss_slots*>(p);
+    boost::mutex::scoped_lock lock(*tss_data_mutex);
     for (tss_slots::size_type i = 0; i < slots->size(); ++i)
     {
-        boost::mutex::scoped_lock lock(tss_data->mutex);
-        (*tss_data->cleanup_handlers[i])((*slots)[i]);
+        (*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
         (*slots)[i] = 0;
     }
+    tss_data_dec_use(lock);
     delete slots;
 }
 
 void init_tss_data()
 {
-    std::auto_ptr<tss_data_t> temp(new tss_data_t);
+    std::auto_ptr<tss_data_cleanup_handlers_type> 
+        temp(new tss_data_cleanup_handlers_type);
+
+    std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
+    if (temp_mutex.get() == 0)
+        throw boost::thread_resource_error();
 
 #if defined(BOOST_HAS_WINTHREADS)
     //Force the cleanup implementation library to be linked in
     tss_cleanup_implemented();
 
     //Allocate tls slot
-    temp->native_key = TlsAlloc();
-    if (temp->native_key == 0xFFFFFFFF)
+    tss_data_native_key = TlsAlloc();
+    if (tss_data_native_key == 0xFFFFFFFF)
         return;
 #elif defined(BOOST_HAS_PTHREADS)
-    int res = pthread_key_create(&temp->native_key, &cleanup_slots);
+    int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
     if (res != 0)
         return;
 #elif defined(BOOST_HAS_MPTASKS)
-    OSStatus status = MPAllocateTaskStorageIndex(&temp->native_key);
+    OSStatus status = MPAllocateTaskStorageIndex(&tss_data_native_key);
     if (status != noErr)
         return;
 #endif
 
-    // Intentional memory "leak"
-    // This is the only way to ensure the mutex in the global data
-    // structure is available when cleanup handlers are run, since the
-    // execution order of cleanup handlers is unspecified on any platform
-    // with regards to C++ destructor ordering rules.
-    tss_data = temp.release();
+    // The life time of cleanup handlers and mutex is beeing
+    // managed by a reference counting technique.
+    // This avoids a memory leak by releasing the global data
+    // after last use only, since the execution order of cleanup
+    // handlers is unspecified on any platform with regards to
+    // C++ destructor ordering rules.
+    tss_data_cleanup_handlers = temp.release();
+    tss_data_mutex = temp_mutex.release();
 }
 
 #if defined(BOOST_HAS_WINTHREADS)
@@ -101,13 +136,13 @@
 
 #if defined(BOOST_HAS_WINTHREADS)
     slots = static_cast<tss_slots*>(
-        TlsGetValue(tss_data->native_key));
+        TlsGetValue(tss_data_native_key));
 #elif defined(BOOST_HAS_PTHREADS)
     slots = static_cast<tss_slots*>(
-        pthread_getspecific(tss_data->native_key));
+        pthread_getspecific(tss_data_native_key));
 #elif defined(BOOST_HAS_MPTASKS)
     slots = static_cast<tss_slots*>(
-        MPGetTaskStorageValue(tss_data->native_key));
+        MPGetTaskStorageValue(tss_data_native_key));
 #endif
 
     if (slots == 0 && alloc)
@@ -117,16 +152,19 @@
 #if defined(BOOST_HAS_WINTHREADS)
         if (at_thread_exit(&tss_thread_exit) == -1)
             return 0;
-        if (!TlsSetValue(tss_data->native_key, temp.get()))
+        if (!TlsSetValue(tss_data_native_key, temp.get()))
             return 0;
 #elif defined(BOOST_HAS_PTHREADS)
-        if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
+        if (pthread_setspecific(tss_data_native_key, temp.get()) != 0)
             return 0;
 #elif defined(BOOST_HAS_MPTASKS)
-        if (MPSetTaskStorageValue(tss_data->native_key, temp.get()) != noErr)
+        if (MPSetTaskStorageValue(tss_data_native_key, temp.get()) != noErr)
             return 0;
 #endif
-
+        {
+            boost::mutex::scoped_lock lock(*tss_data_mutex);
+            tss_data_inc_use(lock);
+        }
         slots = temp.release();
     }
 
@@ -141,13 +179,14 @@
 void tss::init(boost::function1<void, void*>* pcleanup)
 {
     boost::call_once(&init_tss_data, tss_data_once);
-    if (tss_data == 0)
+    if (tss_data_cleanup_handlers == 0)
         throw thread_resource_error();
-    boost::mutex::scoped_lock lock(tss_data->mutex);
+    boost::mutex::scoped_lock lock(*tss_data_mutex);
     try
     {
-        tss_data->cleanup_handlers.push_back(pcleanup);
-        m_slot = tss_data->cleanup_handlers.size() - 1;
+        tss_data_cleanup_handlers->push_back(pcleanup);
+        m_slot = tss_data_cleanup_handlers->size() - 1;
+        tss_data_inc_use(lock);
     }
     catch (...)
     {
@@ -155,6 +194,12 @@
     }
 }
 
+tss::~tss()
+{
+    boost::mutex::scoped_lock lock(*tss_data_mutex);
+    tss_data_dec_use(lock);
+}
+
 void* tss::get() const
 {
     tss_slots* slots = get_slots(false);
@@ -192,8 +237,8 @@
 
 void tss::cleanup(void* value)
 {
-    boost::mutex::scoped_lock lock(tss_data->mutex);
-    (*tss_data->cleanup_handlers[m_slot])(value);
+    boost::mutex::scoped_lock lock(*tss_data_mutex);
+    (*(*tss_data_cleanup_handlers)[m_slot])(value);
 }
 
 } // namespace detail


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Boost-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/boost-cvs

Reply via email to