mirror of
https://github.com/boostorg/thread.git
synced 2026-02-08 23:22:13 +00:00
https://svn.boost.org/svn/boost/trunk ........ r41679 | anthonyw | 2007-12-03 23:57:23 -0800 (Mon, 03 Dec 2007) | 1 line fixed typo in condition_variable_any::timed_wait ........ r41681 | anthonyw | 2007-12-04 01:15:37 -0800 (Tue, 04 Dec 2007) | 1 line changed boost::move to boost::detail::thread_move to fix issue #1492 ........ r41682 | anthonyw | 2007-12-04 02:04:30 -0800 (Tue, 04 Dec 2007) | 1 line split shared mutex tests in two to take less time ........ r41683 | anthonyw | 2007-12-04 03:44:25 -0800 (Tue, 04 Dec 2007) | 1 line don't dllexport/dllimport inline functions ........ r41684 | anthonyw | 2007-12-04 04:08:38 -0800 (Tue, 04 Dec 2007) | 1 line add explicit casts to remove warnings ........ r41686 | anthonyw | 2007-12-04 05:02:58 -0800 (Tue, 04 Dec 2007) | 1 line Added test for thread move constructor; implemented move on pthreads ........ r41687 | anthonyw | 2007-12-04 06:07:01 -0800 (Tue, 04 Dec 2007) | 1 line changed order of declaration to eliminate warnings ........ r41688 | nesotto | 2007-12-04 06:41:44 -0800 (Tue, 04 Dec 2007) | 1 line ticket 1488 ........ r41696 | fmhess | 2007-12-04 11:42:08 -0800 (Tue, 04 Dec 2007) | 2 lines Make sure output filenames don't include any illegal characters. ........ r41697 | fmhess | 2007-12-04 11:45:10 -0800 (Tue, 04 Dec 2007) | 4 lines Fixed printing of object name for nested classes (merge of revision 41421 from sandbox/boost_docs). ........ r41698 | fmhess | 2007-12-04 11:55:50 -0800 (Tue, 04 Dec 2007) | 17 lines Made generated ids for functions and overloaded functions human-readable which also results in (mostly) human-readable names for their .html output files. Made generate.id template properly use its node parameter (merge of parts of revision 41461 from sandbox/boost_docs). Made class name in synopsis a link to class reference page, which is useful for nested classes (merge of revision 41435 from sandbox/boost_docs). Removed spurious new line in synopisis between a nested class and the comment describing its purpose (merge of revision 41434 from sandbox/boost_docs). Added a warning if an "inherit" element has no "type" child element (partial merge of revision 41463 from sandbox/boost_docs). ........ r41701 | chris_kohlhoff | 2007-12-04 13:28:42 -0800 (Tue, 04 Dec 2007) | 2 lines Prevent deprecated function warnings for MSVC >= 8. ........ r41703 | nasonov | 2007-12-04 13:49:51 -0800 (Tue, 04 Dec 2007) | 1 line Link to html version of [Tuning] and BOOST_LEXICAL_CAST_ASSUME_C_LOCALE synopsis ........ r41704 | igaztanaga | 2007-12-04 14:05:28 -0800 (Tue, 04 Dec 2007) | 1 line Added Leopard workaround. _POSIX_THREAD_PROCESS_SHARED is defined but does not seem to work. For the moment, Mac OS will use emulation code ........ r41705 | djenkins | 2007-12-04 14:19:58 -0800 (Tue, 04 Dec 2007) | 1 line Fix msvc-9.0 code analysis problem ........ r41707 | noel_belcourt | 2007-12-04 15:18:38 -0800 (Tue, 04 Dec 2007) | 6 lines Fixes to get pgi shared libraries working, executables that don't core, and limiting the number of error messages emitted by the compiler so as to reduce the size of the log file. ........ r41727 | grafik | 2007-12-04 16:32:04 -0800 (Tue, 04 Dec 2007) | 1 line Switch FTP site for results. ........ r41734 | noel_belcourt | 2007-12-04 19:11:25 -0800 (Tue, 04 Dec 2007) | 5 lines Pgi compilers can't accept shared library with Boost version suffix appended to it. Add logic to tag rule in Jamroot to suppress appending version suffix for pgi toolset. ........ r41735 | noel_belcourt | 2007-12-04 19:20:30 -0800 (Tue, 04 Dec 2007) | 3 lines Patch pgi shared library use. ........ r41736 | grafik | 2007-12-04 20:33:36 -0800 (Tue, 04 Dec 2007) | 1 line Fix parsing of macosx version numbers from detected SDKs. ........ r41738 | anthonyw | 2007-12-05 00:27:44 -0800 (Wed, 05 Dec 2007) | 1 line added missing include of detail/config.hpp ........ r41739 | t_schwinger | 2007-12-05 02:24:21 -0800 (Wed, 05 Dec 2007) | 3 lines clarifies #error message ........ r41740 | t_schwinger | 2007-12-05 02:26:16 -0800 (Wed, 05 Dec 2007) | 2 lines updates function_types failures ........ r41741 | anthonyw | 2007-12-05 02:58:45 -0800 (Wed, 05 Dec 2007) | 1 line improved timeout checks ........ r41742 | t_schwinger | 2007-12-05 05:20:13 -0800 (Wed, 05 Dec 2007) | 3 lines attempts to fix strange problems with Pathscale compilers ........ r41762 | chris_kohlhoff | 2007-12-05 13:46:19 -0800 (Wed, 05 Dec 2007) | 2 lines Don't use deprecated function workaround when compiling for Windows CE. ........ r41770 | ramey | 2007-12-05 18:33:59 -0800 (Wed, 05 Dec 2007) | 2 lines change to fix failures with gcc 4.1+ modification to string input primitives ........ r41775 | djenkins | 2007-12-05 22:23:55 -0800 (Wed, 05 Dec 2007) | 1 line Avoid bug in Microsoft Code Analysis ........ [SVN r41776]
630 lines
20 KiB
C++
630 lines
20 KiB
C++
// 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
|
|
|
|
#define _WIN32_WINNT 0x400
|
|
#define WINVER 0x400
|
|
|
|
#include <boost/thread/thread.hpp>
|
|
#include <algorithm>
|
|
#include <windows.h>
|
|
#ifndef UNDER_CE
|
|
#include <process.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <boost/thread/once.hpp>
|
|
#include <boost/thread/tss.hpp>
|
|
#include <boost/assert.hpp>
|
|
#include <boost/thread/detail/tss_hooks.hpp>
|
|
#include <boost/date_time/posix_time/conversion.hpp>
|
|
|
|
namespace boost
|
|
{
|
|
namespace
|
|
{
|
|
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
|
DWORD current_thread_tls_key=0;
|
|
|
|
void create_current_thread_tls_key()
|
|
{
|
|
current_thread_tls_key=TlsAlloc();
|
|
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
|
}
|
|
|
|
detail::thread_data_base* get_current_thread_data()
|
|
{
|
|
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
|
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
|
}
|
|
|
|
void set_current_thread_data(detail::thread_data_base* new_data)
|
|
{
|
|
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
|
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
|
}
|
|
|
|
#ifdef BOOST_NO_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)
|
|
{
|
|
ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
|
|
DWORD ret=data->start_address_(data->arglist_);
|
|
delete data;
|
|
return ret;
|
|
}
|
|
|
|
typedef void* uintptr_t;
|
|
|
|
inline uintptr_t const _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
|
|
void* arglist, unsigned initflag, unsigned* thrdaddr)
|
|
{
|
|
DWORD threadID;
|
|
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
|
|
new ThreadProxyData(start_address,arglist),initflag,&threadID);
|
|
if (hthread!=0)
|
|
*thrdaddr=threadID;
|
|
return reinterpret_cast<uintptr_t const>(hthread);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void thread::yield()
|
|
{
|
|
this_thread::yield();
|
|
}
|
|
|
|
void thread::sleep(const system_time& target)
|
|
{
|
|
system_time const now(get_system_time());
|
|
|
|
if(target<=now)
|
|
{
|
|
this_thread::yield();
|
|
}
|
|
else
|
|
{
|
|
this_thread::sleep(target-now);
|
|
}
|
|
}
|
|
|
|
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_)
|
|
{}
|
|
};
|
|
|
|
struct tss_data_node
|
|
{
|
|
void const* key;
|
|
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
|
void* value;
|
|
tss_data_node* next;
|
|
|
|
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
|
tss_data_node* next_):
|
|
key(key_),func(func_),value(value_),next(next_)
|
|
{}
|
|
};
|
|
|
|
}
|
|
|
|
namespace
|
|
{
|
|
void run_thread_exit_callbacks()
|
|
{
|
|
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
|
|
if(current_thread_data)
|
|
{
|
|
while(current_thread_data->tss_data || 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)
|
|
{
|
|
detail::tss_data_node* const current_node=current_thread_data->tss_data;
|
|
current_thread_data->tss_data=current_node->next;
|
|
if(current_node->func)
|
|
{
|
|
(*current_node->func)(current_node->value);
|
|
}
|
|
boost::detail::heap_delete(current_node);
|
|
}
|
|
}
|
|
|
|
}
|
|
set_current_thread_data(0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
unsigned __stdcall thread::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);
|
|
try
|
|
{
|
|
thread_info->run();
|
|
}
|
|
catch(thread_interrupted const&)
|
|
{
|
|
}
|
|
catch(...)
|
|
{
|
|
std::terminate();
|
|
}
|
|
run_thread_exit_callbacks();
|
|
return 0;
|
|
}
|
|
|
|
thread::thread()
|
|
{}
|
|
|
|
void thread::start_thread()
|
|
{
|
|
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
|
if(!new_thread)
|
|
{
|
|
throw thread_resource_error();
|
|
}
|
|
intrusive_ptr_add_ref(thread_info.get());
|
|
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
|
ResumeThread(thread_info->thread_handle);
|
|
}
|
|
|
|
thread::thread(detail::thread_data_ptr data):
|
|
thread_info(data)
|
|
{}
|
|
|
|
namespace
|
|
{
|
|
struct externally_launched_thread:
|
|
detail::thread_data_base
|
|
{
|
|
externally_launched_thread()
|
|
{
|
|
++count;
|
|
interruption_enabled=false;
|
|
}
|
|
|
|
void run()
|
|
{}
|
|
};
|
|
|
|
void make_external_thread_data()
|
|
{
|
|
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
|
|
set_current_thread_data(me);
|
|
}
|
|
|
|
detail::thread_data_base* get_or_make_current_thread_data()
|
|
{
|
|
detail::thread_data_base* current_thread_data(get_current_thread_data());
|
|
if(!current_thread_data)
|
|
{
|
|
make_external_thread_data();
|
|
current_thread_data=get_current_thread_data();
|
|
}
|
|
return current_thread_data;
|
|
}
|
|
|
|
}
|
|
|
|
thread::~thread()
|
|
{
|
|
detach();
|
|
}
|
|
|
|
thread::thread(detail::thread_move_t<thread> x)
|
|
{
|
|
lock_guard<mutex> lock(x->thread_info_mutex);
|
|
thread_info=x->thread_info;
|
|
x->thread_info=0;
|
|
}
|
|
|
|
thread& thread::operator=(detail::thread_move_t<thread> x)
|
|
{
|
|
thread new_thread(x);
|
|
swap(new_thread);
|
|
return *this;
|
|
}
|
|
|
|
thread::operator detail::thread_move_t<thread>()
|
|
{
|
|
return move();
|
|
}
|
|
|
|
detail::thread_move_t<thread> thread::move()
|
|
{
|
|
detail::thread_move_t<thread> x(*this);
|
|
return x;
|
|
}
|
|
|
|
void thread::swap(thread& x)
|
|
{
|
|
thread_info.swap(x.thread_info);
|
|
}
|
|
|
|
thread::id thread::get_id() const
|
|
{
|
|
return thread::id(get_thread_info());
|
|
}
|
|
|
|
bool thread::joinable() const
|
|
{
|
|
return get_thread_info();
|
|
}
|
|
|
|
void thread::join()
|
|
{
|
|
detail::thread_data_ptr local_thread_info=get_thread_info();
|
|
if(local_thread_info)
|
|
{
|
|
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
|
|
release_handle();
|
|
}
|
|
}
|
|
|
|
bool thread::timed_join(boost::system_time const& wait_until)
|
|
{
|
|
detail::thread_data_ptr local_thread_info=get_thread_info();
|
|
if(local_thread_info)
|
|
{
|
|
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
|
|
{
|
|
return false;
|
|
}
|
|
release_handle();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void thread::detach()
|
|
{
|
|
release_handle();
|
|
}
|
|
|
|
void thread::release_handle()
|
|
{
|
|
lock_guard<mutex> l1(thread_info_mutex);
|
|
thread_info=0;
|
|
}
|
|
|
|
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
|
|
{
|
|
detail::thread_data_ptr local_thread_info=get_thread_info();
|
|
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
|
}
|
|
|
|
unsigned thread::hardware_concurrency()
|
|
{
|
|
SYSTEM_INFO info={0};
|
|
GetSystemInfo(&info);
|
|
return info.dwNumberOfProcessors;
|
|
}
|
|
|
|
thread::native_handle_type thread::native_handle()
|
|
{
|
|
detail::thread_data_ptr local_thread_info=get_thread_info();
|
|
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
|
|
}
|
|
|
|
detail::thread_data_ptr thread::get_thread_info() const
|
|
{
|
|
boost::mutex::scoped_lock l(thread_info_mutex);
|
|
return thread_info;
|
|
}
|
|
|
|
namespace this_thread
|
|
{
|
|
namespace
|
|
{
|
|
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
|
|
{
|
|
LARGE_INTEGER due_time={0};
|
|
if(target_time.relative)
|
|
{
|
|
unsigned long const elapsed_milliseconds=GetTickCount()-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};
|
|
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;
|
|
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
|
|
}
|
|
}
|
|
return due_time;
|
|
}
|
|
}
|
|
|
|
|
|
bool 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 interruption_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;
|
|
}
|
|
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
|
|
{
|
|
interruption_index=handle_count;
|
|
handles[handle_count++]=get_current_thread_data()->interruption_handle;
|
|
}
|
|
|
|
detail::win32::handle_manager timer_handle;
|
|
|
|
#ifndef UNDER_CE
|
|
unsigned const min_timer_wait_period=20;
|
|
|
|
if(!target_time.is_sentinel())
|
|
{
|
|
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
|
|
if(time_left.milliseconds > min_timer_wait_period)
|
|
{
|
|
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
|
|
timer_handle=CreateWaitableTimer(NULL,false,NULL);
|
|
if(timer_handle!=0)
|
|
{
|
|
LARGE_INTEGER due_time=get_due_time(target_time);
|
|
|
|
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
|
|
if(set_time_succeeded)
|
|
{
|
|
timeout_index=handle_count;
|
|
handles[handle_count++]=timer_handle;
|
|
}
|
|
}
|
|
}
|
|
else if(!target_time.relative)
|
|
{
|
|
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
|
|
target_time=detail::timeout(time_left.milliseconds);
|
|
}
|
|
}
|
|
#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::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
|
if(notified_index<handle_count)
|
|
{
|
|
if(notified_index==wait_handle_index)
|
|
{
|
|
return true;
|
|
}
|
|
else if(notified_index==interruption_index)
|
|
{
|
|
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
|
throw thread_interrupted();
|
|
}
|
|
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()
|
|
{
|
|
return thread::id(get_or_make_current_thread_data());
|
|
}
|
|
|
|
void interruption_point()
|
|
{
|
|
if(interruption_enabled() && interruption_requested())
|
|
{
|
|
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
|
throw thread_interrupted();
|
|
}
|
|
}
|
|
|
|
bool interruption_enabled()
|
|
{
|
|
return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
|
|
}
|
|
|
|
bool interruption_requested()
|
|
{
|
|
return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
|
|
}
|
|
|
|
void yield()
|
|
{
|
|
detail::win32::Sleep(0);
|
|
}
|
|
|
|
disable_interruption::disable_interruption():
|
|
interruption_was_enabled(interruption_enabled())
|
|
{
|
|
if(interruption_was_enabled)
|
|
{
|
|
get_current_thread_data()->interruption_enabled=false;
|
|
}
|
|
}
|
|
|
|
disable_interruption::~disable_interruption()
|
|
{
|
|
if(get_current_thread_data())
|
|
{
|
|
get_current_thread_data()->interruption_enabled=interruption_was_enabled;
|
|
}
|
|
}
|
|
|
|
restore_interruption::restore_interruption(disable_interruption& d)
|
|
{
|
|
if(d.interruption_was_enabled)
|
|
{
|
|
get_current_thread_data()->interruption_enabled=true;
|
|
}
|
|
}
|
|
|
|
restore_interruption::~restore_interruption()
|
|
{
|
|
if(get_current_thread_data())
|
|
{
|
|
get_current_thread_data()->interruption_enabled=false;
|
|
}
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
|
while(current_node)
|
|
{
|
|
if(current_node->key==key)
|
|
{
|
|
return current_node;
|
|
}
|
|
current_node=current_node->next;
|
|
}
|
|
}
|
|
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 set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
|
{
|
|
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
|
if(tss_data_node* const current_node=find_tss_data(key))
|
|
{
|
|
if(cleanup_existing && current_node->func.get())
|
|
{
|
|
(*current_node->func)(current_node->value);
|
|
}
|
|
current_node->func=func;
|
|
current_node->value=tss_data;
|
|
}
|
|
else
|
|
{
|
|
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
|
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
|
|
current_thread_data->tss_data=new_node;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
extern "C" BOOST_THREAD_DECL void on_process_enter()
|
|
{}
|
|
|
|
extern "C" BOOST_THREAD_DECL void on_thread_enter()
|
|
{}
|
|
|
|
extern "C" BOOST_THREAD_DECL void on_process_exit()
|
|
{}
|
|
|
|
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
|
{
|
|
boost::run_thread_exit_callbacks();
|
|
}
|
|
|