mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2026-06-01 13:44:08 -04:00
Squashed 'boost/' content from commit b4feb19f2
git-subtree-dir: boost git-subtree-split: b4feb19f287ee92d87a9624b5d36b7cf46aeadeb
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
// (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/futures/future_error_code.hpp>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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 <boost/throw_exception.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <string.h> // memcmp.
|
||||
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)))
|
||||
{
|
||||
void* data = pthread_getspecific(epoch_tss_key);
|
||||
if (data)
|
||||
delete_epoch_tss_data(data);
|
||||
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));
|
||||
if(!data) BOOST_THROW_EXCEPTION(std::bad_alloc());
|
||||
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 //
|
||||
@@ -0,0 +1,90 @@
|
||||
// (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
|
||||
@@ -0,0 +1,846 @@
|
||||
// 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 <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <string.h> // memcmp.
|
||||
|
||||
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);
|
||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
|
||||
|
||||
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;
|
||||
}
|
||||
while (!thread_info->tss_data.empty())
|
||||
{
|
||||
std::map<void const*,detail::tss_data_node>::iterator current
|
||||
= thread_info->tss_data.begin();
|
||||
if(current->second.func && (current->second.value!=0))
|
||||
{
|
||||
(*current->second.func)(current->second.value);
|
||||
}
|
||||
thread_info->tss_data.erase(current);
|
||||
}
|
||||
}
|
||||
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()
|
||||
{
|
||||
const boost::once_flag uninitialized = BOOST_ONCE_INIT;
|
||||
if (memcmp(¤t_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag)))
|
||||
{
|
||||
void* data = pthread_getspecific(current_thread_tls_key);
|
||||
if (data)
|
||||
tls_destructor(data);
|
||||
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;
|
||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->shared_from_this();
|
||||
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(detail::heap_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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
int detached_state;
|
||||
res = pthread_attr_getdetachstate(h, &detached_state);
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
return false;
|
||||
}
|
||||
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 no_interruption_point
|
||||
{
|
||||
namespace hidden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts)
|
||||
{
|
||||
|
||||
if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero()))
|
||||
{
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
# if defined(__IBMCPP__) || defined(_AIX)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
namespace hidden
|
||||
{
|
||||
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
|
||||
{
|
||||
boost::this_thread::no_interruption_point::hidden::sleep_for(ts);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
boost::this_thread::no_interruption_point::hidden::sleep_until(ts);
|
||||
}
|
||||
}
|
||||
} // hidden
|
||||
} // 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;
|
||||
hidden::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
|
||||
}
|
||||
|
||||
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#ifdef __linux__
|
||||
try {
|
||||
using namespace std;
|
||||
|
||||
ifstream proc_cpuinfo ("/proc/cpuinfo");
|
||||
|
||||
const string physical_id("physical id"), core_id("core id");
|
||||
|
||||
typedef std::pair<unsigned, unsigned> core_entry; // [physical ID, core id]
|
||||
|
||||
std::set<core_entry> cores;
|
||||
|
||||
core_entry current_core_entry;
|
||||
|
||||
string line;
|
||||
while ( getline(proc_cpuinfo, line) ) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
vector<string> key_val(2);
|
||||
boost::split(key_val, line, boost::is_any_of(":"));
|
||||
|
||||
if (key_val.size() != 2)
|
||||
return hardware_concurrency();
|
||||
|
||||
string key = key_val[0];
|
||||
string value = key_val[1];
|
||||
boost::trim(key);
|
||||
boost::trim(value);
|
||||
|
||||
if (key == physical_id) {
|
||||
current_core_entry.first = boost::lexical_cast<unsigned>(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key == core_id) {
|
||||
current_core_entry.second = boost::lexical_cast<unsigned>(value);
|
||||
cores.insert(current_core_entry);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Fall back to hardware_concurrency() in case
|
||||
// /proc/cpuinfo is formatted differently than we expect.
|
||||
return cores.size() != 0 ? cores.size() : hardware_concurrency();
|
||||
} catch(...) {
|
||||
return hardware_concurrency();
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count;
|
||||
#else
|
||||
return hardware_concurrency();
|
||||
#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=
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
// (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)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
// (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/detail/winapi/config.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#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.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#else //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Prevent LNK4221 warning with link=static
|
||||
namespace boost { namespace link_static_warning_inhibit {
|
||||
extern __declspec(dllexport) void foo() { }
|
||||
} }
|
||||
#endif
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
@@ -0,0 +1,325 @@
|
||||
// $Id$
|
||||
// (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/detail/winapi/config.hpp>
|
||||
#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>
|
||||
|
||||
#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) || (_MSC_VER > 1900) // 1300 == VC++ 7.0, 1900 == VC++ 14.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