Ticket #7066: boost_1_50_0_current_thread_tls_key.patch

File boost_1_50_0_current_thread_tls_key.patch, 4.2 KB (added by Pekka Seppänen <pekka.seppanen@…>, 10 years ago)

Move TLS related global static variables inside a function scope in order to ensure predictable initialization order.

  • thread.cpp

     
    3131{
    3232    namespace
    3333    {
    34 #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
    35         boost::once_flag current_thread_tls_init_flag;
    36 #else
    37         boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
     34// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
     35#ifndef TLS_OUT_OF_INDEXES
     36#  define BOOST_THREAD_TLS_OUT_OF_INDEXES_DEFINED
     37#  define TLS_OUT_OF_INDEXES 0xFFFFFFFF
    3838#endif
    39         #if defined(UNDER_CE)
    40         // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
    41         DWORD tls_out_of_index=0xFFFFFFFF;
    42         #else
    43         DWORD tls_out_of_index=TLS_OUT_OF_INDEXES;
    44         #endif
    45         DWORD current_thread_tls_key=tls_out_of_index;
     39        inline DWORD & get_current_thread_tls_key_ref()
     40        {
     41            // Static variables at global scope are initialized in a random
     42            // order. Thus, we may not initialize current_thread_tls_key at a
     43            // global scope or any statically allocated thread_specific_ptr
     44            // call may fail. Consider:
     45            //   a) A static (at global scope) thread_specific_ptr is
     46            //      initialized by some compiler generated code.
     47            //   b) create_current_thread_tls_key gets called. TlsAlloc()
     48            //      result is stored to current_thread_tls_key. (Assuming no
     49            //      errors happen.)
     50            //   c) Now a static (at global scope) current_thread_tls_key gets
     51            //      initialized (again, by compiler generated code) and thus
     52            //      the value we just got from TlsAlloc gets overwritten.
     53            //   d) Any following set_current_thread_data() calls will fail as
     54            //      current_thread_tls_key is TLS_OUT_OF_INDEXES.
     55            static DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
     56            return current_thread_tls_key;
     57        }
    4658
    4759        void create_current_thread_tls_key()
    4860        {
    4961            tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
    50             current_thread_tls_key=TlsAlloc();
    51             BOOST_ASSERT(current_thread_tls_key!=tls_out_of_index);
     62            get_current_thread_tls_key_ref() = TlsAlloc();
     63            BOOST_ASSERT(get_current_thread_tls_key_ref()!=TLS_OUT_OF_INDEXES);
    5264        }
    5365
    5466        void cleanup_tls_key()
    5567        {
    56             if(current_thread_tls_key!=tls_out_of_index)
     68            if(get_current_thread_tls_key_ref()!=TLS_OUT_OF_INDEXES)
    5769            {
    58                 TlsFree(current_thread_tls_key);
    59                 current_thread_tls_key=tls_out_of_index;
     70                TlsFree(get_current_thread_tls_key_ref());
     71                get_current_thread_tls_key_ref() = TLS_OUT_OF_INDEXES;
    6072            }
    6173        }
    6274
    6375        detail::thread_data_base* get_current_thread_data()
    6476        {
    65             if(current_thread_tls_key==tls_out_of_index)
     77            if(get_current_thread_tls_key_ref()==TLS_OUT_OF_INDEXES)
    6678            {
    6779                return 0;
    6880            }
    69             return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
     81            return (detail::thread_data_base*)TlsGetValue(get_current_thread_tls_key_ref());
    7082        }
    7183
    7284        void set_current_thread_data(detail::thread_data_base* new_data)
    7385        {
     86#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
     87            static boost::once_flag current_thread_tls_init_flag;
     88#else
     89            static boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
     90#endif
    7491            boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
    75             if(current_thread_tls_key!=tls_out_of_index)
    76                 BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
     92            if(get_current_thread_tls_key_ref()!=TLS_OUT_OF_INDEXES)
     93                BOOST_VERIFY(TlsSetValue(get_current_thread_tls_key_ref(),new_data));
    7794            else
    7895                boost::throw_exception(thread_resource_error());
    7996        }
    8097
     98#ifdef BOOST_THREAD_TLS_OUT_OF_INDEXES_DEFINED
     99#  undef TLS_OUT_OF_INDEXES
     100#  undef BOOST_THREAD_TLS_OUT_OF_INDEXES_DEFINED
     101#endif
     102
    81103#ifndef BOOST_HAS_THREADEX
    82104// Windows CE doesn't define _beginthreadex
    83105