aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/libs/thread/src
diff options
context:
space:
mode:
authorDaniil Cherednik <dan.cherednik@gmail.com>2022-09-21 20:17:38 +0300
committerDaniil Cherednik <dan.cherednik@gmail.com>2022-09-21 20:17:38 +0300
commite6c9b17192c56494adba359d5e132c431b241191 (patch)
tree6f2449871a118a0e8919ce842b1174e06cb470ef /contrib/restricted/boost/libs/thread/src
parent285021ab1aac39e84b269d9bacd4deee69cf63fc (diff)
downloadydb-e6c9b17192c56494adba359d5e132c431b241191.tar.gz
Ydb stable 22-4-2122.4.21
x-stable-origin-commit: e89099581237299a132feafb5b58af59ebd0468a
Diffstat (limited to 'contrib/restricted/boost/libs/thread/src')
-rw-r--r--contrib/restricted/boost/libs/thread/src/tss_null.cpp38
-rw-r--r--contrib/restricted/boost/libs/thread/src/win32/thread.cpp973
-rw-r--r--contrib/restricted/boost/libs/thread/src/win32/thread_primitives.cpp140
-rw-r--r--contrib/restricted/boost/libs/thread/src/win32/tss_dll.cpp85
-rw-r--r--contrib/restricted/boost/libs/thread/src/win32/tss_pe.cpp337
5 files changed, 1573 insertions, 0 deletions
diff --git a/contrib/restricted/boost/libs/thread/src/tss_null.cpp b/contrib/restricted/boost/libs/thread/src/tss_null.cpp
new file mode 100644
index 0000000000..b5029f1996
--- /dev/null
+++ b/contrib/restricted/boost/libs/thread/src/tss_null.cpp
@@ -0,0 +1,38 @@
+// (C) Copyright Michael Glassford 2004.
+// (C) Copyright 2007 Anthony Williams
+// 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) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
+
+namespace boost
+{
+ /*
+ This file is a "null" implementation of tss cleanup; it's
+ purpose is to to eliminate link errors in cases
+ where it is known that tss cleanup is not needed.
+ */
+
+ void tss_cleanup_implemented(void)
+ {
+ /*
+ 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.
+ */
+ }
+
+}
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)
diff --git a/contrib/restricted/boost/libs/thread/src/win32/thread.cpp b/contrib/restricted/boost/libs/thread/src/win32/thread.cpp
new file mode 100644
index 0000000000..53a4ce6a5b
--- /dev/null
+++ b/contrib/restricted/boost/libs/thread/src/win32/thread.cpp
@@ -0,0 +1,973 @@
+// 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 2007 Anthony Williams
+// (C) Copyright 2007 David Deakins
+// (C) Copyright 2011-2018 Vicente J. Botet Escriba
+
+//#define BOOST_THREAD_VERSION 3
+
+#include <boost/winapi/config.hpp>
+#include <boost/thread/thread_only.hpp>
+#include <boost/thread/once.hpp>
+#include <boost/thread/tss.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/detail/tss_hooks.hpp>
+#include <boost/thread/future.hpp>
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#if defined BOOST_THREAD_USES_DATETIME
+#include <boost/date_time/posix_time/conversion.hpp>
+#include <boost/thread/thread_time.hpp>
+#endif
+#include <boost/thread/csbl/memory/unique_ptr.hpp>
+#include <memory>
+#include <algorithm>
+#ifndef UNDER_CE
+#include <process.h>
+#endif
+#include <stdio.h>
+#include <windows.h>
+#include <boost/predef/platform.h>
+
+#if BOOST_PLAT_WINDOWS_RUNTIME
+#include <mutex>
+#include <atomic>
+#include <Activation.h>
+#include <wrl\client.h>
+#include <wrl\event.h>
+#include <wrl\wrappers\corewrappers.h>
+#include <wrl\ftm.h>
+#include <windows.system.threading.h>
+#pragma comment(lib, "runtimeobject.lib")
+#endif
+
+namespace boost
+{
+ namespace detail
+ {
+ thread_data_base::~thread_data_base()
+ {
+ for (notify_list_t::iterator i = notify.begin(), e = notify.end();
+ i != e; ++i)
+ {
+ i->second->unlock();
+ i->first->notify_all();
+ }
+ for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end();
+ i != e; ++i)
+ {
+ (*i)->notify_deferred();
+ }
+ }
+ }
+
+ namespace
+ {
+#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
+ boost::once_flag current_thread_tls_init_flag;
+#else
+ boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
+#endif
+#if defined(UNDER_CE)
+ // Windows CE does not define the TLS_OUT_OF_INDEXES constant.
+#define TLS_OUT_OF_INDEXES 0xFFFFFFFF
+#endif
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
+#else
+ __declspec(thread) boost::detail::thread_data_base* current_thread_data_base;
+#endif
+
+ void create_current_thread_tls_key()
+ {
+ tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ current_thread_tls_key=TlsAlloc();
+ BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
+#endif
+ }
+
+ void cleanup_tls_key()
+ {
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
+ {
+ TlsFree(current_thread_tls_key);
+ current_thread_tls_key=TLS_OUT_OF_INDEXES;
+ }
+#endif
+ }
+
+ void set_current_thread_data(detail::thread_data_base* new_data)
+ {
+ boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ current_thread_data_base = new_data;
+#else
+ if (current_thread_tls_key != TLS_OUT_OF_INDEXES)
+ {
+ BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data));
+ }
+ else
+ {
+ BOOST_VERIFY(false);
+ //boost::throw_exception(thread_resource_error());
+ }
+#endif
+ }
+ }
+
+ namespace detail
+ {
+ thread_data_base* get_current_thread_data()
+ {
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ return current_thread_data_base;
+#else
+ if (current_thread_tls_key == TLS_OUT_OF_INDEXES)
+ {
+ return 0;
+ }
+ return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
+#endif
+ }
+ }
+
+ namespace
+ {
+#ifndef BOOST_HAS_THREADEX
+// Windows CE doesn't define _beginthreadex
+
+ struct ThreadProxyData
+ {
+ typedef unsigned (__stdcall* func)(void*);
+ func start_address_;
+ void* arglist_;
+ ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
+ };
+
+ DWORD WINAPI ThreadProxy(LPVOID args)
+ {
+ boost::csbl::unique_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
+ DWORD ret=data->start_address_(data->arglist_);
+ return ret;
+ }
+
+ inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
+ void* arglist, unsigned initflag, unsigned* thrdaddr)
+ {
+ DWORD threadID;
+ ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
+ HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
+ data,initflag,&threadID);
+ if (hthread==0) {
+ delete data;
+ return 0;
+ }
+ *thrdaddr=threadID;
+ return reinterpret_cast<uintptr_t const>(hthread);
+ }
+
+#endif
+
+ }
+
+ namespace detail
+ {
+ struct thread_exit_callback_node
+ {
+ boost::detail::thread_exit_function_base* func;
+ thread_exit_callback_node* next;
+
+ thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
+ thread_exit_callback_node* next_):
+ func(func_),next(next_)
+ {}
+ };
+
+ }
+
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ namespace detail
+ {
+ std::atomic_uint threadCount;
+
+ bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId)
+ {
+ Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> threadPoolFactory;
+ HRESULT hr = ::Windows::Foundation::GetActivationFactory(
+ Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(),
+ &threadPoolFactory);
+ if (hr != S_OK)
+ {
+ return false;
+ }
+
+ // Create event for tracking work item completion.
+ *thrdId = ++threadCount;
+ handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
+ if (!completionHandle)
+ {
+ return false;
+ }
+ m_completionHandle = completionHandle;
+
+ // Create new work item.
+ Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IWorkItemHandler> workItem =
+ Microsoft::WRL::Callback<Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase>>
+ ([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *)
+ {
+ // Add a reference since we need to access the completionHandle after the thread_start_function.
+ // This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
+ // up closing the handle.
+ ::boost::detail::thread_data_base* const thread_info(reinterpret_cast<::boost::detail::thread_data_base*>(parameter));
+ intrusive_ptr_add_ref(thread_info);
+
+ __try
+ {
+ address(parameter);
+ }
+ __finally
+ {
+ SetEvent(completionHandle);
+ intrusive_ptr_release(thread_info);
+ }
+ return S_OK;
+ });
+
+ // Schedule work item on the threadpool.
+ Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncAction;
+ hr = threadPoolFactory->RunWithPriorityAndOptionsAsync(
+ workItem.Get(),
+ ABI::Windows::System::Threading::WorkItemPriority_Normal,
+ ABI::Windows::System::Threading::WorkItemOptions_TimeSliced,
+ &asyncAction);
+ return hr == S_OK;
+ }
+ }
+#endif
+
+ namespace
+ {
+ void run_thread_exit_callbacks()
+ {
+ detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false);
+ if(current_thread_data)
+ {
+ while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks)
+ {
+ while(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)
+ {
+ (*current_node->func)();
+ boost::detail::heap_delete(current_node->func);
+ }
+ boost::detail::heap_delete(current_node);
+ }
+ while (!current_thread_data->tss_data.empty())
+ {
+ std::map<void const*,detail::tss_data_node>::iterator current
+ = current_thread_data->tss_data.begin();
+ if(current->second.func && (current->second.value!=0))
+ {
+ (*current->second.func)(current->second.value);
+ }
+ current_thread_data->tss_data.erase(current);
+ }
+ }
+ set_current_thread_data(0);
+ }
+ }
+
+ unsigned __stdcall thread_start_function(void* param)
+ {
+ detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
+ set_current_thread_data(thread_info);
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ BOOST_TRY
+ {
+#endif
+ thread_info->run();
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ }
+ BOOST_CATCH(thread_interrupted const&)
+ {
+ }
+ // Unhandled exceptions still cause the application to terminate
+ BOOST_CATCH_END
+#endif
+ run_thread_exit_callbacks();
+ return 0;
+ }
+ }
+
+ thread::thread() BOOST_NOEXCEPT
+ {}
+
+ bool thread::start_thread_noexcept()
+ {
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ intrusive_ptr_add_ref(thread_info.get());
+ if (!thread_info->thread_handle.start(&thread_start_function, thread_info.get(), &thread_info->id))
+ {
+ intrusive_ptr_release(thread_info.get());
+ return false;
+ }
+ return true;
+#else
+ uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
+ if(!new_thread)
+ {
+ return false;
+ }
+ intrusive_ptr_add_ref(thread_info.get());
+ thread_info->thread_handle=(detail::win32::handle)(new_thread);
+ ResumeThread(thread_info->thread_handle);
+ return true;
+#endif
+ }
+
+ bool thread::start_thread_noexcept(const attributes& attr)
+ {
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ // Stack size isn't supported with Windows Runtime.
+ attr;
+ return start_thread_noexcept();
+#else
+ uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),
+ CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_info->id);
+ if(!new_thread)
+ {
+ return false;
+ }
+ intrusive_ptr_add_ref(thread_info.get());
+ thread_info->thread_handle=(detail::win32::handle)(new_thread);
+ ResumeThread(thread_info->thread_handle);
+ return true;
+#endif
+ }
+
+ thread::thread(detail::thread_data_ptr data):
+ thread_info(data)
+ {}
+
+ namespace
+ {
+ struct externally_launched_thread:
+ detail::thread_data_base
+ {
+ externally_launched_thread()
+ {
+ ++count;
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ interruption_enabled=false;
+#endif
+ }
+ ~externally_launched_thread() {
+ BOOST_ASSERT(notify.empty());
+ notify.clear();
+ BOOST_ASSERT(async_states_.empty());
+ async_states_.clear();
+ }
+
+ void run()
+ {}
+ void notify_all_at_thread_exit(condition_variable*, mutex*)
+ {}
+
+ private:
+ externally_launched_thread(externally_launched_thread&);
+ void operator=(externally_launched_thread&);
+ };
+
+ void make_external_thread_data()
+ {
+ externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
+ BOOST_TRY
+ {
+ set_current_thread_data(me);
+ }
+ BOOST_CATCH(...)
+ {
+ detail::heap_delete(me);
+ BOOST_RETHROW
+ }
+ BOOST_CATCH_END
+ }
+
+ detail::thread_data_base* get_or_make_current_thread_data()
+ {
+ detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
+ if(!current_thread_data)
+ {
+ make_external_thread_data();
+ current_thread_data=detail::get_current_thread_data();
+ }
+ return current_thread_data;
+ }
+ }
+
+ thread::id thread::get_id() const BOOST_NOEXCEPT
+ {
+#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ if(!local_thread_info)
+ {
+ return 0;
+ }
+ return local_thread_info->id;
+#else
+ return thread::id((get_thread_info)());
+#endif
+ }
+
+ bool thread::joinable() const BOOST_NOEXCEPT
+ {
+ detail::thread_data_ptr local_thread_info = (get_thread_info)();
+ if(!local_thread_info)
+ {
+ return false;
+ }
+ return true;
+ }
+ bool thread::join_noexcept()
+ {
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax());
+ release_handle();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res)
+ {
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ if(!this_thread::interruptible_wait(this->native_handle(), timeout))
+ {
+ res=false;
+ return true;
+ }
+ release_handle();
+ res=true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ void thread::detach()
+ {
+ release_handle();
+ }
+
+ void thread::release_handle()
+ {
+ thread_info=0;
+ }
+
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ void thread::interrupt()
+ {
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ if(local_thread_info)
+ {
+ local_thread_info->interrupt();
+ }
+ }
+
+ bool thread::interruption_requested() const BOOST_NOEXCEPT
+ {
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ return local_thread_info.get() && (winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
+ }
+
+#endif
+
+ unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
+ {
+ detail::win32::system_info info;
+ detail::win32::get_system_info(&info);
+ return info.dwNumberOfProcessors;
+ }
+
+ unsigned thread::physical_concurrency() BOOST_NOEXCEPT
+ {
+ // a bit too strict: Windows XP with SP3 would be sufficient
+#if BOOST_PLAT_WINDOWS_RUNTIME \
+ || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \
+ || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600)
+ return 0;
+#else
+ unsigned cores = 0;
+ DWORD size = 0;
+
+ GetLogicalProcessorInformation(NULL, &size);
+ if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
+ return 0;
+
+ std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(size);
+ if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE)
+ return 0;
+
+ const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
+
+ for (size_t i = 0; i < Elements; ++i) {
+ if (buffer[i].Relationship == RelationProcessorCore)
+ ++cores;
+ }
+ return cores;
+#endif
+ }
+
+ thread::native_handle_type thread::native_handle()
+ {
+ detail::thread_data_ptr local_thread_info=(get_thread_info)();
+ if(!local_thread_info)
+ {
+ return detail::win32::invalid_handle_value;
+ }
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ // There is no 'real' Win32 handle so we return a handle that at least can be waited on.
+ return local_thread_info->thread_handle.waitable_handle();
+#else
+ return (detail::win32::handle)local_thread_info->thread_handle;
+#endif
+ }
+
+ detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
+ {
+ return thread_info;
+ }
+
+ namespace this_thread
+ {
+#ifndef UNDER_CE
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ namespace detail_
+ {
+ typedef struct _REASON_CONTEXT {
+ ULONG Version;
+ DWORD Flags;
+ union {
+ LPWSTR SimpleReasonString;
+ struct {
+ HMODULE LocalizedReasonModule;
+ ULONG LocalizedReasonId;
+ ULONG ReasonStringCount;
+ LPWSTR *ReasonStrings;
+ } Detailed;
+ } Reason;
+ } REASON_CONTEXT, *PREASON_CONTEXT;
+ typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG);
+ static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay)
+ {
+ return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE);
+ }
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail
+#endif
+ static inline setwaitabletimerex_t SetWaitableTimerEx()
+ {
+ static setwaitabletimerex_t setwaitabletimerex_impl;
+ if(setwaitabletimerex_impl)
+ return setwaitabletimerex_impl;
+ void (*addr)()=(void (*)()) GetProcAddress(
+#if !defined(BOOST_NO_ANSI_APIS)
+ GetModuleHandleA("KERNEL32.DLL"),
+#else
+ GetModuleHandleW(L"KERNEL32.DLL"),
+#endif
+ "SetWaitableTimerEx");
+ if(addr)
+ setwaitabletimerex_impl=(setwaitabletimerex_t) addr;
+ else
+ setwaitabletimerex_impl=&SetWaitableTimerEx_emulation;
+ return setwaitabletimerex_impl;
+ }
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ }
+#endif
+#endif
+ bool interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
+ {
+ detail::win32::handle handles[4]={0};
+ unsigned handle_count=0;
+ unsigned wait_handle_index=~0U;
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ unsigned interruption_index=~0U;
+#endif
+ unsigned timeout_index=~0U;
+ if(handle_to_wait_for!=detail::win32::invalid_handle_value)
+ {
+ wait_handle_index=handle_count;
+ handles[handle_count++]=handle_to_wait_for;
+ }
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled)
+ {
+ interruption_index=handle_count;
+ handles[handle_count++]=detail::get_current_thread_data()->interruption_handle;
+ }
+#endif
+ detail::win32::handle_manager timer_handle;
+
+#ifndef UNDER_CE
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ // Preferentially use coalescing timers for better power consumption and timer accuracy
+ if(timeout != detail::internal_platform_timepoint::getMax())
+ {
+ boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ timer_handle=CreateWaitableTimer(NULL,false,NULL);
+ if(timer_handle!=0)
+ {
+ ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
+ if(time_left_msec/20>tolerable) // 5%
+ tolerable=static_cast<ULONG>(time_left_msec/20);
+ LARGE_INTEGER due_time={{0,0}};
+ if(time_left_msec>0)
+ {
+ due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
+ }
+ bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
+ if(set_time_succeeded)
+ {
+ timeout_index=handle_count;
+ handles[handle_count++]=timer_handle;
+ }
+ }
+ }
+#endif
+#endif
+
+ bool const using_timer=timeout_index!=~0u;
+ boost::intmax_t time_left_msec(INFINITE);
+ if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
+ {
+ time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ if(time_left_msec < 0)
+ {
+ time_left_msec = 0;
+ }
+ }
+
+ do
+ {
+ if(handle_count)
+ {
+ unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
+ if(notified_index<handle_count)
+ {
+ if(notified_index==wait_handle_index)
+ {
+ return true;
+ }
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ else if(notified_index==interruption_index)
+ {
+ winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
+ throw thread_interrupted();
+ }
+#endif
+ else if(notified_index==timeout_index)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
+ }
+
+ if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
+ {
+ time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ }
+ }
+ while(time_left_msec == INFINITE || time_left_msec > 0);
+ return false;
+ }
+
+ namespace no_interruption_point
+ {
+ bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout)
+ {
+ detail::win32::handle handles[3]={0};
+ unsigned handle_count=0;
+ unsigned wait_handle_index=~0U;
+ unsigned timeout_index=~0U;
+ if(handle_to_wait_for!=detail::win32::invalid_handle_value)
+ {
+ wait_handle_index=handle_count;
+ handles[handle_count++]=handle_to_wait_for;
+ }
+ detail::win32::handle_manager timer_handle;
+
+#ifndef UNDER_CE
+#if !BOOST_PLAT_WINDOWS_RUNTIME
+ // Preferentially use coalescing timers for better power consumption and timer accuracy
+ if(timeout != detail::internal_platform_timepoint::getMax())
+ {
+ boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ timer_handle=CreateWaitableTimer(NULL,false,NULL);
+ if(timer_handle!=0)
+ {
+ ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
+ if(time_left_msec/20>tolerable) // 5%
+ tolerable=static_cast<ULONG>(time_left_msec/20);
+ LARGE_INTEGER due_time={{0,0}};
+ if(time_left_msec>0)
+ {
+ due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time
+ }
+ bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0;
+ if(set_time_succeeded)
+ {
+ timeout_index=handle_count;
+ handles[handle_count++]=timer_handle;
+ }
+ }
+ }
+#endif
+#endif
+
+ bool const using_timer=timeout_index!=~0u;
+ boost::intmax_t time_left_msec(INFINITE);
+ if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
+ {
+ time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ if(time_left_msec < 0)
+ {
+ time_left_msec = 0;
+ }
+ }
+
+ do
+ {
+ if(handle_count)
+ {
+ unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast<DWORD>(time_left_msec), 0);
+ if(notified_index<handle_count)
+ {
+ if(notified_index==wait_handle_index)
+ {
+ return true;
+ }
+ else if(notified_index==timeout_index)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ detail::win32::sleep(static_cast<unsigned long>(time_left_msec));
+ }
+
+ if(!using_timer && timeout != detail::internal_platform_timepoint::getMax())
+ {
+ time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs();
+ }
+ }
+ while(time_left_msec == INFINITE || time_left_msec > 0);
+ return false;
+ }
+ }
+
+ thread::id get_id() BOOST_NOEXCEPT
+ {
+#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
+#if BOOST_PLAT_WINDOWS_RUNTIME
+ detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
+ if (current_thread_data)
+ {
+ return current_thread_data->id;
+ }
+#endif
+ return winapi::GetCurrentThreadId();
+#else
+ return thread::id(get_or_make_current_thread_data());
+#endif
+ }
+
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ void interruption_point()
+ {
+ if(interruption_enabled() && interruption_requested())
+ {
+ winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle);
+ throw thread_interrupted();
+ }
+ }
+
+ bool interruption_enabled() BOOST_NOEXCEPT
+ {
+ return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled;
+ }
+
+ bool interruption_requested() BOOST_NOEXCEPT
+ {
+ return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
+ }
+#endif
+
+ void yield() BOOST_NOEXCEPT
+ {
+ detail::win32::sleep(0);
+ }
+
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ disable_interruption::disable_interruption() BOOST_NOEXCEPT:
+ interruption_was_enabled(interruption_enabled())
+ {
+ if(interruption_was_enabled)
+ {
+ detail::get_current_thread_data()->interruption_enabled=false;
+ }
+ }
+
+ disable_interruption::~disable_interruption() BOOST_NOEXCEPT
+ {
+ if(detail::get_current_thread_data())
+ {
+ detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled;
+ }
+ }
+
+ restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
+ {
+ if(d.interruption_was_enabled)
+ {
+ detail::get_current_thread_data()->interruption_enabled=true;
+ }
+ }
+
+ restore_interruption::~restore_interruption() BOOST_NOEXCEPT
+ {
+ if(detail::get_current_thread_data())
+ {
+ detail::get_current_thread_data()->interruption_enabled=false;
+ }
+ }
+#endif
+ }
+
+ namespace detail
+ {
+ void add_thread_exit_function(thread_exit_function_base* func)
+ {
+ detail::thread_data_base* const current_thread_data(get_or_make_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;
+ }
+
+ tss_data_node* find_tss_data(void const* key)
+ {
+ detail::thread_data_base* const current_thread_data(get_current_thread_data());
+ if(current_thread_data)
+ {
+ std::map<void const*,tss_data_node>::iterator current_node=
+ current_thread_data->tss_data.find(key);
+ if(current_node!=current_thread_data->tss_data.end())
+ {
+ return &current_node->second;
+ }
+ }
+ return NULL;
+ }
+
+ void* get_tss_data(void const* key)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ return current_node->value;
+ }
+ return NULL;
+ }
+
+ void add_new_tss_node(void const* key,
+ boost::shared_ptr<tss_cleanup_function> func,
+ void* tss_data)
+ {
+ detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
+ current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
+ }
+
+ void erase_tss_node(void const* key)
+ {
+ detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
+ current_thread_data->tss_data.erase(key);
+ }
+
+ void set_tss_data(void const* key,
+ boost::shared_ptr<tss_cleanup_function> func,
+ void* tss_data,bool cleanup_existing)
+ {
+ if(tss_data_node* const current_node=find_tss_data(key))
+ {
+ if(cleanup_existing && current_node->func && (current_node->value!=0))
+ {
+ (*current_node->func)(current_node->value);
+ }
+ if(func || (tss_data!=0))
+ {
+ current_node->func=func;
+ current_node->value=tss_data;
+ }
+ else
+ {
+ erase_tss_node(key);
+ }
+ }
+ else if(func || (tss_data!=0))
+ {
+ add_new_tss_node(key,func,tss_data);
+ }
+ }
+ }
+
+ BOOST_THREAD_DECL void __cdecl on_process_enter()
+ {}
+
+ BOOST_THREAD_DECL void __cdecl on_thread_enter()
+ {}
+
+ BOOST_THREAD_DECL void __cdecl on_process_exit()
+ {
+ boost::cleanup_tls_key();
+ }
+
+ BOOST_THREAD_DECL void __cdecl on_thread_exit()
+ {
+ boost::run_thread_exit_callbacks();
+ }
+
+ BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk)
+ {
+ detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
+ if(current_thread_data)
+ {
+ current_thread_data->notify_all_at_thread_exit(&cond, lk.release());
+ }
+ }
+}
+
diff --git a/contrib/restricted/boost/libs/thread/src/win32/thread_primitives.cpp b/contrib/restricted/boost/libs/thread/src/win32/thread_primitives.cpp
new file mode 100644
index 0000000000..f51f621508
--- /dev/null
+++ b/contrib/restricted/boost/libs/thread/src/win32/thread_primitives.cpp
@@ -0,0 +1,140 @@
+// thread_primitives.cpp
+//
+// (C) Copyright 2018 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)
+
+#include <boost/winapi/config.hpp>
+#include <boost/winapi/dll.hpp>
+#include <boost/winapi/time.hpp>
+#include <boost/winapi/event.hpp>
+#include <boost/winapi/handles.hpp>
+#include <boost/winapi/thread_pool.hpp>
+#include <cstdlib>
+#include <boost/config.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/thread/win32/interlocked_read.hpp>
+#include <boost/thread/win32/thread_primitives.hpp>
+
+namespace boost {
+namespace detail {
+namespace win32 {
+
+#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+// Directly use API from Vista and later
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64;
+
+#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+namespace {
+
+enum init_state
+{
+ uninitialized = 0,
+ in_progress,
+ initialized
+};
+
+struct get_tick_count64_state
+{
+ boost::atomic< uint64_t > ticks;
+ boost::atomic< init_state > init;
+ boost::winapi::HANDLE_ wait_event;
+ boost::winapi::HANDLE_ wait_handle;
+};
+
+// Zero-initialized initially
+BOOST_ALIGNMENT(64) static get_tick_count64_state g_state;
+
+//! Artifical implementation of GetTickCount64
+ticks_type WINAPI get_tick_count64()
+{
+ uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire);
+
+ uint32_t new_ticks = boost::winapi::GetTickCount();
+
+ uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff));
+ uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks);
+
+ g_state.ticks.store(new_state, boost::memory_order_release);
+
+ return new_state;
+}
+
+//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated
+void NTAPI refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_)
+{
+ get_tick_count64();
+}
+
+//! Cleanup function to stop get_tick_count64 refreshes
+void cleanup_get_tick_count64()
+{
+ if (g_state.wait_handle)
+ {
+ boost::winapi::UnregisterWait(g_state.wait_handle);
+ g_state.wait_handle = NULL;
+ }
+
+ if (g_state.wait_event)
+ {
+ boost::winapi::CloseHandle(g_state.wait_event);
+ g_state.wait_event = NULL;
+ }
+}
+
+ticks_type WINAPI get_tick_count_init()
+{
+ boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32)
+ {
+ boost::detail::win32::detail::gettickcount64_t p =
+ (boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64");
+ if (p)
+ {
+ // Use native API
+ boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p);
+ return p();
+ }
+ }
+
+ // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted.
+ init_state old_init = uninitialized;
+ if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed))
+ {
+ if (!g_state.wait_event)
+ g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false);
+ if (g_state.wait_event)
+ {
+ boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_);
+ if (res)
+ {
+ std::atexit(&cleanup_get_tick_count64);
+
+ boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64);
+ g_state.init.store(initialized, boost::memory_order_release);
+ goto finish;
+ }
+ }
+
+ g_state.init.store(uninitialized, boost::memory_order_release);
+ }
+
+finish:
+ return get_tick_count64();
+}
+
+} // namespace
+
+BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init;
+
+#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
+
+} // namespace win32
+} // namespace detail
+} // namespace boost
diff --git a/contrib/restricted/boost/libs/thread/src/win32/tss_dll.cpp b/contrib/restricted/boost/libs/thread/src/win32/tss_dll.cpp
new file mode 100644
index 0000000000..75ea93a5aa
--- /dev/null
+++ b/contrib/restricted/boost/libs/thread/src/win32/tss_dll.cpp
@@ -0,0 +1,85 @@
+// (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/winapi/config.hpp>
+#include <boost/thread/detail/config.hpp>
+
+
+#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
+
+ #include <boost/thread/detail/tss_hooks.hpp>
+
+ #include <windows.h>
+
+ #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
+{
+ 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.
+ */
+ }
+}
+
+#else //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
+
+#ifdef _MSC_VER
+// Prevent LNK4221 warning with link=static
+namespace boost { namespace link_static_warning_inhibit {
+ extern __declspec(dllexport) void foo() { }
+} }
+#endif
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
diff --git a/contrib/restricted/boost/libs/thread/src/win32/tss_pe.cpp b/contrib/restricted/boost/libs/thread/src/win32/tss_pe.cpp
new file mode 100644
index 0000000000..e4a0a3aaa3
--- /dev/null
+++ b/contrib/restricted/boost/libs/thread/src/win32/tss_pe.cpp
@@ -0,0 +1,337 @@
+// $Id$
+// (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/winapi/config.hpp>
+#include <boost/thread/detail/config.hpp>
+
+#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
+
+#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
+
+#include <boost/thread/detail/tss_hooks.hpp>
+
+#include <windows.h>
+
+#include <cstdlib>
+
+namespace boost
+{
+ void tss_cleanup_implemented() {}
+}
+
+namespace {
+ void NTAPI on_tls_callback(void* , DWORD dwReason, PVOID )
+ {
+ switch (dwReason)
+ {
+ case DLL_THREAD_DETACH:
+ {
+ boost::on_thread_exit();
+ break;
+ }
+ }
+ }
+}
+
+#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32__) || (__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 <boost/thread/detail/tss_hooks.hpp>
+
+ #include <stdlib.h>
+
+ #include <windows.h>
+
+
+// _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)(HINSTANCE, DWORD, LPVOID);
+extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HINSTANCE, 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) || ((_MSC_VER > 1900) && (_MSC_VER < 1910)) // 1300 == VC++ 7.0, 1900 == VC++ 14.0, 1910 == VC++ 2017
+ typedef void ( __cdecl *_PVFV_ )();
+ typedef void ( __cdecl *_PIFV_ )();
+ #define INIRETSUCCESS_V
+ #define INIRETSUCCESS_I
+ #define PVAPI_V void __cdecl
+ #define PVAPI_I void __cdecl
+ #elif (_MSC_VER >= 1910)
+ typedef void ( __cdecl *_PVFV_ )();
+ typedef int ( __cdecl *_PIFV_ )();
+ #define INIRETSUCCESS_V
+ #define INIRETSUCCESS_I 0
+ #define PVAPI_V void __cdecl
+ #define PVAPI_I int __cdecl
+ #else
+ typedef int ( __cdecl *_PVFV_ )();
+ typedef int ( __cdecl *_PIFV_ )();
+ #define INIRETSUCCESS_V 0
+ #define INIRETSUCCESS_I 0
+ #define PVAPI_V int __cdecl
+ #define PVAPI_I 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_I on_tls_prepare();
+ static PVAPI_V on_process_init();
+ static PVAPI_V 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"))_PIFV_ 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 _PIFV_ 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_I 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_I;
+ }
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+
+ PVAPI_V 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_V;
+ }
+
+ PVAPI_V on_process_term()
+ {
+ boost::on_process_exit();
+ return INIRETSUCCESS_V;
+ }
+
+ 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(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+#else
+ BOOL WINAPI dll_callback(HINSTANCE, 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)(HINSTANCE, DWORD, LPVOID)=&dll_callback;
+}
+namespace boost
+{
+ 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.
+ */
+ }
+}
+
+#endif //defined(_MSC_VER) && !defined(UNDER_CE)
+
+#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)