blob: f23cf29a1d67af76ec9a6f2f7a7502365ef43391 [file] [log] [blame]
// 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-2013 Vicente J. Botet Escriba
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
#endif
#ifndef WINVER
#define WINVER 0x400
#endif
//#define BOOST_THREAD_VERSION 3
#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>
#endif
#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)->make_ready();
}
}
}
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)
{
std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
DWORD ret=data->start_address_(data->arglist_);
return ret;
}
//typedef void* uintptr_t;
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&)
{
}
// Removed as it stops the debugger identifying the cause of the exception
// Unhandled exceptions still cause the application to terminate
// BOOST_CATCH(...)
// {
// std::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());
// boost::throw_exception(thread_resource_error());
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;
// boost::throw_exception(thread_resource_error());
}
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(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
if(!new_thread)
{
return false;
// boost::throw_exception(thread_resource_error());
}
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::timeout::sentinel());
release_handle();
return true;
}
else
{
return false;
}
}
#if defined BOOST_THREAD_USES_DATETIME
bool thread::timed_join(boost::system_time const& wait_until)
{
return do_try_join_until(get_milliseconds_until(wait_until));
}
#endif
bool thread::do_try_join_until_noexcept(uintmax_t milli, bool& res)
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(this->native_handle(),milli))
{
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() && (detail::win32::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
{
#if BOOST_PLAT_WINDOWS_RUNTIME || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
return hardware_concurrency();
#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
{
namespace
{
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={{0,0}};
if(target_time.relative)
{
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64_()()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0,0,0,0,0,0,0,0};
target_system_time.wYear=target_time.abs_time.date().year();
target_system_time.wMonth=target_time.abs_time.date().month();
target_system_time.wDay=target_time.abs_time.date().day();
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
posix_time::time_duration::tick_type const ticks_per_second=
target_time.abs_time.time_of_day().ticks_per_second();
if(ticks_per_second>hundred_nanoseconds_in_one_second)
{
posix_time::time_duration::tick_type const
ticks_per_hundred_nanoseconds=
ticks_per_second/hundred_nanoseconds_in_one_second;
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()/
ticks_per_hundred_nanoseconds;
}
else
{
due_time.QuadPart+=
target_time.abs_time.time_of_day().fractional_seconds()*
(hundred_nanoseconds_in_one_second/ticks_per_second);
}
}
}
return due_time;
}
}
#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;
static REASON_CONTEXT default_reason_context={0/*POWER_REQUEST_CONTEXT_VERSION*/, 0x00000001/*POWER_REQUEST_CONTEXT_SIMPLE_STRING*/, (LPWSTR)L"generic"};
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::timeout target_time)
{
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(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
if(time_left.milliseconds/20>tolerable) // 5%
tolerable=time_left.milliseconds/20;
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,&detail_::default_reason_context,tolerable)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
#endif
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 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)
{
detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
#endif
else if(notified_index==timeout_index)
{
return false;
}
}
}
else
{
detail::win32::sleep(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
}
}
while(time_left.more);
return false;
}
namespace no_interruption_point
{
bool non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
{
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(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26
if(time_left.milliseconds/20>tolerable) // 5%
tolerable=time_left.milliseconds/20;
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,&detail_::default_reason_context,tolerable)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
#endif
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 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(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
}
}
while(time_left.more);
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 detail::win32::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())
{
detail::win32::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() && (detail::win32::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());
}
}
//namespace detail {
//
// void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
// {
// detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
// if(current_thread_data)
// {
// current_thread_data->make_ready_at_thread_exit(as);
// }
// }
//}
}