Python: Upgraded boost to 1.58
This commit is contained in:
13
python/external/boost/libs/thread/index.html
vendored
13
python/external/boost/libs/thread/index.html
vendored
@@ -1,13 +0,0 @@
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
|
||||
</body>
|
||||
</html>
|
63
python/external/boost/libs/thread/src/future.cpp
vendored
63
python/external/boost/libs/thread/src/future.cpp
vendored
@@ -1,63 +0,0 @@
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
// 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>
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
|
||||
#include <boost/thread/future_error_code.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
class future_error_category :
|
||||
public boost::system::error_category
|
||||
{
|
||||
public:
|
||||
virtual const char* name() const BOOST_NOEXCEPT;
|
||||
virtual std::string message(int ev) const;
|
||||
};
|
||||
|
||||
const char*
|
||||
future_error_category::name() const BOOST_NOEXCEPT
|
||||
{
|
||||
return "future";
|
||||
}
|
||||
|
||||
std::string
|
||||
future_error_category::message(int ev) const
|
||||
{
|
||||
switch (BOOST_SCOPED_ENUM_NATIVE(future_errc)(ev))
|
||||
{
|
||||
case future_errc::broken_promise:
|
||||
return std::string("The associated promise has been destructed prior "
|
||||
"to the associated state becoming ready.");
|
||||
case future_errc::future_already_retrieved:
|
||||
return std::string("The future has already been retrieved from "
|
||||
"the promise or packaged_task.");
|
||||
case future_errc::promise_already_satisfied:
|
||||
return std::string("The state of the promise has already been set.");
|
||||
case future_errc::no_state:
|
||||
return std::string("Operation not permitted on an object without "
|
||||
"an associated state.");
|
||||
}
|
||||
return std::string("unspecified future_errc value\n");
|
||||
}
|
||||
future_error_category future_error_category_var;
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL
|
||||
const system::error_category&
|
||||
future_category() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread_detail::future_error_category_var;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,78 +0,0 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// 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/thread/detail/config.hpp>
|
||||
#ifdef BOOST_THREAD_ONCE_ATOMIC
|
||||
#include "./once_atomic.cpp"
|
||||
#else
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
BOOST_THREAD_DECL uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
|
||||
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
namespace
|
||||
{
|
||||
pthread_key_t epoch_tss_key;
|
||||
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void create_epoch_tss_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PATCH
|
||||
const pthread_once_t pthread_once_init_value=PTHREAD_ONCE_INIT;
|
||||
struct BOOST_THREAD_DECL delete_epoch_tss_key_on_dlclose_t
|
||||
{
|
||||
delete_epoch_tss_key_on_dlclose_t()
|
||||
{
|
||||
}
|
||||
~delete_epoch_tss_key_on_dlclose_t()
|
||||
{
|
||||
if(memcmp(&epoch_tss_key_flag, &pthread_once_init_value, sizeof(pthread_once_t)))
|
||||
{
|
||||
pthread_key_delete(epoch_tss_key);
|
||||
}
|
||||
}
|
||||
};
|
||||
delete_epoch_tss_key_on_dlclose_t delete_epoch_tss_key_on_dlclose;
|
||||
#endif
|
||||
}
|
||||
|
||||
uintmax_atomic_t& get_once_per_thread_epoch()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
|
||||
void* data=pthread_getspecific(epoch_tss_key);
|
||||
if(!data)
|
||||
{
|
||||
data=malloc(sizeof(thread_detail::uintmax_atomic_t));
|
||||
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
|
||||
*static_cast<thread_detail::uintmax_atomic_t*>(data)=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C;
|
||||
}
|
||||
return *static_cast<thread_detail::uintmax_atomic_t*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif //
|
@@ -1,90 +0,0 @@
|
||||
// (C) Copyright 2013 Andrey Semashev
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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)
|
||||
|
||||
//#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <pthread.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
enum flag_states
|
||||
{
|
||||
uninitialized, in_progress, initialized
|
||||
};
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(atomic_int_type) == sizeof(atomic_type), "Boost.Thread: unsupported platform");
|
||||
#endif
|
||||
|
||||
static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
if (f.load(memory_order_acquire) != initialized)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
if (f.load(memory_order_acquire) != initialized)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
atomic_int_type expected = uninitialized;
|
||||
if (f.compare_exchange_strong(expected, in_progress, memory_order_acq_rel, memory_order_acquire))
|
||||
{
|
||||
// We have set the flag to in_progress
|
||||
return true;
|
||||
}
|
||||
else if (expected == initialized)
|
||||
{
|
||||
// Another thread managed to complete the initialization
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait until the initialization is complete
|
||||
//pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_wait(&once_cv, &once_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
f.store(initialized, memory_order_release);
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT
|
||||
{
|
||||
atomic_type& f = get_atomic_storage(flag);
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&once_mutex);
|
||||
f.store(uninitialized, memory_order_release);
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&once_cv));
|
||||
}
|
||||
|
||||
} // namespace thread_detail
|
||||
|
||||
} // namespace boost
|
@@ -1,767 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#endif
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined BOOST_HAS_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "./timeconv.inl"
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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_)
|
||||
{}
|
||||
};
|
||||
|
||||
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
|
||||
pthread_key_t current_thread_tls_key;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
{
|
||||
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
|
||||
thread_info->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
delete current_node->func;
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
for(std::map<void const*,tss_data_node>::iterator next=thread_info->tss_data.begin(),
|
||||
current,
|
||||
end=thread_info->tss_data.end();
|
||||
next!=end;)
|
||||
{
|
||||
current=next;
|
||||
++next;
|
||||
if(current->second.func && (current->second.value!=0))
|
||||
{
|
||||
(*current->second.func)(current->second.value);
|
||||
}
|
||||
thread_info->tss_data.erase(current);
|
||||
}
|
||||
}
|
||||
if (thread_info) // fixme: should we test this?
|
||||
{
|
||||
thread_info->self.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PATCH
|
||||
|
||||
struct delete_current_thread_tls_key_on_dlclose_t
|
||||
{
|
||||
delete_current_thread_tls_key_on_dlclose_t()
|
||||
{
|
||||
}
|
||||
~delete_current_thread_tls_key_on_dlclose_t()
|
||||
{
|
||||
if (current_thread_tls_init_flag.epoch!=BOOST_ONCE_INITIAL_FLAG_VALUE)
|
||||
{
|
||||
pthread_key_delete(current_thread_tls_key);
|
||||
}
|
||||
}
|
||||
};
|
||||
delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
|
||||
#endif
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor));
|
||||
}
|
||||
}
|
||||
|
||||
boost::detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
return (boost::detail::thread_data_base*)pthread_getspecific(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(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
static void* thread_proxy(void* param)
|
||||
{
|
||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
||||
thread_info->self.reset();
|
||||
detail::set_current_thread_data(thread_info.get());
|
||||
#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(...)
|
||||
// {
|
||||
// throw;
|
||||
//
|
||||
// std::terminate();
|
||||
// }
|
||||
BOOST_CATCH_END
|
||||
#endif
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
|
||||
thread_info->done=true;
|
||||
thread_info->done_condition.notify_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace detail
|
||||
{
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
interrupt_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&);
|
||||
};
|
||||
|
||||
thread_data_base* make_external_thread_data()
|
||||
{
|
||||
thread_data_base* const me(new externally_launched_thread());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
thread_data_base* current_thread_data(get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
current_thread_data=make_external_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
thread::thread() BOOST_NOEXCEPT
|
||||
{}
|
||||
|
||||
bool thread::start_thread_noexcept()
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
return false;
|
||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thread::start_thread_noexcept(const attributes& attr)
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
const attributes::native_handle_type* h = attr.native_handle();
|
||||
int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
return false;
|
||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
|
||||
}
|
||||
int detached_state;
|
||||
res = pthread_attr_getdetachstate(h, &detached_state);
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
return false;
|
||||
// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_attr_getdetachstate"));
|
||||
}
|
||||
if (PTHREAD_CREATE_DETACHED==detached_state)
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
//lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
//BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
{
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
bool thread::join_noexcept()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::do_try_join_until_noexcept(struct timespec const &timeout, bool& res)
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
if(!local_thread_info->done_condition.do_wait_until(lock,timeout))
|
||||
{
|
||||
res=false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
res=true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return (get_thread_info)()?true:false;
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
|
||||
|
||||
if(thread_info)
|
||||
{
|
||||
unique_lock<mutex> lk(thread_info->sleep_mutex);
|
||||
while( thread_info->sleep_condition.do_wait_for(lk,ts)) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
# if defined(__IBMCPP__)
|
||||
BOOST_VERIFY(!pthread_delay_np(const_cast<timespec*>(&ts)));
|
||||
# else
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# endif
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_for(lock, ts);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts)
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data();
|
||||
|
||||
if(thread_info)
|
||||
{
|
||||
unique_lock<mutex> lk(thread_info->sleep_mutex);
|
||||
while(thread_info->sleep_condition.do_wait_until(lk,ts)) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
timespec now = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_gt(ts, now))
|
||||
{
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
BOOST_VERIFY(!pthread_delay_np(&d));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
timespec d = boost::detail::timespec_minus(ts, now);
|
||||
nanosleep(&d, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
unique_lock<mutex> lock(mx);
|
||||
condition_variable cond;
|
||||
cond.do_wait_until(lock, ts);
|
||||
# endif
|
||||
timespec now2 = boost::detail::timespec_now();
|
||||
if (boost::detail::timespec_ge(now2, ts))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // hiden
|
||||
} // this_thread
|
||||
namespace this_thread
|
||||
{
|
||||
void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
# if defined(BOOST_HAS_SCHED_YIELD)
|
||||
BOOST_VERIFY(!sched_yield());
|
||||
# elif defined(BOOST_HAS_PTHREAD_YIELD)
|
||||
BOOST_VERIFY(!pthread_yield());
|
||||
//# elif defined BOOST_THREAD_USES_DATETIME
|
||||
// xtime xt;
|
||||
// xtime_get(&xt, TIME_UTC_);
|
||||
// sleep(xt);
|
||||
// sleep_for(chrono::milliseconds(0));
|
||||
# else
|
||||
#error
|
||||
timespec ts;
|
||||
ts.tv_sec= 0;
|
||||
ts.tv_nsec= 0;
|
||||
hiden::sleep_for(ts);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined(PTW32_VERSION) || defined(__hpux)
|
||||
return pthread_num_processors_np();
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
|
||||
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
|
||||
int const count=sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (count>0)?count:0;
|
||||
#elif defined(__GLIBC__)
|
||||
return get_nprocs();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
local_thread_info->interrupt_requested=true;
|
||||
if(local_thread_info->current_cond)
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const BOOST_NOEXCEPT
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->interrupt_requested;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->thread_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
namespace this_thread
|
||||
{
|
||||
void interruption_point()
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool interruption_enabled() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
return thread_info && thread_info->interrupt_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(!thread_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
return thread_info->interrupt_requested;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption() BOOST_NOEXCEPT:
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_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=
|
||||
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 ¤t_node->second;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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_current_thread_data());
|
||||
if(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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@@ -1,151 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2009 Anthony Williams
|
||||
//
|
||||
// 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)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
#else
|
||||
ts.tv_sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
ts.tv_nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++ts.tv_sec;
|
||||
ts.tv_nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
@@ -1,38 +0,0 @@
|
||||
// (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)
|
@@ -1,769 +0,0 @@
|
||||
// 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>
|
||||
|
||||
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
|
||||
DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
|
||||
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!=TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
}
|
||||
|
||||
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 (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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
namespace detail
|
||||
{
|
||||
thread_data_base* get_current_thread_data()
|
||||
{
|
||||
if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
}
|
||||
}
|
||||
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_)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
for(std::map<void const*,detail::tss_data_node>::iterator next=current_thread_data->tss_data.begin(),
|
||||
current,
|
||||
end=current_thread_data->tss_data.end();
|
||||
next!=end;)
|
||||
{
|
||||
current=next;
|
||||
++next;
|
||||
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()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
bool thread::start_thread_noexcept(const attributes& attr)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
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)();
|
||||
return local_thread_info?local_thread_info->id:0;
|
||||
//return const_cast<thread*>(this)->native_handle();
|
||||
#else
|
||||
return thread::id((get_thread_info)());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool thread::joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return (get_thread_info)() ? true : false;
|
||||
}
|
||||
bool thread::join_noexcept()
|
||||
{
|
||||
|
||||
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();
|
||||
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(local_thread_info->thread_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::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
//SYSTEM_INFO info={{0}};
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
#endif
|
||||
|
||||
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 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)
|
||||
{
|
||||
unsigned long 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
#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
|
||||
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;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
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::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,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 ¤t_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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
@@ -1,130 +0,0 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// 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)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
@@ -1,77 +0,0 @@
|
||||
// (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/thread/detail/config.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#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.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
@@ -1,325 +0,0 @@
|
||||
// $Id: tss_pe.cpp 84717 2013-06-09 17:18:15Z viboes $
|
||||
// (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/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_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>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#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)(HANDLE, DWORD, LPVOID);
|
||||
extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HANDLE, 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) // 1300 == VC++ 7.0
|
||||
typedef void (__cdecl *_PVFV)();
|
||||
#define INIRETSUCCESS
|
||||
#define PVAPI void __cdecl
|
||||
#else
|
||||
typedef int (__cdecl *_PVFV)();
|
||||
#define INIRETSUCCESS 0
|
||||
#define PVAPI 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 on_tls_prepare();
|
||||
static PVAPI on_process_init();
|
||||
static PVAPI 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"))_PVFV 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 _PVFV 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 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;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
PVAPI 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;
|
||||
}
|
||||
|
||||
PVAPI on_process_term()
|
||||
{
|
||||
boost::on_process_exit();
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
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(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)
|
||||
#else
|
||||
BOOL WINAPI dll_callback(HANDLE, 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)(HANDLE, 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)
|
Reference in New Issue
Block a user