mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
2 Commits
boost-1.36
...
boost-1.37
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c5df23f20 | ||
|
|
0997fad8ec |
@@ -77,4 +77,7 @@ been moved to __thread_id__.
|
||||
|
||||
* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
|
||||
|
||||
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
|
||||
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -41,9 +41,9 @@ namespace boost
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
|
||||
{
|
||||
return t;
|
||||
return T(detail::thread_move_t<T>(t));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -339,9 +339,9 @@ namespace boost
|
||||
return t;
|
||||
}
|
||||
#else
|
||||
inline detail::thread_move_t<thread> move(detail::thread_move_t<thread> t)
|
||||
inline thread move(detail::thread_move_t<thread> t)
|
||||
{
|
||||
return t;
|
||||
return thread(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -234,6 +234,12 @@ namespace boost
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
template<typename TimeDuration>
|
||||
unique_lock(Mutex& m_,TimeDuration const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
unique_lock(Mutex& m_,system_time const& target_time):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace boost
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(abs_time);
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,18 +57,18 @@ namespace boost
|
||||
void lock_shared()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
shared_cond.wait(lock);
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
@@ -84,11 +84,11 @@ namespace boost
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace boost
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
@@ -127,12 +127,12 @@ namespace boost
|
||||
void lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
exclusive_cond.wait(lock);
|
||||
exclusive_cond.wait(lk);
|
||||
}
|
||||
state.exclusive=true;
|
||||
}
|
||||
@@ -140,12 +140,12 @@ namespace boost
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
if(!exclusive_cond.timed_wait(lock,timeout))
|
||||
if(!exclusive_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -168,7 +168,7 @@ namespace boost
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
@@ -193,10 +193,10 @@ namespace boost
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
shared_cond.wait(lock);
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
@@ -205,10 +205,10 @@ namespace boost
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lock,timeout))
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
@@ -230,7 +230,7 @@ namespace boost
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
@@ -245,7 +245,7 @@ namespace boost
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
@@ -259,11 +259,11 @@ namespace boost
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
{
|
||||
upgrade_cond.wait(lock);
|
||||
upgrade_cond.wait(lk);
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
@@ -271,7 +271,7 @@ namespace boost
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
@@ -281,7 +281,7 @@ namespace boost
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
@@ -290,7 +290,7 @@ namespace boost
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(state_change);
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
|
||||
@@ -64,11 +64,6 @@ namespace boost
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
long get_active_count()
|
||||
{
|
||||
return mutex.get_active_count();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
@@ -78,11 +73,6 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return mutex.locked();
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
|
||||
@@ -123,11 +123,6 @@ namespace boost
|
||||
return timed_lock(system_time(timeout));
|
||||
}
|
||||
|
||||
long get_active_count()
|
||||
{
|
||||
return ::boost::detail::interlocked_read_acquire(&active_count);
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
long const offset=lock_flag_value;
|
||||
@@ -141,11 +136,6 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
bool locked()
|
||||
{
|
||||
return get_active_count()>=lock_flag_value;
|
||||
}
|
||||
|
||||
private:
|
||||
void* get_event()
|
||||
{
|
||||
|
||||
0
src/pthread/once.cpp
Executable file → Normal file
0
src/pthread/once.cpp
Executable file → Normal file
@@ -29,13 +29,26 @@ namespace boost
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
current_thread_tls_key=TlsAlloc();
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
|
||||
void cleanup_tls_key()
|
||||
{
|
||||
if(current_thread_tls_key)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=0;
|
||||
}
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
if(!current_thread_tls_key)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
}
|
||||
|
||||
@@ -141,8 +154,8 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
set_current_thread_data(0);
|
||||
}
|
||||
set_current_thread_data(0);
|
||||
}
|
||||
|
||||
unsigned __stdcall thread_start_function(void* param)
|
||||
@@ -544,7 +557,6 @@ namespace boost
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func.get())
|
||||
@@ -572,7 +584,9 @@ extern "C" BOOST_THREAD_DECL void on_thread_enter()
|
||||
{}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_process_exit()
|
||||
{}
|
||||
{
|
||||
boost::cleanup_tls_key();
|
||||
}
|
||||
|
||||
extern "C" BOOST_THREAD_DECL void on_thread_exit()
|
||||
{
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace {
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,10 +125,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#pragma section(".CRT$XCU",long,read)
|
||||
#pragma section(".CRT$XTU",long,read)
|
||||
#pragma section(".CRT$XLC",long,read)
|
||||
static __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
|
||||
static __declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
|
||||
static __declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
|
||||
static __declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
|
||||
__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)
|
||||
@@ -168,6 +168,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4189)
|
||||
#endif
|
||||
|
||||
PVAPI on_tls_prepare(void)
|
||||
{
|
||||
//The following line has an important side effect:
|
||||
@@ -239,15 +240,32 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
case DLL_THREAD_DETACH:
|
||||
on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
on_thread_exit();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
on_process_exit();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
|
||||
}
|
||||
|
||||
extern "C" void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
@@ -96,6 +97,86 @@ struct test_trylock
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Mutex>
|
||||
struct test_lock_times_out_if_other_thread_has_lock
|
||||
{
|
||||
typedef boost::unique_lock<Mutex> Lock;
|
||||
|
||||
Mutex m;
|
||||
boost::mutex done_mutex;
|
||||
bool done;
|
||||
bool locked;
|
||||
boost::condition_variable done_cond;
|
||||
|
||||
test_lock_times_out_if_other_thread_has_lock():
|
||||
done(false),locked(false)
|
||||
{}
|
||||
|
||||
void locking_thread()
|
||||
{
|
||||
Lock lock(m,boost::defer_lock);
|
||||
lock.timed_lock(boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
void locking_thread_through_constructor()
|
||||
{
|
||||
Lock lock(m,boost::posix_time::milliseconds(50));
|
||||
|
||||
boost::lock_guard<boost::mutex> lk(done_mutex);
|
||||
locked=lock.owns_lock();
|
||||
done=true;
|
||||
done_cond.notify_one();
|
||||
}
|
||||
|
||||
bool is_done() const
|
||||
{
|
||||
return done;
|
||||
}
|
||||
|
||||
typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
|
||||
|
||||
void do_test(void (this_type::*test_func)())
|
||||
{
|
||||
Lock lock(m);
|
||||
|
||||
locked=false;
|
||||
done=false;
|
||||
|
||||
boost::thread t(test_func,this);
|
||||
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lk(done_mutex);
|
||||
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
|
||||
boost::bind(&this_type::is_done,this)));
|
||||
BOOST_CHECK(!locked);
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
t.join();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
lock.unlock();
|
||||
t.join();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
do_test(&this_type::locking_thread);
|
||||
do_test(&this_type::locking_thread_through_constructor);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
struct test_timedlock
|
||||
{
|
||||
@@ -109,6 +190,8 @@ struct test_timedlock
|
||||
|
||||
void operator()()
|
||||
{
|
||||
test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
|
||||
|
||||
mutex_type mutex;
|
||||
boost::condition condition;
|
||||
|
||||
@@ -178,6 +261,7 @@ struct test_recursive_lock
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void do_test_mutex()
|
||||
{
|
||||
test_lock<boost::mutex>()();
|
||||
|
||||
@@ -5,26 +5,59 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
void do_nothing()
|
||||
{}
|
||||
void do_nothing(boost::thread::id* my_id)
|
||||
{
|
||||
*my_id=boost::this_thread::get_id();
|
||||
}
|
||||
|
||||
void test_move_on_construction()
|
||||
{
|
||||
boost::thread x=boost::thread(do_nothing);
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=boost::thread(do_nothing,&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::thread make_thread()
|
||||
boost::thread make_thread(boost::thread::id* the_id)
|
||||
{
|
||||
return boost::thread(do_nothing);
|
||||
return boost::thread(do_nothing,the_id);
|
||||
}
|
||||
|
||||
void test_move_from_function_return()
|
||||
{
|
||||
boost::thread x=make_thread();
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::thread make_thread_return_lvalue(boost::thread::id* the_id)
|
||||
{
|
||||
boost::thread t(do_nothing,the_id);
|
||||
return boost::move(t);
|
||||
}
|
||||
|
||||
void test_move_from_function_return_lvalue()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x=make_thread_return_lvalue(&the_id);
|
||||
boost::thread::id x_id=x.get_id();
|
||||
x.join();
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
void test_move_assign()
|
||||
{
|
||||
boost::thread::id the_id;
|
||||
boost::thread x(do_nothing,&the_id);
|
||||
boost::thread y;
|
||||
y=boost::move(x);
|
||||
boost::thread::id y_id=y.get_id();
|
||||
y.join();
|
||||
BOOST_CHECK_EQUAL(the_id,y_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
@@ -33,5 +66,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_on_construction));
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return));
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return_lvalue));
|
||||
test->add(BOOST_TEST_CASE(test_move_assign));
|
||||
return test;
|
||||
}
|
||||
|
||||
366
test/util.inl
366
test/util.inl
@@ -1,183 +1,183 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 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)
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
|
||||
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
void operator=(indirect_adapter&);
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class thread_binder
|
||||
{
|
||||
public:
|
||||
thread_binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
thread_binder<F, T> bind(const F& func, const T& param)
|
||||
{
|
||||
return thread_binder<F, T>(func, param);
|
||||
}
|
||||
|
||||
template <typename R, typename T>
|
||||
class thread_member_binder
|
||||
{
|
||||
public:
|
||||
thread_member_binder(R (T::*func)(), T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { (param.*func)(); }
|
||||
|
||||
private:
|
||||
void operator=(thread_member_binder&);
|
||||
|
||||
R (T::*func)();
|
||||
T& param;
|
||||
};
|
||||
|
||||
|
||||
template <typename R, typename T>
|
||||
thread_member_binder<R, T> bind(R (T::*func)(), T& param)
|
||||
{
|
||||
return thread_member_binder<R, T>(func, param);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 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)
|
||||
|
||||
#if !defined(UTIL_INL_WEK01242003)
|
||||
#define UTIL_INL_WEK01242003
|
||||
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
|
||||
# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
|
||||
#endif
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace
|
||||
{
|
||||
inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
|
||||
{
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
boost::xtime xt;
|
||||
if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
|
||||
BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
|
||||
|
||||
nsecs += xt.nsec;
|
||||
msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
|
||||
secs += msecs / MILLISECONDS_PER_SECOND;
|
||||
nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
|
||||
xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
|
||||
xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
|
||||
|
||||
return xt;
|
||||
}
|
||||
|
||||
inline bool in_range(const boost::xtime& xt, int secs=1)
|
||||
{
|
||||
boost::xtime min = delay(-secs);
|
||||
boost::xtime max = delay(0);
|
||||
return (boost::xtime_cmp(xt, min) >= 0) &&
|
||||
(boost::xtime_cmp(xt, max) <= 0);
|
||||
}
|
||||
|
||||
class execution_monitor
|
||||
{
|
||||
public:
|
||||
enum wait_type { use_sleep_only, use_mutex, use_condition };
|
||||
|
||||
execution_monitor(wait_type type, int secs)
|
||||
: done(false), type(type), secs(secs) { }
|
||||
void start()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex); done = false;
|
||||
} else {
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
void finish()
|
||||
{
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
done = true;
|
||||
if (type == use_condition)
|
||||
cond.notify_one();
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
bool wait()
|
||||
{
|
||||
boost::xtime xt = delay(secs);
|
||||
if (type != use_condition)
|
||||
boost::thread::sleep(xt);
|
||||
if (type != use_sleep_only) {
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
while (type == use_condition && !done) {
|
||||
if (!cond.timed_wait(lock, xt))
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
bool done;
|
||||
wait_type type;
|
||||
int secs;
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
class indirect_adapter
|
||||
{
|
||||
public:
|
||||
indirect_adapter(F func, execution_monitor& monitor)
|
||||
: func(func), monitor(monitor) { }
|
||||
void operator()() const
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::thread thrd(func);
|
||||
thrd.join();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
monitor.finish();
|
||||
throw;
|
||||
}
|
||||
monitor.finish();
|
||||
}
|
||||
|
||||
private:
|
||||
F func;
|
||||
execution_monitor& monitor;
|
||||
void operator=(indirect_adapter&);
|
||||
};
|
||||
|
||||
template <typename F>
|
||||
void timed_test(F func, int secs,
|
||||
execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
|
||||
{
|
||||
execution_monitor monitor(type, secs);
|
||||
indirect_adapter<F> ifunc(func, monitor);
|
||||
monitor.start();
|
||||
boost::thread thrd(ifunc);
|
||||
BOOST_REQUIRE_MESSAGE(monitor.wait(),
|
||||
"Timed test didn't complete in time, possible deadlock.");
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
class thread_binder
|
||||
{
|
||||
public:
|
||||
thread_binder(const F& func, const T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { func(param); }
|
||||
|
||||
private:
|
||||
F func;
|
||||
T param;
|
||||
};
|
||||
|
||||
template <typename F, typename T>
|
||||
thread_binder<F, T> bind(const F& func, const T& param)
|
||||
{
|
||||
return thread_binder<F, T>(func, param);
|
||||
}
|
||||
|
||||
template <typename R, typename T>
|
||||
class thread_member_binder
|
||||
{
|
||||
public:
|
||||
thread_member_binder(R (T::*func)(), T& param)
|
||||
: func(func), param(param) { }
|
||||
void operator()() const { (param.*func)(); }
|
||||
|
||||
private:
|
||||
void operator=(thread_member_binder&);
|
||||
|
||||
R (T::*func)();
|
||||
T& param;
|
||||
};
|
||||
|
||||
|
||||
template <typename R, typename T>
|
||||
thread_member_binder<R, T> bind(R (T::*func)(), T& param)
|
||||
{
|
||||
return thread_member_binder<R, T>(func, param);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user