2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-10 11:52:10 +00:00
Files
thread/src/win32/thread.cpp
Eric Niebler 784ec87be1 Merged revisions 41023-41071 via svnmerge from
https://svn.boost.org/svn/boost/trunk

........
  r41026 | johnmaddock | 2007-11-12 02:00:46 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Adjust test logic to cope with compilers that don't underflow constants to zero when they should.
........
  r41027 | burbelgruff | 2007-11-12 03:10:20 -0800 (Mon, 12 Nov 2007) | 1 line
  
  #1425 Support for Visual Studio 2008
........
  r41028 | chris_kohlhoff | 2007-11-12 04:07:39 -0800 (Mon, 12 Nov 2007) | 5 lines
  
  Cannot perform concurrent operations on the /dev/poll descriptor where
  the sockets descriptors involved may already be being waited on. Changed
  the dev_poll_reactor class to keep a vector of pending event changes and
  interrupt the /dev/poll ioctl() wait to apply it.
........
  r41029 | garcia | 2007-11-12 05:00:41 -0800 (Mon, 12 Nov 2007) | 2 lines
  
  added a reviewer for singleton.
........
  r41030 | garcia | 2007-11-12 05:04:16 -0800 (Mon, 12 Nov 2007) | 2 lines
  
  Removed review dates that passed without happening.
........
  r41033 | bemandawes | 2007-11-12 07:22:24 -0800 (Mon, 12 Nov 2007) | 2 lines
  
  Add separate headers for system-specific enums, thus reducing coupling. Suggested by Emil Dotchevski.
........
  r41036 | bgubenko | 2007-11-12 09:03:38 -0800 (Mon, 12 Nov 2007) | 1 line
  
  add -fno-strict-aliasing to compilation with gcc
........
  r41038 | johnmaddock | 2007-11-12 09:21:47 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Disable long double tests if there are no long double math functions.
........
  r41040 | bemandawes | 2007-11-12 09:42:42 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Include system-specific headers, change namespaces accordingly.
........
  r41043 | eric_niebler | 2007-11-12 13:07:54 -0800 (Mon, 12 Nov 2007) | 1 line
  
  minor clean-up
........
  r41046 | bemandawes | 2007-11-12 14:29:48 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Change default to --v2
........
  r41048 | noel_belcourt | 2007-11-12 14:52:12 -0800 (Mon, 12 Nov 2007) | 3 lines
  
  Get the unix timing working correctly.
........
  r41050 | bgubenko | 2007-11-12 16:51:37 -0800 (Mon, 12 Nov 2007) | 1 line
  
  when setting OSPLAT, check __ia64 macro
........
  r41052 | bemandawes | 2007-11-12 18:54:32 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Add tests for, and fix, current_path overloading.
........
  r41054 | vladimir_prus | 2007-11-12 23:54:20 -0800 (Mon, 12 Nov 2007) | 1 line
  
  Add Google Analytics tracking code
........
  r41056 | anthonyw | 2007-11-13 01:27:11 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Integrated TSS with storage of thread data; cleaned up the heap allocation functions to throw bad_alloc if they run out of memory
........
  r41057 | danieljames | 2007-11-13 03:51:23 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Don't use fpclass because it causes a warning for long doubles. I don't know if the warning is vaild here - but I don't want to disable it as it's useful for checking other function calls.
........
  r41059 | chris_kohlhoff | 2007-11-13 04:50:27 -0800 (Tue, 13 Nov 2007) | 6 lines
  
  Add a workaround for MSVC secure iterator problem where allowing the
  destruction of an iterator to an already-destroyed string object results in
  a program crash. Revert previous change to destroy buffers prior to
  invoking the handler since it didn't fix the problem and wasn't cleaning
  up all copies of the buffers anyway.
........
  r41060 | bemandawes | 2007-11-13 05:54:58 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Correct detection of failure to run in a boost tree, and refactor code as a separate set_boost_root function.
........
  r41062 | johnmaddock | 2007-11-13 08:15:27 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Ooops, disable long double overloads when there is no long double support (Borland fix).
........
  r41063 | eric_niebler | 2007-11-13 08:38:11 -0800 (Tue, 13 Nov 2007) | 1 line
  
  portability fix for Intel 8.1
........
  r41064 | johnmaddock | 2007-11-13 09:15:29 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Updated compiler status, and regenerated docs.
........
  r41069 | davedeakins | 2007-11-13 12:19:39 -0800 (Tue, 13 Nov 2007) | 1 line
  
  Have the local_time and universal_time functions use GetSystemTime and SystemTimeToFileTime on Windows CE (since GetSystemTimeAsFileTime is not present)
........


[SVN r41072]
2007-11-13 23:23:44 +00:00

568 lines
17 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
#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>
namespace boost
{
namespace
{
#if defined(_MSC_VER) && !defined(UNDER_CE)
__declspec(thread) detail::thread_data_base* current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#elif defined(__BORLANDC__)
detail::thread_data_base* __thread current_thread_data=0;
detail::thread_data_base* get_current_thread_data()
{
return current_thread_data;
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
current_thread_data=new_data;
}
#else
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));
}
#endif
#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::detail::tss_cleanup_function func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,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()
{
boost::intrusive_ptr<detail::thread_data_base> 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->key,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(boost::intrusive_ptr<detail::thread_data_base> data):
thread_info(data)
{}
namespace
{
struct externally_launched_thread:
detail::thread_data_base
{
externally_launched_thread()
{
++count;
interruption_enabled=false;
thread_handle=detail::win32::duplicate_handle(detail::win32::GetCurrentThread());
}
void run()
{}
};
void make_external_thread_data()
{
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
set_current_thread_data(me);
}
}
thread thread::self()
{
if(!get_current_thread_data())
{
make_external_thread_data();
}
return thread(boost::intrusive_ptr<detail::thread_data_base>(get_current_thread_data()));
}
thread::~thread()
{
detach();
}
thread::thread(boost::move_t<thread> x)
{
{
boost::mutex::scoped_lock l(x->thread_info_mutex);
thread_info=x->thread_info;
}
x->release_handle();
}
thread& thread::operator=(boost::move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
thread::operator boost::move_t<thread>()
{
return move();
}
boost::move_t<thread> thread::move()
{
boost::move_t<thread> x(*this);
return x;
}
void thread::swap(thread& x)
{
thread_info.swap(x.thread_info);
}
thread::id thread::get_id() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::id(local_thread_info->id):thread::id();
}
thread::interruption_handle thread::get_interruption_handle() const
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?thread::interruption_handle(local_thread_info->interruption_handle.duplicate()):thread::interruption_handle();
}
bool thread::joinable() const
{
return get_thread_info();
}
void thread::join()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::win32::infinite);
release_handle();
}
}
bool thread::timed_join(boost::system_time const& wait_until)
{
boost::intrusive_ptr<detail::thread_data_base> 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()
{
boost::mutex::scoped_lock l1(thread_info_mutex);
thread_info=0;
}
void thread::interrupt()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
if(local_thread_info)
{
detail::win32::SetEvent(local_thread_info->interruption_handle);
}
}
bool thread::interruption_requested() const
{
boost::intrusive_ptr<detail::thread_data_base> 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()
{
boost::intrusive_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
}
boost::intrusive_ptr<detail::thread_data_base> thread::get_thread_info() const
{
boost::mutex::scoped_lock l(thread_info_mutex);
return thread_info;
}
namespace this_thread
{
thread::interruption_handle get_interruption_handle()
{
return get_current_thread_data()?thread::interruption_handle(get_current_thread_data()->interruption_handle.duplicate()):thread::interruption_handle();
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,unsigned long milliseconds)
{
detail::win32::handle handles[2]={0};
unsigned handle_count=0;
unsigned interruption_index=~0U;
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
{
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;
}
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,milliseconds);
if((handle_to_wait_for!=detail::win32::invalid_handle_value) && !notified_index)
{
return true;
}
else if(notified_index==interruption_index)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
}
else
{
detail::win32::Sleep(milliseconds);
}
return false;
}
thread::id get_id()
{
return thread::id(detail::win32::GetCurrentThreadId());
}
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_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,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)
{
(current_node->func)(current_node->key,current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
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();
}
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();
}