Ticket #2361: tss.patch

File tss.patch, 38.4 KB (added by Andrey Semashev, 13 years ago)

The patch restores constant-time complexity of thread_specific_ptr

  • boost/thread/pthread/thread_heap_alloc.hpp

     
    55#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP
    66#define THREAD_HEAP_ALLOC_PTHREAD_HPP
    77
     8#include <memory>
    89#include <boost/config/abi_prefix.hpp>
    910
    1011namespace boost
    1112{
    1213    namespace detail
    1314    {
     15        template< typename T >
     16        struct heap_allocator :
     17            public std::allocator< T >
     18        {
     19            template< typename U >
     20            struct rebind
     21            {
     22                typedef heap_allocator< U > other;
     23            };
     24
     25            heap_allocator() {}
     26            heap_allocator(heap_allocator const& that):
     27                std::allocator< T >(static_cast< std::allocator< T > const& >(that))
     28            {
     29            }
     30            template< typename U >
     31            heap_allocator(heap_allocator< U > const& that):
     32                std::allocator< T >(static_cast< std::allocator< U > const& >(that))
     33            {
     34            }
     35        };
     36
    1437        template<typename T>
    1538        inline T* heap_new()
    1639        {
     
    7295        {
    7396            return heap_new_impl<T,A1&>(a1);
    7497        }
    75 
     98
    7699        template<typename T,typename A1,typename A2>
    77100        inline T* heap_new(A1 const& a1,A2 const& a2)
    78101        {
     
    218241        {
    219242            return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
    220243        }
    221 
    222 #endif
     244
     245#endif
    223246        template<typename T>
    224247        inline void heap_delete(T* data)
    225248        {
  • boost/thread/pthread/thread_data.hpp

     
    55// http://www.boost.org/LICENSE_1_0.txt)
    66// (C) Copyright 2007 Anthony Williams
    77
     8#include <vector>
    89#include <boost/thread/detail/config.hpp>
    910#include <boost/thread/exceptions.hpp>
    1011#include <boost/shared_ptr.hpp>
     
    1314#include <boost/optional.hpp>
    1415#include <pthread.h>
    1516#include "condition_variable_fwd.hpp"
     17#include "thread_heap_alloc.hpp"
    1618
    1719#include <boost/config/abi_prefix.hpp>
    1820
    1921namespace boost
    2022{
    2123    class thread;
    22 
     24
    2325    namespace detail
    2426    {
    2527        struct thread_exit_callback_node;
    26         struct tss_data_node;
     28        struct tss_cleanup_function;
     29        struct tss_data_node
     30        {
     31            void* value;
     32            shared_ptr< tss_cleanup_function > cleanup;
    2733
     34            tss_data_node():
     35                value(0)
     36            {
     37            }
     38        };
     39
    2840        struct thread_data_base;
    2941        typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
    30 
     42
    3143        struct BOOST_THREAD_DECL thread_data_base:
    3244            enable_shared_from_this<thread_data_base>
    3345        {
     46            typedef std::vector< tss_data_node, heap_allocator< tss_data_node > > tss_nodes;
     47
    3448            thread_data_ptr self;
    3549            pthread_t thread_handle;
    3650            boost::mutex data_mutex;
     
    4155            bool join_started;
    4256            bool joined;
    4357            boost::detail::thread_exit_callback_node* thread_exit_callbacks;
    44             boost::detail::tss_data_node* tss_data;
     58            tss_nodes tss_data;
    4559            bool interrupt_enabled;
    4660            bool interrupt_requested;
    4761            pthread_cond_t* current_cond;
    4862
    4963            thread_data_base():
    5064                done(false),join_started(false),joined(false),
    51                 thread_exit_callbacks(0),tss_data(0),
     65                thread_exit_callbacks(0),
    5266                interrupt_enabled(true),
    5367                interrupt_requested(false),
    5468                current_cond(0)
     
    7488                    throw thread_interrupted();
    7589                }
    7690            }
    77 
     91
    7892            void operator=(interruption_checker&);
    7993        public:
    8094            explicit interruption_checker(pthread_cond_t* cond):
     
    102116    namespace this_thread
    103117    {
    104118        void BOOST_THREAD_DECL yield();
    105 
     119
    106120        void BOOST_THREAD_DECL sleep(system_time const& abs_time);
    107 
     121
    108122        template<typename TimeDuration>
    109123        inline void sleep(TimeDuration const& rel_time)
    110124        {
  • boost/thread/tss.hpp

     
    1 #ifndef BOOST_THREAD_TSS_HPP
    2 #define BOOST_THREAD_TSS_HPP
    3 // Distributed under the Boost Software License, Version 1.0. (See
    4 // accompanying file LICENSE_1_0.txt or copy at
    5 // http://www.boost.org/LICENSE_1_0.txt)
    6 // (C) Copyright 2007-8 Anthony Williams
    7 
    8 #include <boost/thread/detail/config.hpp>
    9 #include <boost/shared_ptr.hpp>
    10 #include <boost/thread/detail/thread_heap_alloc.hpp>
    11 
    12 #include <boost/config/abi_prefix.hpp>
    13 
    14 namespace boost
    15 {
    16     namespace detail
    17     {
    18         struct tss_cleanup_function
    19         {
    20             virtual ~tss_cleanup_function()
    21             {}
    22 
    23             virtual void operator()(void* data)=0;
    24         };
    25 
    26         BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
    27         BOOST_THREAD_DECL void* get_tss_data(void const* key);
    28     }
    29 
    30     template <typename T>
    31     class thread_specific_ptr
    32     {
    33     private:
    34         thread_specific_ptr(thread_specific_ptr&);
    35         thread_specific_ptr& operator=(thread_specific_ptr&);
    36 
    37         struct delete_data:
    38             detail::tss_cleanup_function
    39         {
    40             void operator()(void* data)
    41             {
    42                 delete static_cast<T*>(data);
    43             }
    44         };
    45 
    46         struct run_custom_cleanup_function:
    47             detail::tss_cleanup_function
    48         {
    49             void (*cleanup_function)(T*);
    50 
    51             explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
    52                 cleanup_function(cleanup_function_)
    53             {}
    54 
    55             void operator()(void* data)
    56             {
    57                 cleanup_function(static_cast<T*>(data));
    58             }
    59         };
    60 
    61 
    62         boost::shared_ptr<detail::tss_cleanup_function> cleanup;
    63 
    64     public:
    65         thread_specific_ptr():
    66             cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
    67         {}
    68         explicit thread_specific_ptr(void (*func_)(T*))
    69         {
    70             if(func_)
    71             {
    72                 cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
    73             }
    74         }
    75         ~thread_specific_ptr()
    76         {
    77             reset();
    78         }
    79 
    80         T* get() const
    81         {
    82             return static_cast<T*>(detail::get_tss_data(this));
    83         }
    84         T* operator->() const
    85         {
    86             return get();
    87         }
    88         T& operator*() const
    89         {
    90             return *get();
    91         }
    92         T* release()
    93         {
    94             T* const temp=get();
    95             detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
    96             return temp;
    97         }
    98         void reset(T* new_value=0)
    99         {
    100             T* const current_value=get();
    101             if(current_value!=new_value)
    102             {
    103                 detail::set_tss_data(this,cleanup,new_value,true);
    104             }
    105         }
    106     };
    107 }
    108 
    109 #include <boost/config/abi_suffix.hpp>
    110 
    111 #endif
     1#ifndef BOOST_THREAD_TSS_HPP
     2#define BOOST_THREAD_TSS_HPP
     3// Distributed under the Boost Software License, Version 1.0. (See
     4// accompanying file LICENSE_1_0.txt or copy at
     5// http://www.boost.org/LICENSE_1_0.txt)
     6// (C) Copyright 2007-8 Anthony Williams
     7
     8#include <boost/thread/detail/config.hpp>
     9#include <boost/shared_ptr.hpp>
     10#include <boost/make_shared.hpp>
     11#include <boost/thread/detail/thread_heap_alloc.hpp>
     12
     13#include <boost/config/abi_prefix.hpp>
     14
     15namespace boost
     16{
     17    namespace detail
     18    {
     19        typedef unsigned int tss_key_t;
     20
     21        struct tss_cleanup_function
     22        {
     23            virtual ~tss_cleanup_function()
     24            {}
     25
     26            virtual void operator()(void* data)=0;
     27        };
     28
     29        BOOST_THREAD_DECL tss_key_t allocate_tss_key();
     30        BOOST_THREAD_DECL void set_tss_data(tss_key_t key,boost::shared_ptr<tss_cleanup_function> const& func,void* tss_data,bool call_cleanup);
     31        BOOST_THREAD_DECL void* get_tss_data(tss_key_t key);
     32    }
     33
     34    template <typename T>
     35    class thread_specific_ptr
     36    {
     37    private:
     38        thread_specific_ptr(thread_specific_ptr&);
     39        thread_specific_ptr& operator=(thread_specific_ptr&);
     40
     41        struct delete_data:
     42            detail::tss_cleanup_function
     43        {
     44            void operator()(void* data)
     45            {
     46                delete static_cast<T*>(data);
     47            }
     48        };
     49
     50        struct run_custom_cleanup_function:
     51            detail::tss_cleanup_function
     52        {
     53            void (*cleanup_function)(T*);
     54
     55            explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
     56                cleanup_function(cleanup_function_)
     57            {}
     58
     59            void operator()(void* data)
     60            {
     61                cleanup_function(static_cast<T*>(data));
     62            }
     63        };
     64
     65
     66        detail::tss_key_t key;
     67        boost::shared_ptr<detail::tss_cleanup_function> cleanup;
     68
     69    public:
     70        thread_specific_ptr():
     71            key(detail::allocate_tss_key()),
     72            cleanup(boost::allocate_shared< delete_data >(detail::heap_allocator< delete_data >()))
     73        {}
     74        explicit thread_specific_ptr(void (*func_)(T*)):
     75            key(detail::allocate_tss_key())
     76        {
     77            if(func_)
     78            {
     79                cleanup = boost::allocate_shared< run_custom_cleanup_function >(
     80                    detail::heap_allocator< run_custom_cleanup_function >(), func_);
     81            }
     82        }
     83        ~thread_specific_ptr()
     84        {
     85            detail::set_tss_data(key,boost::shared_ptr<detail::tss_cleanup_function>(),0,true);
     86        }
     87
     88        T* get() const
     89        {
     90            return static_cast<T*>(detail::get_tss_data(key));
     91        }
     92        T* operator->() const
     93        {
     94            return get();
     95        }
     96        T& operator*() const
     97        {
     98            return *get();
     99        }
     100        T* release()
     101        {
     102            T* const temp=get();
     103            detail::set_tss_data(key,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
     104            return temp;
     105        }
     106        void reset(T* new_value=0)
     107        {
     108            T* const current_value=get();
     109            if(current_value!=new_value)
     110            {
     111                detail::set_tss_data(key,cleanup,new_value,true);
     112            }
     113        }
     114    };
     115}
     116
     117#include <boost/config/abi_suffix.hpp>
     118
     119#endif
  • boost/thread/win32/thread_heap_alloc.hpp

     
    88#include "thread_primitives.hpp"
    99#include <stdexcept>
    1010#include <boost/assert.hpp>
     11#include <boost/compatibility/cpp_c_headers/cstddef>
    1112
    1213#if defined( BOOST_USE_WINDOWS_H )
    1314# include <windows.h>
     
    6970        {
    7071            BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
    7172        }
    72 
     73
     74        template< typename T >
     75        struct heap_allocator
     76        {
     77            template< typename U >
     78            struct rebind
     79            {
     80                typedef heap_allocator< U > other;
     81            };
     82
     83            typedef std::size_t size_type;
     84            typedef std::ptrdiff_t difference_type;
     85            typedef T value_type;
     86            typedef value_type* pointer;
     87            typedef const value_type* const_pointer;
     88            typedef value_type& reference;
     89            typedef const value_type& const_reference;
     90
     91            heap_allocator() {}
     92            heap_allocator(heap_allocator const&) {}
     93            template< typename U >
     94            heap_allocator(heap_allocator< U > const&) {}
     95
     96            pointer address(reference x) const { return &x; }
     97            const_pointer address(const_reference x) const { return &x; }
     98
     99            pointer allocate(size_type n, const void* = 0)
     100            {
     101                return static_cast< pointer >(
     102                    detail::allocate_raw_heap_memory(static_cast< unsigned >(n * sizeof(value_type))));
     103            }
     104            void deallocate(pointer p, size_type)
     105            {
     106                detail::free_raw_heap_memory(p);
     107            }
     108
     109            void construct(pointer p, const_reference val)
     110            {
     111                new (p) value_type(val);
     112            }
     113            void destroy(pointer p)
     114            {
     115                p->~value_type();
     116            }
     117
     118            size_type max_size() const
     119            {
     120                return (~static_cast< std::size_t >(0)) / sizeof(value_type);
     121            }
     122
     123            template< typename U >
     124            bool operator== (heap_allocator< U > const&) const { return true; }
     125            template< typename U >
     126            bool operator!= (heap_allocator< U > const&) const { return false; }
     127        };
     128
    73129        template<typename T>
    74130        inline T* heap_new()
    75131        {
     
    225281        {
    226282            return heap_new_impl<T,A1&>(a1);
    227283        }
    228 
     284
    229285        template<typename T,typename A1,typename A2>
    230286        inline T* heap_new(A1 const& a1,A2 const& a2)
    231287        {
     
    371427        {
    372428            return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
    373429        }
    374 
    375 #endif
     430
     431#endif
    376432        template<typename T>
    377433        inline void heap_delete(T* data)
    378434        {
  • boost/thread/win32/thread_data.hpp

     
    55// http://www.boost.org/LICENSE_1_0.txt)
    66// (C) Copyright 2008 Anthony Williams
    77
     8#include <vector>
    89#include <boost/thread/detail/config.hpp>
     10#include <boost/shared_ptr.hpp>
    911#include <boost/intrusive_ptr.hpp>
    1012#include <boost/thread/thread_time.hpp>
    1113#include "thread_primitives.hpp"
     
    1820    namespace detail
    1921    {
    2022        struct thread_exit_callback_node;
    21         struct tss_data_node;
     23        struct tss_cleanup_function;
     24        struct tss_data_node
     25        {
     26            void* value;
     27            shared_ptr< tss_cleanup_function > cleanup;
    2228
     29            tss_data_node():
     30                value(0)
     31            {
     32            }
     33        };
     34
    2335        struct thread_data_base;
    2436        void intrusive_ptr_add_ref(thread_data_base * p);
    2537        void intrusive_ptr_release(thread_data_base * p);
    26 
     38
    2739        struct thread_data_base
    2840        {
     41            typedef std::vector< tss_data_node, heap_allocator< tss_data_node > > tss_nodes;
     42
    2943            long count;
    3044            detail::win32::handle_manager thread_handle;
    3145            detail::win32::handle_manager interruption_handle;
    3246            boost::detail::thread_exit_callback_node* thread_exit_callbacks;
    33             boost::detail::tss_data_node* tss_data;
     47            tss_nodes tss_data;
    3448            bool interruption_enabled;
    3549            unsigned id;
    3650
    3751            thread_data_base():
    3852                count(0),thread_handle(detail::win32::invalid_handle_value),
    3953                interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
    40                 thread_exit_callbacks(0),tss_data(0),
     54                thread_exit_callbacks(0),
    4155                interruption_enabled(true),
    4256                id(0)
    4357            {}
     
    4862            {
    4963                BOOST_INTERLOCKED_INCREMENT(&p->count);
    5064            }
    51 
     65
    5266            friend void intrusive_ptr_release(thread_data_base * p)
    5367            {
    5468                if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
     
    6175            {
    6276                BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
    6377            }
    64 
     78
    6579            typedef detail::win32::handle native_handle_type;
    6680
    6781            virtual void run()=0;
     
    130144            {
    131145                return milliseconds==~uintmax_t(0);
    132146            }
    133 
    134147
     148
    135149            static timeout sentinel()
    136150            {
    137151                return timeout(sentinel_type());
     
    139153        private:
    140154            struct sentinel_type
    141155            {};
    142 
     156
    143157            explicit timeout(sentinel_type):
    144158                start(0),milliseconds(~uintmax_t(0)),relative(true)
    145159            {}
     
    170184            interruptible_wait(abs_time);
    171185        }
    172186    }
    173 
     187
    174188}
    175189
    176190#include <boost/config/abi_suffix.hpp>
  • libs/thread/src/win32/thread.cpp

     
    1717#include <boost/thread/once.hpp>
    1818#include <boost/thread/tss.hpp>
    1919#include <boost/assert.hpp>
     20#include <boost/detail/interlocked.hpp>
    2021#include <boost/thread/detail/tss_hooks.hpp>
    2122#include <boost/date_time/posix_time/conversion.hpp>
    2223
     
    7677            delete data;
    7778            return ret;
    7879        }
    79 
     80
    8081        typedef void* uintptr_t;
    8182
    8283        inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
     
    107108            {}
    108109        };
    109110
    110         struct tss_data_node
    111         {
    112             void const* key;
    113             boost::shared_ptr<boost::detail::tss_cleanup_function> func;
    114             void* value;
    115             tss_data_node* next;
    116 
    117             tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
    118                           tss_data_node* next_):
    119                 key(key_),func(func_),value(value_),next(next_)
    120             {}
    121         };
    122 
    123111    }
    124112
    125113    namespace
     
    129117            detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
    130118            if(current_thread_data)
    131119            {
    132                 while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
     120                bool all_tss_released;
     121                do
    133122                {
    134123                    while(current_thread_data->thread_exit_callbacks)
    135124                    {
     
    142131                        }
    143132                        boost::detail::heap_delete(current_node);
    144133                    }
    145                     while(current_thread_data->tss_data)
     134
     135                    all_tss_released = true;
     136                    for (detail::tss_key_t key = 0; key < current_thread_data->tss_data.size(); ++key)
    146137                    {
    147                         detail::tss_data_node* const current_node=current_thread_data->tss_data;
    148                         current_thread_data->tss_data=current_node->next;
    149                         if(current_node->func)
     138                        detail::tss_data_node& node = current_thread_data->tss_data[key];
     139                        shared_ptr< detail::tss_cleanup_function > cleanup;
     140                        cleanup.swap(node.cleanup);
     141                        if (cleanup && node.value)
    150142                        {
    151                             (*current_node->func)(current_node->value);
     143                            all_tss_released = false;
     144                            (*cleanup)(node.value);
    152145                        }
    153                         boost::detail::heap_delete(current_node);
    154146                    }
    155147                }
    156 
     148                while(!all_tss_released || current_thread_data->thread_exit_callbacks);
     149
    157150                set_current_thread_data(0);
    158151            }
    159152        }
    160 
     153
    161154        unsigned __stdcall thread_start_function(void* param)
    162155        {
    163156            detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
     
    209202                ++count;
    210203                interruption_enabled=false;
    211204            }
    212 
     205
    213206            void run()
    214207            {}
    215208        private:
     
    233226            }
    234227            return current_thread_data;
    235228        }
    236 
     229
    237230    }
    238231
    239232    thread::~thread()
    240233    {
    241234        detach();
    242235    }
    243 
     236
    244237    thread::id thread::get_id() const
    245238    {
    246239        return thread::id(get_thread_info());
     
    274267        }
    275268        return true;
    276269    }
    277 
     270
    278271    void thread::detach()
    279272    {
    280273        release_handle();
     
    285278        lock_guard<mutex> l1(thread_info_mutex);
    286279        thread_info=0;
    287280    }
    288 
     281
    289282    void thread::interrupt()
    290283    {
    291284        detail::thread_data_ptr local_thread_info=get_thread_info();
     
    294287            local_thread_info->interrupt();
    295288        }
    296289    }
    297 
     290
    298291    bool thread::interruption_requested() const
    299292    {
    300293        detail::thread_data_ptr local_thread_info=get_thread_info();
    301294        return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
    302295    }
    303 
     296
    304297    unsigned thread::hardware_concurrency()
    305298    {
    306299        SYSTEM_INFO info={0};
    307300        GetSystemInfo(&info);
    308301        return info.dwNumberOfProcessors;
    309302    }
    310 
     303
    311304    thread::native_handle_type thread::native_handle()
    312305    {
    313306        detail::thread_data_ptr local_thread_info=get_thread_info();
     
    361354                return due_time;
    362355            }
    363356        }
    364 
    365357
     358
    366359        bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
    367360        {
    368361            detail::win32::handle handles[3]={0};
     
    382375            }
    383376
    384377            detail::win32::handle_manager timer_handle;
    385 
     378
    386379#ifndef UNDER_CE
    387380            unsigned const min_timer_wait_period=20;
    388 
     381
    389382            if(!target_time.is_sentinel())
    390383            {
    391384                detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
     
    396389                    if(timer_handle!=0)
    397390                    {
    398391                        LARGE_INTEGER due_time=get_due_time(target_time);
    399 
     392
    400393                        bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
    401394                        if(set_time_succeeded)
    402395                        {
     
    412405                }
    413406            }
    414407#endif
    415 
     408
    416409            bool const using_timer=timeout_index!=~0u;
    417410            detail::timeout::remaining_time time_left(0);
    418 
     411
    419412            do
    420413            {
    421414                if(!using_timer)
    422415                {
    423416                    time_left=target_time.remaining_milliseconds();
    424417                }
    425 
     418
    426419                if(handle_count)
    427420                {
    428421                    unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
     
    469462                throw thread_interrupted();
    470463            }
    471464        }
    472 
     465
    473466        bool interruption_enabled()
    474467        {
    475468            return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
    476469        }
    477 
     470
    478471        bool interruption_requested()
    479472        {
    480473            return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
     
    484477        {
    485478            detail::win32::Sleep(0);
    486479        }
    487 
     480
    488481        disable_interruption::disable_interruption():
    489482            interruption_was_enabled(interruption_enabled())
    490483        {
     
    493486                get_current_thread_data()->interruption_enabled=false;
    494487            }
    495488        }
    496 
     489
    497490        disable_interruption::~disable_interruption()
    498491        {
    499492            if(get_current_thread_data())
     
    509502                get_current_thread_data()->interruption_enabled=true;
    510503            }
    511504        }
    512 
     505
    513506        restore_interruption::~restore_interruption()
    514507        {
    515508            if(get_current_thread_data())
     
    530523            current_thread_data->thread_exit_callbacks=new_node;
    531524        }
    532525
    533         tss_data_node* find_tss_data(void const* key)
     526        tss_key_t allocate_tss_key()
    534527        {
    535             detail::thread_data_base* const current_thread_data(get_current_thread_data());
    536             if(current_thread_data)
    537             {
    538                 detail::tss_data_node* current_node=current_thread_data->tss_data;
    539                 while(current_node)
    540                 {
    541                     if(current_node->key==key)
    542                     {
    543                         return current_node;
    544                     }
    545                     current_node=current_node->next;
    546                 }
    547             }
    548             return NULL;
     528            static long counter = 0;
     529            return static_cast< tss_key_t >(BOOST_INTERLOCKED_INCREMENT(&counter)) - 1;
    549530        }
    550531
    551         void* get_tss_data(void const* key)
     532        void* get_tss_data(tss_key_t key)
    552533        {
    553             if(tss_data_node* const current_node=find_tss_data(key))
     534            detail::thread_data_base* const current_thread_data(get_current_thread_data());
     535            if(current_thread_data && key < current_thread_data->tss_data.size())
    554536            {
    555                 return current_node->value;
     537                return current_thread_data->tss_data[key].value;
    556538            }
    557539            return NULL;
    558540        }
    559 
    560         void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
     541
     542        void set_tss_data(tss_key_t key,boost::shared_ptr<tss_cleanup_function> const& func,void* tss_data,bool call_cleanup)
    561543        {
    562             if(tss_data_node* const current_node=find_tss_data(key))
     544            detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
     545            if (current_thread_data)
    563546            {
    564                 if(cleanup_existing && current_node->func.get())
     547                if (key >= current_thread_data->tss_data.size())
    565548                {
    566                     (*current_node->func)(current_node->value);
     549                    current_thread_data->tss_data.resize(key + 1);
    567550                }
    568                 current_node->func=func;
    569                 current_node->value=tss_data;
     551
     552                {
     553                    tss_data_node& node = current_thread_data->tss_data[key];
     554                    if (call_cleanup && node.cleanup)
     555                    {
     556                        (*node.cleanup)(node.value);
     557                    }
     558                }
     559                {
     560                    // need to reload node reference since the cleanup might have called tss_data.resize
     561                    tss_data_node& node = current_thread_data->tss_data[key];
     562                    node.cleanup = func;
     563                    node.value = tss_data;
     564                }
    570565            }
    571             else
    572             {
    573                 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
    574                 tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
    575                 current_thread_data->tss_data=new_node;
    576             }
    577566        }
    578567    }
    579568}
  • libs/thread/src/pthread/thread.cpp

     
    22// William E. Kempf
    33// Copyright (C) 2007-8 Anthony Williams
    44//
    5 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
     5//  Distributed under the Boost Software License, Version 1.0. (See accompanying
    66//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    77
    88#include <boost/thread/detail/config.hpp>
     
    1313#include <boost/thread/locks.hpp>
    1414#include <boost/thread/once.hpp>
    1515#include <boost/thread/tss.hpp>
     16#include <boost/detail/atomic_count.hpp>
    1617#ifdef __linux__
    1718#include <sys/sysinfo.h>
    1819#elif defined(__APPLE__) || defined(__FreeBSD__)
     
    4243            {}
    4344        };
    4445
    45         struct tss_data_node
    46         {
    47             void const* key;
    48             boost::shared_ptr<boost::detail::tss_cleanup_function> func;
    49             void* value;
    50             tss_data_node* next;
    51 
    52             tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
    53                           tss_data_node* next_):
    54                 key(key_),func(func_),value(value_),next(next_)
    55             {}
    56         };
    57 
    5846        namespace
    5947        {
    6048            boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
     
    6755                    boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
    6856                    if(thread_info)
    6957                    {
    70                         while(thread_info->tss_data || thread_info->thread_exit_callbacks)
     58                        bool all_tss_released;
     59                        do
    7160                        {
    7261                            while(thread_info->thread_exit_callbacks)
    7362                            {
     
    8069                                }
    8170                                delete current_node;
    8271                            }
    83                             while(thread_info->tss_data)
     72
     73                            all_tss_released = true;
     74                            for (tss_key_t key = 0; key < thread_info->tss_data.size(); ++key)
    8475                            {
    85                                 detail::tss_data_node* const current_node=thread_info->tss_data;
    86                                 thread_info->tss_data=current_node->next;
    87                                 if(current_node->func)
     76                                tss_data_node& node = thread_info->tss_data[key];
     77                                shared_ptr< tss_cleanup_function > cleanup;
     78                                cleanup.swap(node.cleanup);
     79                                if (cleanup && node.value)
    8880                                {
    89                                     (*current_node->func)(current_node->value);
     81                                    all_tss_released = false;
     82                                    (*cleanup)(node.value);
    9083                                }
    91                                 delete current_node;
    9284                            }
    9385                        }
     86                        while(!all_tss_released || thread_info->thread_exit_callbacks);
     87
    9488                        thread_info->self.reset();
    9589                    }
    9690                }
    9791            }
    98 
    9992
     93            detail::atomic_count& get_tss_key_counter()
     94            {
     95                static detail::atomic_count counter(0);
     96                return counter;
     97            }
     98
    10099            void create_current_thread_tls_key()
    101100            {
    102101                BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
     102                // initialize tss key counter
     103                get_tss_key_counter();
    103104            }
    104105        }
    105 
     106
    106107        boost::detail::thread_data_base* get_current_thread_data()
    107108        {
    108109            boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
     
    115116            BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
    116117        }
    117118    }
    118 
     119
    119120    namespace
    120121    {
    121122        extern "C"
     
    155156            {
    156157                interrupt_enabled=false;
    157158            }
    158 
     159
    159160            void run()
    160161            {}
    161162
     
    217218        if(local_thread_info)
    218219        {
    219220            bool do_join=false;
    220 
     221
    221222            {
    222223                unique_lock<mutex> lock(local_thread_info->data_mutex);
    223224                while(!local_thread_info->done)
     
    225226                    local_thread_info->done_condition.wait(lock);
    226227                }
    227228                do_join=!local_thread_info->join_started;
    228 
     229
    229230                if(do_join)
    230231                {
    231232                    local_thread_info->join_started=true;
     
    246247                local_thread_info->joined=true;
    247248                local_thread_info->done_condition.notify_all();
    248249            }
    249 
     250
    250251            lock_guard<mutex> l1(thread_info_mutex);
    251252            if(thread_info==local_thread_info)
    252253            {
     
    261262        if(local_thread_info)
    262263        {
    263264            bool do_join=false;
    264 
     265
    265266            {
    266267                unique_lock<mutex> lock(local_thread_info->data_mutex);
    267268                while(!local_thread_info->done)
     
    272273                    }
    273274                }
    274275                do_join=!local_thread_info->join_started;
    275 
     276
    276277                if(do_join)
    277278                {
    278279                    local_thread_info->join_started=true;
     
    293294                local_thread_info->joined=true;
    294295                local_thread_info->done_condition.notify_all();
    295296            }
    296 
     297
    297298            lock_guard<mutex> l1(thread_info_mutex);
    298299            if(thread_info==local_thread_info)
    299300            {
     
    316317            lock_guard<mutex> l1(thread_info_mutex);
    317318            thread_info.swap(local_thread_info);
    318319        }
    319 
     320
    320321        if(local_thread_info)
    321322        {
    322323            lock_guard<mutex> lock(local_thread_info->data_mutex);
     
    331332
    332333    namespace this_thread
    333334    {
    334 
     335
    335336        void sleep(const system_time& st)
    336337        {
    337338            detail::thread_data_base* const thread_info=detail::get_current_thread_data();
    338 
     339
    339340            if(thread_info)
    340341            {
    341342                unique_lock<mutex> lk(thread_info->sleep_mutex);
     
    344345            else
    345346            {
    346347                xtime const xt=get_xtime(st);
    347 
     348
    348349                for (int foo=0; foo < 5; ++foo)
    349350                {
    350351#   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
     
    354355#   elif defined(BOOST_HAS_NANOSLEEP)
    355356                    timespec ts;
    356357                    to_timespec_duration(xt, ts);
    357 
     358
    358359                    //  nanosleep takes a timespec that is an offset, not
    359360                    //  an absolute time.
    360361                    nanosleep(&ts, 0);
     
    458459            return pthread_t();
    459460        }
    460461    }
    461 
    462 
    463462
     463
     464
    464465    namespace this_thread
    465466    {
    466467        thread::id get_id()
     
    482483                }
    483484            }
    484485        }
    485 
     486
    486487        bool interruption_enabled()
    487488        {
    488489            boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
    489490            return thread_info && thread_info->interrupt_enabled;
    490491        }
    491 
     492
    492493        bool interruption_requested()
    493494        {
    494495            boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
     
    511512                detail::get_current_thread_data()->interrupt_enabled=false;
    512513            }
    513514        }
    514 
     515
    515516        disable_interruption::~disable_interruption()
    516517        {
    517518            if(detail::get_current_thread_data())
     
    527528                detail::get_current_thread_data()->interrupt_enabled=true;
    528529            }
    529530        }
    530 
     531
    531532        restore_interruption::~restore_interruption()
    532533        {
    533534            if(detail::get_current_thread_data())
     
    547548            current_thread_data->thread_exit_callbacks=new_node;
    548549        }
    549550
    550         tss_data_node* find_tss_data(void const* key)
     551        tss_key_t allocate_tss_key()
    551552        {
    552             detail::thread_data_base* const current_thread_data(get_current_thread_data());
    553             if(current_thread_data)
    554             {
    555                 detail::tss_data_node* current_node=current_thread_data->tss_data;
    556                 while(current_node)
    557                 {
    558                     if(current_node->key==key)
    559                     {
    560                         return current_node;
    561                     }
    562                     current_node=current_node->next;
    563                 }
    564             }
    565             return NULL;
     553            return static_cast< tss_key_t >(++get_tss_key_counter()) - 1;
    566554        }
    567555
    568         void* get_tss_data(void const* key)
     556        void* get_tss_data(tss_key_t key)
    569557        {
    570             if(tss_data_node* const current_node=find_tss_data(key))
     558            detail::thread_data_base* const current_thread_data(get_current_thread_data());
     559            if(current_thread_data && key < current_thread_data->tss_data.size())
    571560            {
    572                 return current_node->value;
     561                return current_thread_data->tss_data[key].value;
    573562            }
    574563            return NULL;
    575564        }
    576 
    577         void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
     565
     566        void set_tss_data(tss_key_t key,boost::shared_ptr<tss_cleanup_function> const& func,void* tss_data,bool call_cleanup)
    578567        {
    579             if(tss_data_node* const current_node=find_tss_data(key))
     568            detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
     569            if (current_thread_data)
    580570            {
    581                 if(cleanup_existing && current_node->func)
     571                if (key >= current_thread_data->tss_data.size())
    582572                {
    583                     (*current_node->func)(current_node->value);
     573                    current_thread_data->tss_data.resize(key + 1);
    584574                }
    585                 current_node->func=func;
    586                 current_node->value=tss_data;
     575
     576                {
     577                    tss_data_node& node = current_thread_data->tss_data[key];
     578                    if (call_cleanup && node.cleanup)
     579                    {
     580                        (*node.cleanup)(node.value);
     581                    }
     582                }
     583                {
     584                    // need to reload node reference since the cleanup might have called tss_data.resize
     585                    tss_data_node& node = current_thread_data->tss_data[key];
     586                    node.cleanup = func;
     587                    node.value = tss_data;
     588                }
    587589            }
    588             else
    589             {
    590                 detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
    591                 tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
    592                 current_thread_data->tss_data=new_node;
    593             }
    594590        }
    595591    }
    596592
     
    660656//     void thread_group::interrupt_all()
    661657//     {
    662658//         boost::lock_guard<mutex> guard(m_mutex);
    663 
     659
    664660//         for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
    665661//             it!=end;
    666662//             ++it)
     
    668664//             (*it)->interrupt();
    669665//         }
    670666//     }
    671 
    672667
     668
    673669//     size_t thread_group::size() const
    674670//     {
    675671//         return m_threads.size();