|
Boost-Commit : |
From: anthony_at_[hidden]
Date: 2007-11-13 04:27:12
Author: anthonyw
Date: 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
New Revision: 41056
URL: http://svn.boost.org/trac/boost/changeset/41056
Log:
Integrated TSS with storage of thread data; cleaned up the heap allocation functions to throw bad_alloc if they run out of memory
Added:
trunk/boost/thread/win32/tss.hpp (contents, props changed)
Removed:
trunk/libs/thread/src/win32/tss.cpp
trunk/libs/thread/src/win32/tss_hooks.cpp
Text files modified:
trunk/boost/thread/detail/tss_hooks.hpp | 2
trunk/boost/thread/tss.hpp | 14 ++-
trunk/boost/thread/win32/thread.hpp | 4
trunk/boost/thread/win32/thread_heap_alloc.hpp | 93 +++++++++++++++++++++--
trunk/libs/thread/build/Jamfile.v2 | 2
trunk/libs/thread/src/win32/thread.cpp | 151 +++++++++++++++++++++++++++++----------
trunk/libs/thread/src/win32/tss_pe.cpp | 3
7 files changed, 208 insertions(+), 61 deletions(-)
Modified: trunk/boost/thread/detail/tss_hooks.hpp
==============================================================================
--- trunk/boost/thread/detail/tss_hooks.hpp (original)
+++ trunk/boost/thread/detail/tss_hooks.hpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -67,7 +67,7 @@
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
-
+
extern "C" void tss_cleanup_implemented(void);
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force
Modified: trunk/boost/thread/tss.hpp
==============================================================================
--- trunk/boost/thread/tss.hpp (original)
+++ trunk/boost/thread/tss.hpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
+// Copyright (C) 2007 Anthony Williams
//
// 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)
@@ -9,14 +10,17 @@
#include <boost/thread/detail/config.hpp>
+#ifdef BOOST_HAS_WINTHREADS
+#include <boost/thread/detail/platform.hpp>
+#include BOOST_THREAD_PLATFORM(tss.hpp)
+#else
+
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
-#elif defined(BOOST_HAS_MPTASKS)
-# include <Multiprocessing.h>
#endif
namespace boost {
@@ -57,10 +61,6 @@
void init(boost::function1<void, void*>* pcleanup);
};
-#if defined(BOOST_HAS_MPTASKS)
-void thread_cleanup();
-#endif
-
template <typename T>
struct tss_adapter
{
@@ -112,6 +112,8 @@
} // namespace boost
+#endif
+
#endif //BOOST_TSS_WEK070601_HPP
// Change Log:
Modified: trunk/boost/thread/win32/thread.hpp
==============================================================================
--- trunk/boost/thread/win32/thread.hpp (original)
+++ trunk/boost/thread/win32/thread.hpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -27,6 +27,7 @@
namespace detail
{
struct thread_exit_callback_node;
+ struct tss_data_node;
struct thread_data_base
{
@@ -34,13 +35,14 @@
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
+ boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
- thread_exit_callbacks(0),
+ thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
Modified: trunk/boost/thread/win32/thread_heap_alloc.hpp
==============================================================================
--- trunk/boost/thread/win32/thread_heap_alloc.hpp (original)
+++ trunk/boost/thread/win32/thread_heap_alloc.hpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -6,6 +6,8 @@
#define THREAD_HEAP_ALLOC_HPP
#include <new>
#include "thread_primitives.hpp"
+#include <stdexcept>
+#include <boost/assert.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -51,35 +53,106 @@
{
namespace detail
{
+ inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
+ {
+ void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
+ if(!heap_memory)
+ {
+ throw std::bad_alloc();
+ }
+ return heap_memory;
+ }
+
+ inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
+ {
+ BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
+ }
+
template<typename T>
T* heap_new()
{
- void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
- T* const data=new (heap_memory) T();
- return data;
+ void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
+ try
+ {
+ T* const data=new (heap_memory) T();
+ return data;
+ }
+ catch(...)
+ {
+ free_raw_heap_memory(heap_memory);
+ throw;
+ }
}
template<typename T,typename A1>
T* heap_new(A1 a1)
{
- void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
- T* const data=new (heap_memory) T(a1);
- return data;
+ void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
+ try
+ {
+ T* const data=new (heap_memory) T(a1);
+ return data;
+ }
+ catch(...)
+ {
+ free_raw_heap_memory(heap_memory);
+ throw;
+ }
}
template<typename T,typename A1,typename A2>
T* heap_new(A1 a1,A2 a2)
{
- void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,sizeof(T));
- T* const data=new (heap_memory) T(a1,a2);
- return data;
+ void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
+ try
+ {
+ T* const data=new (heap_memory) T(a1,a2);
+ return data;
+ }
+ catch(...)
+ {
+ free_raw_heap_memory(heap_memory);
+ throw;
+ }
+ }
+
+ template<typename T,typename A1,typename A2,typename A3>
+ T* heap_new(A1 a1,A2 a2,A3 a3)
+ {
+ void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
+ try
+ {
+ T* const data=new (heap_memory) T(a1,a2,a3);
+ return data;
+ }
+ catch(...)
+ {
+ free_raw_heap_memory(heap_memory);
+ throw;
+ }
+ }
+
+ template<typename T,typename A1,typename A2,typename A3,typename A4>
+ T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4)
+ {
+ void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
+ try
+ {
+ T* const data=new (heap_memory) T(a1,a2,a3,a4);
+ return data;
+ }
+ catch(...)
+ {
+ free_raw_heap_memory(heap_memory);
+ throw;
+ }
}
template<typename T>
void heap_delete(T* data)
{
data->~T();
- detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,data);
+ free_raw_heap_memory(data);
}
template<typename T>
Added: trunk/boost/thread/win32/tss.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/thread/win32/tss.hpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -0,0 +1,82 @@
+#ifndef BOOST_THREAD_WIN32_TSS_HPP
+#define BOOST_THREAD_WIN32_TSS_HPP
+
+namespace boost
+{
+ namespace detail
+ {
+ typedef void(*tss_cleanup_function)(void const* key,void* value);
+
+ BOOST_THREAD_DECL void set_tss_data(void const* key,tss_cleanup_function func,void* tss_data,bool cleanup_existing);
+ BOOST_THREAD_DECL void* get_tss_data(void const* key);
+ }
+
+ template <typename T>
+ class thread_specific_ptr
+ {
+ private:
+ thread_specific_ptr(thread_specific_ptr&);
+ thread_specific_ptr& operator=(thread_specific_ptr&);
+
+ static void delete_data(void const* self,void* value)
+ {
+ static_cast<thread_specific_ptr const*>(self)->cleanup((T*)value);
+ }
+
+ void cleanup(T* data) const
+ {
+ if(func)
+ {
+ func(data);
+ }
+ else
+ {
+ delete data;
+ }
+ }
+
+ void (*func)(T*);
+
+ public:
+ thread_specific_ptr():
+ func(0)
+ {}
+ explicit thread_specific_ptr(void (*func_)(T*)):
+ func(func_)
+ {}
+ ~thread_specific_ptr()
+ {
+ reset();
+ }
+
+ T* get() const
+ {
+ return static_cast<T*>(detail::get_tss_data(this));
+ }
+ T* operator->() const
+ {
+ return get();
+ }
+ T& operator*() const
+ {
+ return *get();
+ }
+ T* release()
+ {
+ T* const temp=get();
+ detail::set_tss_data(this,0,0,false);
+ return temp;
+ }
+ void reset(T* new_value=0)
+ {
+ T* const current_value=get();
+ if(current_value!=new_value)
+ {
+ detail::set_tss_data(this,delete_data,new_value,true);
+ }
+ }
+ };
+}
+
+
+#endif
Modified: trunk/libs/thread/build/Jamfile.v2
==============================================================================
--- trunk/libs/thread/build/Jamfile.v2 (original)
+++ trunk/libs/thread/build/Jamfile.v2 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -180,8 +180,6 @@
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
- win32/tss.cpp
- win32/tss_hooks.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
Modified: trunk/libs/thread/src/win32/thread.cpp
==============================================================================
--- trunk/libs/thread/src/win32/thread.cpp (original)
+++ trunk/libs/thread/src/win32/thread.cpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -12,7 +12,9 @@
#endif
#include <stdio.h>
#include <boost/thread/once.hpp>
+#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
+#include <boost/thread/detail/tss_hooks.hpp>
namespace boost
{
@@ -130,6 +132,19 @@
{}
};
+ struct tss_data_node
+ {
+ void const* key;
+ boost::detail::tss_cleanup_function func;
+ void* value;
+ tss_data_node* next;
+
+ tss_data_node(void const* key_,boost::detail::tss_cleanup_function func_,void* value_,
+ tss_data_node* next_):
+ key(key_),func(func_),value(value_),next(next_)
+ {}
+ };
+
}
namespace
@@ -139,17 +154,31 @@
boost::intrusive_ptr<detail::thread_data_base> current_thread_data(get_current_thread_data(),false);
if(current_thread_data)
{
- while(current_thread_data->thread_exit_callbacks)
+ while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
{
- detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
- current_thread_data->thread_exit_callbacks=current_node->next;
- if(current_node->func)
+ while(current_thread_data->thread_exit_callbacks)
{
- (*current_node->func)();
- boost::detail::heap_delete(current_node->func);
+ detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
+ current_thread_data->thread_exit_callbacks=current_node->next;
+ if(current_node->func)
+ {
+ (*current_node->func)();
+ boost::detail::heap_delete(current_node->func);
+ }
+ boost::detail::heap_delete(current_node);
+ }
+ while(current_thread_data->tss_data)
+ {
+ detail::tss_data_node* const current_node=current_thread_data->tss_data;
+ current_thread_data->tss_data=current_node->next;
+ if(current_node->func)
+ {
+ (*current_node->func)(current_node->key,current_node->value);
+ }
+ boost::detail::heap_delete(current_node);
}
- boost::detail::heap_delete(current_node);
}
+
}
set_current_thread_data(0);
}
@@ -210,14 +239,20 @@
void run()
{}
};
+
+ void make_external_thread_data()
+ {
+ externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
+ set_current_thread_data(me);
+ }
+
}
thread thread::self()
{
if(!get_current_thread_data())
{
- externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
- set_current_thread_data(me);
+ make_external_thread_data();
}
return thread(boost::intrusive_ptr<detail::thread_data_base>(get_current_thread_data()));
}
@@ -450,49 +485,83 @@
}
}
- namespace
+ namespace detail
{
- void NTAPI thread_exit_func_callback(HINSTANCE, DWORD, PVOID);
- typedef void (NTAPI* tls_callback)(HINSTANCE, DWORD, PVOID);
-
-#ifdef _MSC_VER
- extern "C"
+ void add_thread_exit_function(thread_exit_function_base* func)
{
- extern DWORD _tls_used; //the tls directory (located in .rdata segment)
- extern tls_callback __xl_a[], __xl_z[]; //tls initializers */
+ detail::thread_data_base* const current_thread_data(get_current_thread_data());
+ thread_exit_callback_node* const new_node=
+ heap_new<thread_exit_callback_node>(func,
+ current_thread_data->thread_exit_callbacks);
+ current_thread_data->thread_exit_callbacks=new_node;
}
-
-#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
-# pragma data_seg(push, old_seg)
-#endif
-
-#pragma data_seg(".CRT$XLB")
- tls_callback p_thread_callback = thread_exit_func_callback;
-#pragma data_seg()
-
-#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
-# pragma data_seg(pop, old_seg)
-#endif
-#endif
- void NTAPI thread_exit_func_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
+ tss_data_node* find_tss_data(void const* key)
{
- if((dwReason==DLL_THREAD_DETACH) || (dwReason==DLL_PROCESS_DETACH))
+ detail::thread_data_base* const current_thread_data(get_current_thread_data());
+ if(current_thread_data)
{
- run_thread_exit_callbacks();
+ detail::tss_data_node* current_node=current_thread_data->tss_data;
+ while(current_node)
+ {
+ if(current_node->key==key)
+ {
+ return current_node;
+ }
+ current_node=current_node->next;
+ }
}
+ return NULL;
}
- }
- namespace detail
- {
- void add_thread_exit_function(thread_exit_function_base* func)
+ void* get_tss_data(void const* key)
{
- thread_exit_callback_node* const new_node=
- heap_new<thread_exit_callback_node>(func,
- get_current_thread_data()->thread_exit_callbacks);
- get_current_thread_data()->thread_exit_callbacks=new_node;
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ return current_node->value;
+ }
+ return NULL;
+ }
+
+ void set_tss_data(void const* key,tss_cleanup_function func,void* tss_data,bool cleanup_existing)
+ {
+ tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ if(cleanup_existing && current_node->func)
+ {
+ (current_node->func)(current_node->key,current_node->value);
+ }
+ current_node->func=func;
+ current_node->value=tss_data;
+ }
+ else
+ {
+ detail::thread_data_base* current_thread_data(get_current_thread_data());
+ if(!current_thread_data)
+ {
+ make_external_thread_data();
+ current_thread_data=get_current_thread_data();
+ }
+ tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
+ current_thread_data->tss_data=new_node;
+ }
}
}
}
+
+extern "C" BOOST_THREAD_DECL void on_process_enter()
+{}
+
+extern "C" BOOST_THREAD_DECL void on_thread_enter()
+{}
+
+extern "C" BOOST_THREAD_DECL void on_process_exit()
+{}
+
+extern "C" BOOST_THREAD_DECL void on_thread_exit()
+{
+ boost::run_thread_exit_callbacks();
+}
+
Deleted: trunk/libs/thread/src/win32/tss.cpp
==============================================================================
--- trunk/libs/thread/src/win32/tss.cpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
+++ (empty file)
@@ -1,211 +0,0 @@
-// Copyright (C) 2001-2003 William E. Kempf
-// Copyright (C) 2006 Roland Schwarz
-// Copyright (C) 2007 Anthony Williams
-// Copyright (C) 2007 David Deakins
-//
-// 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)
-
-#include <boost/thread/detail/config.hpp>
-
-#include <boost/thread/tss.hpp>
-#ifndef BOOST_THREAD_NO_TSS_CLEANUP
-
-#include <boost/thread/once.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/exceptions.hpp>
-#include <vector>
-#include <string>
-#include <stdexcept>
-#include <cassert>
-
-#include <windows.h>
-#include <boost/thread/detail/tss_hooks.hpp>
-#if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
-# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
-#endif
-
-namespace {
-
-typedef std::vector<void*> tss_slots;
-typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
-
-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;
- DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
-int tss_data_use = 0;
-
-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;
- TlsFree(tss_data_native_key);
- tss_data_native_key=TLS_OUT_OF_INDEXES;
- }
-}
-
-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)
- {
- (*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
- (*slots)[i] = 0;
- }
- TlsSetValue(tss_data_native_key,0);
- tss_data_dec_use(lock);
- delete slots;
-}
-
-void init_tss_data()
-{
- 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();
-
- //Force the cleanup implementation library to be linked in
- tss_cleanup_implemented();
-
- //Allocate tls slot
- tss_data_native_key = TlsAlloc();
- if (tss_data_native_key == TLS_OUT_OF_INDEXES)
- return;
-
- // 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();
-}
-
-tss_slots* get_slots(bool alloc);
-
-void __cdecl tss_thread_exit()
-{
- tss_slots* slots = get_slots(false);
- if (slots)
- cleanup_slots(slots);
-}
-
-tss_slots* get_slots(bool alloc)
-{
- tss_slots* slots = 0;
-
- slots = static_cast<tss_slots*>(
- TlsGetValue(tss_data_native_key));
-
- if (slots == 0 && alloc)
- {
- std::auto_ptr<tss_slots> temp(new tss_slots);
-
- if (at_thread_exit(&tss_thread_exit) == -1)
- return 0;
- if (!TlsSetValue(tss_data_native_key, temp.get()))
- return 0;
- {
- boost::mutex::scoped_lock lock(*tss_data_mutex);
- tss_data_inc_use(lock);
- }
- slots = temp.release();
- }
-
- return slots;
-}
-
-} // namespace
-
-namespace boost {
-
-namespace detail {
-void tss::init(boost::function1<void, void*>* pcleanup)
-{
- boost::call_once(tss_data_once, &init_tss_data);
- if (tss_data_cleanup_handlers == 0)
- throw thread_resource_error();
- 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_inc_use(lock);
- }
- catch (...)
- {
- throw thread_resource_error();
- }
-}
-
-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);
-
- if (!slots)
- return 0;
-
- if (m_slot >= slots->size())
- return 0;
-
- return (*slots)[m_slot];
-}
-
-void tss::set(void* value)
-{
- tss_slots* slots = get_slots(true);
-
- if (!slots)
- throw boost::thread_resource_error();
-
- if (m_slot >= slots->size())
- {
- try
- {
- slots->resize(m_slot + 1);
- }
- catch (...)
- {
- throw boost::thread_resource_error();
- }
- }
-
- (*slots)[m_slot] = value;
-}
-
-void tss::cleanup(void* value)
-{
- boost::mutex::scoped_lock lock(*tss_data_mutex);
- (*(*tss_data_cleanup_handlers)[m_slot])(value);
-}
-
-} // namespace detail
-} // namespace boost
-
-#endif //BOOST_THREAD_NO_TSS_CLEANUP
Deleted: trunk/libs/thread/src/win32/tss_hooks.cpp
==============================================================================
--- trunk/libs/thread/src/win32/tss_hooks.cpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
+++ (empty file)
@@ -1,218 +0,0 @@
-// Copyright (C) 2004 Michael Glassford
-// Copyright (C) 2006 Roland Schwarz
-// Copyright (C) 2007 Anthony Williams
-// Copyright (C) 2007 David Deakins
-// Use, modification and distribution are subject to 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)
-
-#include <boost/thread/detail/config.hpp>
-
-#if defined(BOOST_HAS_WINTHREADS)
-
- #include <boost/thread/detail/tss_hooks.hpp>
-
- #include <boost/assert.hpp>
-// #include <boost/thread/mutex.hpp>
- #include <boost/thread/once.hpp>
-
- #include <list>
-
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
-
-# if defined(UNDER_CE) && !defined(TLS_OUT_OF_INDEXES)
-# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
-# endif
-
- namespace
- {
- class CScopedCSLock
- {
- public:
- CScopedCSLock(LPCRITICAL_SECTION cs) : lk(true), cs(cs) {
- ::EnterCriticalSection(cs);
- }
- ~CScopedCSLock() {
- if (lk) ::LeaveCriticalSection(cs);
- }
- void Unlock() {
- lk = false;
- ::LeaveCriticalSection(cs);
- }
- private:
- bool lk;
- LPCRITICAL_SECTION cs;
- };
-
- typedef std::list<thread_exit_handler> thread_exit_handlers;
-
- boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
- //boost::mutex* threadmon_mutex;
- // We don't use boost::mutex here, to avoid a memory leak report,
- // because we cannot delete it again easily.
- CRITICAL_SECTION threadmon_mutex;
- void init_threadmon_mutex(void)
- {
- //threadmon_mutex = new boost::mutex;
- //if (!threadmon_mutex)
- // throw boost::thread_resource_error();
- ::InitializeCriticalSection(&threadmon_mutex);
- }
-
- const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
- DWORD tls_key = invalid_tls_key;
-
- unsigned long attached_thread_count = 0;
- }
-
- /*
- Calls to DllMain() and tls_callback() are serialized by the OS;
- however, calls to at_thread_exit are not, so it must be protected
- by a mutex. Since we already need a mutex for at_thread_exit(),
- and since there is no guarantee that on_process_enter(),
- on_process_exit(), on_thread_enter(), and on_thread_exit()
- will be called only from DllMain() or tls_callback(), it makes
- sense to protect those, too.
- */
-
- extern "C" BOOST_THREAD_DECL int at_thread_exit(
- thread_exit_handler exit_handler
- )
- {
- boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
- //boost::mutex::scoped_lock lock(*threadmon_mutex);
- CScopedCSLock lock(&threadmon_mutex);
-
- //Allocate a tls slot if necessary.
-
- if (tls_key == invalid_tls_key)
- tls_key = TlsAlloc();
-
- if (tls_key == invalid_tls_key)
- return -1;
-
- //Get the exit handlers list for the current thread from tls.
-
- thread_exit_handlers* exit_handlers =
- static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
-
- if (!exit_handlers)
- {
- //No exit handlers list was created yet.
-
- try
- {
- //Attempt to create a new exit handlers list.
-
- exit_handlers = new thread_exit_handlers;
- if (!exit_handlers)
- return -1;
-
- //Attempt to store the list pointer in tls.
-
- if (TlsSetValue(tls_key, exit_handlers))
- ++attached_thread_count;
- else
- {
- delete exit_handlers;
- return -1;
- }
- }
- catch (...)
- {
- return -1;
- }
- }
-
- //Like the C runtime library atexit() function,
- //functions should be called in the reverse of
- //the order they are added, so push them on the
- //front of the list.
-
- try
- {
- exit_handlers->push_front(exit_handler);
- }
- catch (...)
- {
- return -1;
- }
-
- //Like the atexit() function, a result of zero
- //indicates success.
-
- return 0;
- }
-
- extern "C" BOOST_THREAD_DECL void on_process_enter(void)
- {
- boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
-// boost::mutex::scoped_lock lock(*threadmon_mutex);
- CScopedCSLock lock(&threadmon_mutex);
-
- BOOST_ASSERT(attached_thread_count == 0);
- }
-
- extern "C" BOOST_THREAD_DECL void on_process_exit(void)
- {
- boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
-// boost::mutex::scoped_lock lock(*threadmon_mutex);
- CScopedCSLock lock(&threadmon_mutex);
-
- BOOST_ASSERT(attached_thread_count == 0);
-
- //Free the tls slot if one was allocated.
-
- if (tls_key != invalid_tls_key)
- {
- TlsFree(tls_key);
- tls_key = invalid_tls_key;
- }
- }
-
- extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
- {
- //boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
- //boost::mutex::scoped_lock lock(*threadmon_mutex);
- }
-
- extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
- {
- boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
-// boost::mutex::scoped_lock lock(*threadmon_mutex);
- CScopedCSLock lock(&threadmon_mutex);
-
- //Get the exit handlers list for the current thread from tls.
-
- if (tls_key == invalid_tls_key)
- return;
-
- thread_exit_handlers* exit_handlers =
- static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
-
- //If a handlers list was found, use it.
-
- if (exit_handlers && TlsSetValue(tls_key, 0))
- {
- BOOST_ASSERT(attached_thread_count > 0);
- --attached_thread_count;
-
- //lock.unlock();
- lock.Unlock();
-
- //Call each handler and remove it from the list
-
- while (!exit_handlers->empty())
- {
- if (thread_exit_handler exit_handler = *exit_handlers->begin())
- (*exit_handler)();
- exit_handlers->pop_front();
- }
-
- delete exit_handlers;
- exit_handlers = 0;
- }
- }
-
-#endif //defined(BOOST_HAS_WINTHREADS)
Modified: trunk/libs/thread/src/win32/tss_pe.cpp
==============================================================================
--- trunk/libs/thread/src/win32/tss_pe.cpp (original)
+++ trunk/libs/thread/src/win32/tss_pe.cpp 2007-11-13 04:27:11 EST (Tue, 13 Nov 2007)
@@ -220,10 +220,13 @@
void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv)
{
+ OutputDebugString("on_tls_callback\n");
+
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
+ OutputDebugString("on_tls_callback: thread_exit\n");
on_thread_exit();
break;
}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk