Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r86390 - in trunk: boost/sync/detail libs/sync/build libs/sync/src
From: andrey.semashev_at_[hidden]
Date: 2013-10-22 09:31:21


Author: andysem
Date: 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013)
New Revision: 86390
URL: http://svn.boost.org/trac/boost/changeset/86390

Log:
Added preliminary implementation of internal TLS.

Added:
   trunk/libs/sync/build/
   trunk/libs/sync/build/Jamfile.v2 (contents, props changed)
   trunk/libs/sync/src/
   trunk/libs/sync/src/tss_manager.hpp (contents, props changed)
   trunk/libs/sync/src/tss_pthread.cpp (contents, props changed)
   trunk/libs/sync/src/tss_windows.cpp (contents, props changed)
   trunk/libs/sync/src/tss_windows_dll.cpp (contents, props changed)
   trunk/libs/sync/src/tss_windows_hooks.hpp (contents, props changed)
   trunk/libs/sync/src/tss_windows_pe.cpp (contents, props changed)
Text files modified:
   trunk/boost/sync/detail/tss.hpp | 7
   trunk/libs/sync/build/Jamfile.v2 | 179 ++++++++++++++++++++
   trunk/libs/sync/src/tss_manager.hpp | 246 ++++++++++++++++++++++++++++
   trunk/libs/sync/src/tss_pthread.cpp | 129 ++++++++++++++
   trunk/libs/sync/src/tss_windows.cpp | 188 +++++++++++++++++++++
   trunk/libs/sync/src/tss_windows_dll.cpp | 86 +++++++++
   trunk/libs/sync/src/tss_windows_hooks.hpp | 75 ++++++++
   trunk/libs/sync/src/tss_windows_pe.cpp | 348 ++++++++++++++++++++++++++++++++++++++++
   8 files changed, 1256 insertions(+), 2 deletions(-)

Modified: trunk/boost/sync/detail/tss.hpp
==============================================================================
--- trunk/boost/sync/detail/tss.hpp Tue Oct 22 09:28:27 2013 (r86389)
+++ trunk/boost/sync/detail/tss.hpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -30,7 +30,7 @@
 namespace detail {
 
 typedef unsigned int thread_specific_key;
-typedef void (*at_thread_exit_callback)(void*) BOOST_NOEXCEPT;
+typedef void (*at_thread_exit_callback)(void*);
 
 /*!
  * \brief Adds a callback to be invoked when the current thread terminates
@@ -47,10 +47,13 @@
  * \brief Creates a thread-specific key
  *
  * \param callback The callback to be called when a thread that used the key terminates. The callback will also be called when the key is deleted.
+ * \param cleanup_at_delete If \c true, The \a callback will be called for all non-NULL thread-specific values associated with this key at the point
+ * of \c delete_thread_specific_key call. The user's code should be prepared that the cleanup function can be called not only in the context of the
+ * thread that initialized the specific value.
  *
  * \returns The created key.
  */
-BOOST_SYNC_API thread_specific_key new_thread_specific_key(at_thread_exit_callback callback);
+BOOST_SYNC_API thread_specific_key new_thread_specific_key(at_thread_exit_callback callback, bool cleanup_at_delete);
 /*!
  * \brief Destroys the thread-specific key and all associated values.
  *

Added: trunk/libs/sync/build/Jamfile.v2
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/build/Jamfile.v2 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,179 @@
+# Copyright 2006-2007 Roland Schwarz.
+# Copyright 2007 Anthony Williams
+# Copyright 2011-2012 Vicente J.Botet Escriba.
+# Copyright 2013 Andrey Semashev
+# 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)
+
+#########################################################################
+# The Boost.Sync library can be built on top of different API's on Windows.
+# Currently this is the win32 API and the pthreads API.
+# Pthread is native on unix variants.
+# To get pthread on windows you need the pthread win32 library
+# http://sourceware.org/pthreads-win32 which is available under LGPL.
+#
+# You need to provide the include path and lib path in the variables
+# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
+# paths in site-config.jam, user-config.jam or in the environment.
+# Boost.Sync also makes use of the threadapi feature defined by Boost.Thread:
+# <threadapi>win32 and <threadapi>pthread.
+#
+# To request the pthread variant on windows, from boost root you would
+# say e.g:
+# bjam msvc-8.0 --with-sync install threadapi=pthread
+#########################################################################
+
+import os ;
+import feature ;
+import indirect ;
+import path ;
+import configure ;
+
+project boost/sync
+ : source-location ../src
+ : requirements
+ <threading>multi
+ <link>static:<define>BOOST_SYNC_STATIC_LINK=1
+ <link>shared:<define>BOOST_SYNC_DYN_LINK=1
+ <define>BOOST_SYNC_BUILDING=1
+ <target-os>windows:<define>BOOST_USE_WINDOWS_H=1
+ <target-os>windows:<define>WIN32_LEAN_AND_MEAN=1
+ <library>/boost/system//boost_system
+
+ : usage-requirements # pass these requirement to dependents (i.e. users)
+ <link>static:<define>BOOST_SYNC_STATIC_LINK=1
+ <link>shared:<define>BOOST_SYNC_DYN_LINK=1
+ <library>/boost/system//boost_system
+ ;
+
+rule win32_pthread_paths ( properties * )
+{
+ local result ;
+ local PTW32_INCLUDE ;
+ local PTW32_LIB ;
+ PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
+ PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
+ PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
+ PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
+ PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
+ PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
+
+ if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
+ {
+ if ! $(.notified)
+ {
+ echo "************************************************************" ;
+ echo "Trying to build Boost.Sync with pthread support." ;
+ echo "If you need pthread you should specify the paths." ;
+ echo "You can specify them in site-config.jam, user-config.jam" ;
+ echo "or in the environment." ;
+ echo "For example:" ;
+ echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
+ echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
+ echo "************************************************************" ;
+ .notified = true ;
+ }
+ }
+ else
+ {
+ local include_path = [ path.make $(PTW32_INCLUDE) ] ;
+ local lib_path = [ path.make $(PTW32_LIB) ] ;
+ local libname = pthread ;
+ if <toolset>msvc in $(properties)
+ {
+ libname = $(libname)VC2.lib ;
+ }
+ if <toolset>gcc in $(properties)
+ {
+ libname = lib$(libname)GC2.a ;
+ }
+ lib_path = [ path.glob $(lib_path) : $(libname) ] ;
+ if ! $(lib_path)
+ {
+ if ! $(.notified)
+ {
+ echo "************************************************************" ;
+ echo "Trying to build Boost.Sync with pthread support." ;
+ echo "But the library" $(libname) "could not be found in path" ;
+ echo $(PTW32_LIB) ;
+ echo "************************************************************" ;
+ .notified = true ;
+ }
+ }
+ else
+ {
+ result += <include>$(include_path) ;
+ result += <library>$(lib_path) ;
+ }
+ }
+ return $(result) ;
+}
+
+rule usage-requirements ( properties * )
+{
+ local result ;
+ if <threadapi>pthread in $(properties)
+ {
+ if <target-os>windows in $(properties)
+ {
+ result += <define>BOOST_SYNC_USE_PTHREAD ;
+ result += [ win32_pthread_paths $(properties) ] ;
+ # TODO: What is for static linking? Is the <library> also needed
+ # in that case?
+ }
+ }
+
+ return $(result) ;
+}
+
+rule requirements ( properties * )
+{
+ local result ;
+
+ if <threadapi>pthread in $(properties)
+ {
+ result += <define>BOOST_SYNC_USE_PTHREAD ;
+ if <target-os>windows in $(properties)
+ {
+ local paths = [ win32_pthread_paths $(properties) ] ;
+ if $(paths)
+ {
+ result += $(paths) ;
+ }
+ else
+ {
+ result = <build>no ;
+ }
+ }
+ }
+
+ return $(result) ;
+}
+
+alias sync_platform_sources
+ :
+ tss_windows_dll.cpp
+ tss_windows_pe.cpp
+ tss_windows.cpp
+ tss_pthread.cpp
+ :
+ <target-os>windows
+ ;
+
+alias sync_platform_sources
+ :
+ tss_pthread.cpp
+ ;
+
+explicit sync_platform_sources ;
+
+lib boost_sync
+ :
+ sync_platform_sources
+ :
+ <conditional>@requirements
+ :
+ :
+ <conditional>@usage-requirements
+ ;

Added: trunk/libs/sync/src/tss_manager.hpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_manager.hpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,246 @@
+/*
+ * 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)
+ *
+ * (C) Copyright 2013 Andrey Semashev
+ */
+/*!
+ * \file tss_manager.hpp
+ *
+ * \brief This header is the Boost.Sync library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
+ */
+
+#ifndef BOOST_SYNC_IMPL_TSS_MANAGER_HPP_INCLUDED_
+#define BOOST_SYNC_IMPL_TSS_MANAGER_HPP_INCLUDED_
+
+#include <stack>
+#include <vector>
+#include <boost/assert.hpp>
+#include <boost/intrusive/options.hpp>
+#include <boost/intrusive/list.hpp>
+#include <boost/intrusive/list_hook.hpp>
+#include <boost/sync/detail/config.hpp>
+#include <boost/sync/locks/lock_guard.hpp>
+#include <boost/sync/locks/unique_lock.hpp>
+#include <boost/sync/mutexes/mutex.hpp>
+#include <boost/sync/detail/tss.hpp>
+#include <boost/sync/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+class tss_manager
+{
+public:
+ typedef intrusive::list_base_hook<
+ intrusive::tag< struct for_thread_context_list >,
+ intrusive::link_mode< intrusive::safe_link >
+ > thread_context_list_hook;
+
+ class thread_context :
+ public thread_context_list_hook
+ {
+ friend class tss_manager;
+
+ private:
+ struct at_exit_entry
+ {
+ at_thread_exit_callback callback;
+ void* context;
+ };
+
+ private:
+ std::vector< void* > m_storage;
+ std::vector< at_exit_entry > m_at_exit_functions;
+
+ public:
+ void* get_value(thread_specific_key key) const BOOST_NOEXCEPT
+ {
+ if (key < m_storage.size())
+ return m_storage[key];
+ else
+ return NULL;
+ }
+
+ void set_value(thread_specific_key key, void* value)
+ {
+ if (key >= m_storage.size())
+ m_storage.resize(key + 1, static_cast< void* >(NULL));
+ m_storage[key] = value;
+ }
+
+ void add_at_exit_entry(at_thread_exit_callback callback, void* context)
+ {
+ at_exit_entry entry;
+ entry.callback = callback;
+ entry.context = context;
+ m_at_exit_functions.push_back(entry);
+ }
+ };
+
+private:
+ typedef sync::mutex mutex_type;
+
+ typedef intrusive::list<
+ thread_context,
+ intrusive::base_hook< thread_context_list_hook >,
+ intrusive::constant_time_size< false >
+ > thread_context_list;
+
+ struct cleanup_info
+ {
+ at_thread_exit_callback cleanup;
+ bool cleanup_at_delete;
+ };
+
+private:
+ //! Thread synchronization primitive
+ mutex_type m_mutex;
+ //! The list of thread contexts
+ thread_context_list m_thread_contexts;
+ //! The list of cleanup functions for TLS
+ std::vector< cleanup_info > m_storage_cleanup;
+ //! The list of TLS keys released
+ std::stack< thread_specific_key > m_freed_keys;
+
+public:
+ BOOST_DEFAULTED_FUNCTION(tss_manager(), {})
+
+ ~tss_manager()
+ {
+ while (!m_thread_contexts.empty())
+ destroy_thread_context(&m_thread_contexts.front());
+ }
+
+ thread_context* create_thread_context()
+ {
+ thread_context* p = new thread_context();
+
+ sync::lock_guard< mutex_type > lock(m_mutex);
+ m_thread_contexts.push_back(*p);
+
+ return p;
+ }
+
+ void destroy_thread_context(thread_context* p) BOOST_NOEXCEPT
+ {
+ // Run cleanup functions
+ while (!p->m_at_exit_functions.empty())
+ {
+ std::vector< thread_context::at_exit_entry > at_exit_functions;
+ at_exit_functions.swap(p->m_at_exit_functions);
+
+ for (std::vector< thread_context::at_exit_entry >::reverse_iterator it = at_exit_functions.rbegin(), end = at_exit_functions.rend(); it != end; ++it)
+ {
+ it->callback(it->context);
+ }
+ }
+
+ // Destroy TLS
+ while (!p->m_storage.empty())
+ {
+ std::vector< void* > storage;
+ storage.swap(p->m_storage);
+ for (thread_specific_key key = 0, n = storage.size(); key < n; ++key)
+ {
+ void* const value = storage[key];
+ if (value)
+ {
+ const at_thread_exit_callback cleanup = m_storage_cleanup[key].cleanup;
+ if (cleanup)
+ cleanup(value);
+ }
+ }
+ }
+
+ // Destroy the context
+ {
+ sync::lock_guard< mutex_type > lock(m_mutex);
+ m_thread_contexts.erase(m_thread_contexts.iterator_to(*p));
+ }
+ delete p;
+ }
+
+ thread_specific_key new_key(at_thread_exit_callback cleanup, bool cleanup_at_delete)
+ {
+ sync::lock_guard< mutex_type > lock(m_mutex);
+
+ // See if we can recycle some key
+ thread_specific_key key;
+ if (!m_freed_keys.empty())
+ {
+ key = m_freed_keys.top();
+ m_freed_keys.pop();
+ cleanup_info& info = m_storage_cleanup[key];
+ info.cleanup = cleanup;
+ info.cleanup_at_delete = cleanup_at_delete;
+ }
+ else
+ {
+ key = static_cast< thread_specific_key >(m_storage_cleanup.size());
+ cleanup_info info;
+ info.cleanup = cleanup;
+ info.cleanup_at_delete = cleanup_at_delete;
+ m_storage_cleanup.push_back(info);
+ }
+
+ return key;
+ }
+
+ void delete_key(thread_specific_key key)
+ {
+ sync::unique_lock< mutex_type > lock(m_mutex);
+
+ BOOST_ASSERT(key < m_storage_cleanup.size());
+
+ cleanup_info& info = m_storage_cleanup[key];
+ if (info.cleanup_at_delete)
+ {
+ std::vector< void* > storage;
+ const at_thread_exit_callback cleanup = info.cleanup;
+ info.cleanup = NULL;
+
+ for (thread_context_list::iterator it = m_thread_contexts.begin(), end = m_thread_contexts.end(); it != end; ++it)
+ {
+ if (it->m_storage.size() > key && it->m_storage[key] != NULL)
+ {
+ if (cleanup)
+ storage.push_back(it->m_storage[key]);
+ it->m_storage[key] = NULL;
+ }
+ }
+
+ m_freed_keys.push(key);
+
+ lock.unlock();
+
+ // Run cleanup routines while the lock is released
+ for (std::vector< void* >::iterator it = storage.begin(), end = storage.end(); it != end; ++it)
+ {
+ cleanup(*it);
+ }
+ }
+ }
+
+ BOOST_DELETED_FUNCTION(tss_manager(tss_manager const&))
+ BOOST_DELETED_FUNCTION(tss_manager& operator= (tss_manager const&))
+};
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#include <boost/sync/detail/footer.hpp>
+
+#endif // BOOST_SYNC_IMPL_TSS_MANAGER_HPP_INCLUDED_

Added: trunk/libs/sync/src/tss_pthread.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_pthread.cpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,129 @@
+/*
+ * 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)
+ *
+ * (C) Copyright 2004 Michael Glassford
+ * (C) Copyright 2013 Andrey Semashev
+ */
+/*!
+ * \file tss_pthread.cpp
+ *
+ * \brief This header is the Boost.Sync library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
+ */
+
+#include <boost/sync/detail/config.hpp>
+
+#if !defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI)
+
+#include <cstddef>
+#include <cstdlib>
+#include <pthread.h>
+#include <boost/sync/detail/tss.hpp>
+#include "tss_manager.hpp"
+#include <boost/sync/detail/header.hpp>
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace {
+
+static pthread_once_t init_tss_once_flag = PTHREAD_ONCE_INIT;
+static tss_manager* tss_mgr = NULL;
+static pthread_key_t tss_key;
+
+extern "C" {
+
+static void tss_cleanup(void* p)
+{
+ if (tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(p))
+ {
+ tss_mgr->destroy_thread_context(ctx);
+ }
+}
+
+static void init_tss()
+{
+ try
+ {
+ tss_mgr = new tss_manager();
+ }
+ catch (...)
+ {
+ std::abort();
+ }
+
+ if (pthread_key_create(&tss_key, &tss_cleanup) != 0)
+ std::abort();
+}
+
+} // extern "C"
+
+} // namespace
+
+BOOST_SYNC_API void add_thread_exit_callback(at_thread_exit_callback callback, void* context)
+{
+ pthread_once(&init_tss_once_flag, &init_tss);
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(pthread_getspecific(tss_key));
+
+ if (!ctx)
+ {
+ ctx = tss_mgr->create_thread_context();
+ pthread_setspecific(tss_key, ctx);
+ }
+
+ ctx->add_at_exit_entry(callback, context);
+}
+
+BOOST_SYNC_API thread_specific_key new_thread_specific_key(at_thread_exit_callback callback, bool cleanup_at_delete)
+{
+ pthread_once(&init_tss_once_flag, &init_tss);
+ return tss_mgr->new_key(callback, cleanup_at_delete);
+}
+
+BOOST_SYNC_API void delete_thread_specific_key(thread_specific_key key) BOOST_NOEXCEPT
+{
+ try
+ {
+ tss_mgr->delete_key(key);
+ }
+ catch (...)
+ {
+ std::abort();
+ }
+}
+
+BOOST_SYNC_API void* get_thread_specific(thread_specific_key key)
+{
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(pthread_getspecific(tss_key));
+ if (ctx)
+ return ctx->get_value(key);
+ return NULL;
+}
+
+BOOST_SYNC_API void set_thread_specific(thread_specific_key key, void* p)
+{
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(pthread_getspecific(tss_key));
+
+ if (!ctx)
+ {
+ ctx = tss_mgr->create_thread_context();
+ pthread_setspecific(tss_key, ctx);
+ }
+
+ ctx->set_value(key, p);
+}
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#include <boost/sync/detail/footer.hpp>
+
+#endif // !defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI)

Added: trunk/libs/sync/src/tss_windows.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_windows.cpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,188 @@
+/*
+ * 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)
+ *
+ * (C) Copyright 2004 Michael Glassford
+ * (C) Copyright 2013 Andrey Semashev
+ */
+/*!
+ * \file tss_windows.cpp
+ *
+ * \brief This header is the Boost.Sync library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
+ */
+
+#include <boost/sync/detail/config.hpp>
+
+#if defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI)
+
+#include <cstddef>
+#include <cstdlib>
+#include <boost/sync/detail/interlocked.hpp>
+#include <boost/sync/detail/tss.hpp>
+#include "tss_manager.hpp"
+#include "tss_windows_hooks.hpp"
+#include <windows.h>
+#include <boost/sync/detail/header.hpp>
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace {
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+static INIT_ONCE init_tss_once_flag = INIT_ONCE_STATIC_INIT;
+#else
+static long init_tss_once_flag = 0;
+#endif
+static tss_manager* tss_mgr = NULL;
+static DWORD tss_key = TLS_OUT_OF_INDEXES;
+
+extern "C" {
+
+static BOOL WINAPI init_tss(void*, void*, void**)
+{
+ try
+ {
+ tss_mgr = new tss_manager();
+ }
+ catch (...)
+ {
+ std::abort();
+ }
+
+ tss_key = TlsAlloc();
+ if (tss_key == TLS_OUT_OF_INDEXES)
+ std::abort();
+
+ return TRUE;
+}
+
+} // extern "C"
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+BOOST_FORCEINLINE void init_tss_once()
+{
+ InitOnceExecuteOnce(&init_tss_once_flag, (PINIT_ONCE_FN)&init_tss, NULL, NULL);
+}
+
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+BOOST_FORCEINLINE void init_tss_once()
+{
+ if (const_cast< long volatile& >(init_tss_once_flag) != 2)
+ {
+ while (true)
+ {
+ long old_val = BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&init_tss_once_flag, 1, 0);
+ if (old_val == 2)
+ break;
+ else if (old_val == 1)
+ SwitchToThread();
+ else
+ {
+ init_tss(NUll, NULL, NULL);
+ BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&init_tss_once_flag, 2);
+ break;
+ }
+ }
+ }
+}
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+} // namespace
+
+namespace windows {
+
+void on_process_enter()
+{
+}
+
+void on_process_exit()
+{
+}
+
+void on_thread_enter()
+{
+}
+
+void on_thread_exit()
+{
+ // This callback may be called before tss manager is initialized
+ init_tss_once();
+ if (tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(TlsGetValue(tss_key)))
+ {
+ tss_mgr->destroy_thread_context(ctx);
+ }
+}
+
+} // namespace windows
+
+BOOST_SYNC_API void add_thread_exit_callback(at_thread_exit_callback callback, void* context)
+{
+ init_tss_once();
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(pthread_getspecific(tss_key));
+
+ if (!ctx)
+ {
+ ctx = tss_mgr->create_thread_context();
+ pthread_setspecific(tss_key, ctx);
+ }
+
+ ctx->add_at_exit_entry(callback, context);
+}
+
+BOOST_SYNC_API thread_specific_key new_thread_specific_key(at_thread_exit_callback callback, bool cleanup_at_delete)
+{
+ init_tss_once();
+ return tss_mgr->new_key(callback, cleanup_at_delete);
+}
+
+BOOST_SYNC_API void delete_thread_specific_key(thread_specific_key key) BOOST_NOEXCEPT
+{
+ try
+ {
+ tss_mgr->delete_key(key);
+ }
+ catch (...)
+ {
+ std::abort();
+ }
+}
+
+BOOST_SYNC_API void* get_thread_specific(thread_specific_key key)
+{
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(TlsGetValue(tss_key));
+ if (ctx)
+ return ctx->get_value(key);
+ return NULL;
+}
+
+BOOST_SYNC_API void set_thread_specific(thread_specific_key key, void* p)
+{
+ tss_manager::thread_context* ctx = static_cast< tss_manager::thread_context* >(TlsGetValue(tss_key));
+
+ if (!ctx)
+ {
+ ctx = tss_mgr->create_thread_context();
+ TlsSetValue(tss_key, ctx);
+ }
+
+ ctx->set_value(key, p);
+}
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#include <boost/sync/detail/footer.hpp>
+
+#endif // defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI)

Added: trunk/libs/sync/src/tss_windows_dll.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_windows_dll.cpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,86 @@
+// (C) Copyright Michael Glassford 2004.
+// 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/sync/detail/config.hpp>
+
+#if defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI) && defined(BOOST_SYNC_DYN_LINK)
+
+#include <windows.h>
+#include "tss_windows_hooks.hpp"
+
+#if defined(__BORLANDC__)
+extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+#elif defined(_WIN32_WCE)
+extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+#else
+extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
+#endif
+{
+ switch(dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ boost::on_process_enter();
+ boost::on_thread_enter();
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ boost::on_thread_enter();
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ boost::on_thread_exit();
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ boost::on_thread_exit();
+ boost::on_process_exit();
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace windows {
+
+void tss_cleanup_implemented()
+{
+ /*
+ This function's sole purpose is to cause a link error in cases where
+ automatic tss cleanup is not implemented by Boost.Threads as a
+ reminder that user code is responsible for calling the necessary
+ functions at the appropriate times (and for implementing an a
+ tss_cleanup_implemented() function to eliminate the linker's
+ missing symbol error).
+
+ If Boost.Threads later implements automatic tss cleanup in cases
+ where it currently doesn't (which is the plan), the duplicate
+ symbol error will warn the user that their custom solution is no
+ longer needed and can be removed.
+ */
+}
+
+} // namespace windows
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#endif // defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI) && defined(BOOST_SYNC_DYN_LINK)

Added: trunk/libs/sync/src/tss_windows_hooks.hpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_windows_hooks.hpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,75 @@
+/*
+ * 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)
+ *
+ * (C) Copyright 2004 Michael Glassford
+ * (C) Copyright 2013 Andrey Semashev
+ */
+/*!
+ * \file tss_windows_hooks.hpp
+ *
+ * \brief This header is the Boost.Sync library implementation, see the library documentation
+ * at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html.
+ */
+
+#ifndef BOOST_SYNC_IMPL_TSS_WINDOWS_HOOKS_HPP_INCLUDED_
+#define BOOST_SYNC_IMPL_TSS_WINDOWS_HOOKS_HPP_INCLUDED_
+
+#include <boost/sync/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace windows {
+
+/*!
+ * Function to be called when the exe or dll that uses Boost.Sync first starts or is first loaded.
+ * Should be called only before the first call to \c on_thread_enter. Called automatically by
+ * Boost.Sync when a method for doing so has been discovered. May be omitted; may be called multiple times.
+ */
+void on_process_enter();
+
+/*!
+ * Function to be called when the exe or dll that uses Boost.Sync first starts or is first loaded.
+ * Should be called only after the last call to \c on_thread_exit. Called automatically by Boost.Sync
+ * when a method for doing so has been discovered. Must not be omitted; may be called multiple times.
+ */
+void on_process_exit();
+
+/*!
+ * Function to be called just after a thread starts in an exe or dll that uses Boost.Sync.
+ * Must be called in the context of the thread that is starting. Called automatically by Boost.Sync
+ * when a method for doing so has been discovered. May be omitted; may be called multiple times.
+ */
+void on_thread_enter();
+
+/*!
+ * Function to be called just be fore a thread ends in an exe or dll that uses Boost.Sync.
+ * Must be called in the context of the thread that is ending. Called automatically by Boost.Sync
+ * when a method for doing so has been discovered. Must not be omitted; may be called multiple times.
+ */
+void on_thread_exit();
+
+/*!
+ * Dummy function used both to detect whether tss cleanup cleanup has been implemented and to force
+ * it to be linked into the Boost.Sync library.
+ */
+void tss_cleanup_implemented();
+
+} // namespace windows
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#endif // BOOST_SYNC_IMPL_TSS_WINDOWS_HOOKS_HPP_INCLUDED_

Added: trunk/libs/sync/src/tss_windows_pe.cpp
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/libs/sync/src/tss_windows_pe.cpp 2013-10-22 09:31:21 EDT (Tue, 22 Oct 2013) (r86390)
@@ -0,0 +1,348 @@
+// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
+// (C) Copyright 2007 Roland Schwarz
+// (C) Copyright 2007 Anthony Williams
+// (C) Copyright 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/sync/detail/config.hpp>
+
+#if defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI) && defined(BOOST_SYNC_STATIC_LINK)
+
+#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
+
+#include <cstdlib>
+#include <windows.h>
+#include "tss_windows_hooks.hpp"
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace windows {
+
+void tss_cleanup_implemented()
+{
+}
+
+} // namespace windows
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+namespace {
+
+void NTAPI on_tls_callback(void*, DWORD dwReason, PVOID)
+{
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ {
+ boost::on_thread_exit();
+ break;
+ }
+ }
+}
+
+} // namespace
+
+#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32_MAJOR_VERSION > 3) || \
+ ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION >= 18))
+extern "C"
+{
+ PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
+}
+#else
+extern "C" {
+
+ void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter;
+ void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit;
+ void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit;
+
+ ULONG __tls_index__ = 0;
+ char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
+ char __tls_start__ __attribute__((section(".tls"))) = 0;
+
+
+ PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
+ PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
+}
+extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
+{
+ (DWORD) &__tls_start__,
+ (DWORD) &__tls_end__,
+ (DWORD) &__tls_index__,
+ (DWORD) (&__crt_xl_start__+1),
+ (DWORD) 0,
+ (DWORD) 0
+};
+#endif
+
+
+#elif defined(_MSC_VER) && !defined(UNDER_CE)
+
+#include <stdlib.h>
+#include <windows.h>
+#include "tss_windows_hooks.hpp"
+
+// _pRawDllMainOrig can be defined by including boost/thread/win32/mfc_thread_init.hpp
+// into your dll; it ensures that MFC-Dll-initialization will be done properly
+// The following code is adapted from the MFC-Dll-init code
+/*
+ * _pRawDllMainOrig MUST be an extern const variable, which will be aliased to
+ * _pDefaultRawDllMainOrig if no real user definition is present, thanks to the
+ * alternatename directive.
+ */
+
+// work at least with _MSC_VER 1500 (MSVC++ 9.0, VS 2008)
+#if (_MSC_VER >= 1500)
+
+extern "C" {
+extern BOOL (WINAPI * const _pRawDllMainOrig)(HANDLE, DWORD, LPVOID);
+extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HANDLE, DWORD, LPVOID) = NULL;
+#if defined (_M_IX86)
+#pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig")
+#elif defined (_M_X64) || defined (_M_ARM)
+#pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig")
+#else /* defined (_M_X64) || defined (_M_ARM) */
+#error Unsupported platform
+#endif /* defined (_M_X64) || defined (_M_ARM) */
+}
+
+#endif
+
+
+//Definitions required by implementation
+
+#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
+ typedef void (__cdecl *_PVFV)();
+ #define INIRETSUCCESS
+ #define PVAPI void __cdecl
+#else
+ typedef int (__cdecl *_PVFV)();
+ #define INIRETSUCCESS 0
+ #define PVAPI int __cdecl
+#endif
+
+typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
+
+//Symbols for connection to the runtime environment
+
+extern "C"
+{
+ extern DWORD _tls_used; //the tls directory (located in .rdata segment)
+ extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */
+}
+
+namespace
+{
+ //Forward declarations
+
+ static PVAPI on_tls_prepare();
+ static PVAPI on_process_init();
+ static PVAPI on_process_term();
+ static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
+
+ //The .CRT$Xxx information is taken from Codeguru:
+ //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
+
+#if (_MSC_VER >= 1400)
+#pragma section(".CRT$XIU",long,read)
+#pragma section(".CRT$XCU",long,read)
+#pragma section(".CRT$XTU",long,read)
+#pragma section(".CRT$XLC",long,read)
+ __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
+ __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
+ __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
+ __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
+#else
+ #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+ # pragma data_seg(push, old_seg)
+ #endif
+ //Callback to run tls glue code first.
+ //I don't think it is necessary to run it
+ //at .CRT$XIB level, since we are only
+ //interested in thread detachement. But
+ //this could be changed easily if required.
+
+ #pragma data_seg(".CRT$XIU")
+ static _PVFV p_tls_prepare = on_tls_prepare;
+ #pragma data_seg()
+
+ //Callback after all global ctors.
+
+ #pragma data_seg(".CRT$XCU")
+ static _PVFV p_process_init = on_process_init;
+ #pragma data_seg()
+
+ //Callback for tls notifications.
+
+ #pragma data_seg(".CRT$XLB")
+ _TLSCB p_thread_callback = on_tls_callback;
+ #pragma data_seg()
+ //Callback for termination.
+
+ #pragma data_seg(".CRT$XTU")
+ static _PVFV p_process_term = on_process_term;
+ #pragma data_seg()
+ #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+ # pragma data_seg(pop, old_seg)
+ #endif
+#endif
+
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable:4189)
+#endif
+
+PVAPI on_tls_prepare()
+{
+ //The following line has an important side effect:
+ //if the TLS directory is not already there, it will
+ //be created by the linker. In other words, it forces a tls
+ //directory to be generated by the linker even when static tls
+ //(i.e. __declspec(thread)) is not used.
+ //The volatile should prevent the optimizer
+ //from removing the reference.
+
+ DWORD volatile dw = _tls_used;
+
+ #if (_MSC_VER < 1300) // 1300 == VC++ 7.0
+ _TLSCB* pfbegin = __xl_a;
+ _TLSCB* pfend = __xl_z;
+ _TLSCB* pfdst = pfbegin;
+ //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
+
+ //The following loop will merge the address pointers
+ //into a contiguous area, since the tlssup code seems
+ //to require this (at least on MSVC 6)
+
+ while (pfbegin < pfend)
+ {
+ if (*pfbegin != 0)
+ {
+ *pfdst = *pfbegin;
+ ++pfdst;
+ }
+ ++pfbegin;
+ }
+
+ *pfdst = 0;
+ #endif
+
+ return INIRETSUCCESS;
+}
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+PVAPI on_process_init()
+{
+ //Schedule on_thread_exit() to be called for the main
+ //thread before destructors of global objects have been
+ //called.
+
+ //It will not be run when 'quick' exiting the
+ //library; however, this is the standard behaviour
+ //for destructors of global objects, so that
+ //shouldn't be a problem.
+
+ atexit(boost::on_thread_exit);
+
+ //Call Boost process entry callback here
+
+ boost::on_process_enter();
+
+ return INIRETSUCCESS;
+}
+
+PVAPI on_process_term()
+{
+ boost::on_process_exit();
+ return INIRETSUCCESS;
+}
+
+void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
+{
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ boost::on_thread_exit();
+ break;
+ }
+}
+
+#if (_MSC_VER >= 1500)
+BOOL WINAPI dll_callback(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
+#else
+BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
+#endif
+{
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ boost::on_thread_exit();
+ break;
+ case DLL_PROCESS_DETACH:
+ boost::on_process_exit();
+ break;
+ }
+
+#if (_MSC_VER >= 1500)
+ if( _pRawDllMainOrig )
+ {
+ return _pRawDllMainOrig(hInstance, dwReason, lpReserved);
+ }
+#endif
+ return true;
+}
+
+} //namespace
+
+extern "C"
+{
+ extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID) = &dll_callback;
+}
+
+namespace boost {
+
+namespace sync {
+
+namespace detail {
+
+namespace windows {
+
+void tss_cleanup_implemented()
+{
+ /*
+ This function's sole purpose is to cause a link error in cases where
+ automatic tss cleanup is not implemented by Boost.Threads as a
+ reminder that user code is responsible for calling the necessary
+ functions at the appropriate times (and for implementing an a
+ tss_cleanup_implemented() function to eliminate the linker's
+ missing symbol error).
+
+ If Boost.Threads later implements automatic tss cleanup in cases
+ where it currently doesn't (which is the plan), the duplicate
+ symbol error will warn the user that their custom solution is no
+ longer needed and can be removed.
+ */
+}
+
+} // namespace windows
+
+} // namespace detail
+
+} // namespace sync
+
+} // namespace boost
+
+#endif //defined(_MSC_VER) && !defined(UNDER_CE)
+
+#endif //defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI) && defined(BOOST_SYNC_STATIC_LINK)


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