summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2009-06-01 08:48:42 (GMT)
committerRemko Tronçon <git@el-tramo.be>2009-06-01 09:24:28 (GMT)
commit2812bddd81f8a1b804c7460f4e14cd0aa393d129 (patch)
treed46294f35150c4f0f43deaf2d31fceaf945ae715 /3rdParty/Boost/libs/thread/src/win32/thread.cpp
downloadswift-contrib-2812bddd81f8a1b804c7460f4e14cd0aa393d129.zip
swift-contrib-2812bddd81f8a1b804c7460f4e14cd0aa393d129.tar.bz2
Import.
Diffstat (limited to '3rdParty/Boost/libs/thread/src/win32/thread.cpp')
-rw-r--r--3rdParty/Boost/libs/thread/src/win32/thread.cpp597
1 files changed, 597 insertions, 0 deletions
diff --git a/3rdParty/Boost/libs/thread/src/win32/thread.cpp b/3rdParty/Boost/libs/thread/src/win32/thread.cpp
new file mode 100644
index 0000000..a72f053
--- /dev/null
+++ b/3rdParty/Boost/libs/thread/src/win32/thread.cpp
@@ -0,0 +1,597 @@
+// 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()
+ {
+ tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
+ current_thread_tls_key=TlsAlloc();
+ BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
+ }
+
+ void cleanup_tls_key()
+ {
+ if(current_thread_tls_key)
+ {
+ TlsFree(current_thread_tls_key);
+ current_thread_tls_key=0;
+ }
+ }
+
+ detail::thread_data_base* get_current_thread_data()
+ {
+ if(!current_thread_tls_key)
+ {
+ return 0;
+ }
+ 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
+
+ }
+
+ 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_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&)
+ {
+ }
+// Removed as it stops the debugger identifying the cause of the exception
+// Unhandled exceptions still cause the application to terminate
+// 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()
+ {}
+ 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>();
+ 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::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)
+ {
+ 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()
+{
+ boost::cleanup_tls_key();
+}
+
+extern "C" BOOST_THREAD_DECL void on_thread_exit()
+{
+ boost::run_thread_exit_callbacks();
+}
+