From ca10110aa7bfe1ec5ab46c9470ae596073619ae9 Mon Sep 17 00:00:00 2001 From: "William E. Kempf" Date: Tue, 21 Jan 2003 22:57:30 +0000 Subject: [PATCH] Updated tests for new thread design [SVN r16984] --- include/boost/thread/thread.hpp | 11 +- src/thread.cpp | 197 ++++++++++++++------------------ test/test_thread.cpp | 66 +++++------ test/utils.inl | 46 +++++--- 4 files changed, 157 insertions(+), 163 deletions(-) diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index c02c6db5..67e200da 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -137,16 +137,15 @@ public: static const int stack_min; -private: - template - friend std::basic_ostream& operator<<(std::basic_ostream&, const thread&); - #if defined(BOOST_HAS_WINTHREADS) - long id() const; + typedef unsigned int id_type; #else - const void* id() const; + typedef void* id_type; #endif + + id_type id() const; +private: void* m_handle; }; diff --git a/src/thread.cpp b/src/thread.cpp index f8f4bff8..1e07bfa3 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,32 @@ #include "timeconv.inl" -namespace boost { +namespace { + +struct pointer_based +{ + template + static const void* do_from(const T& obj) { return obj; } +}; + +struct value_based +{ + template + static const void* do_from(const T& obj) { return 0; } +}; + +template +struct as_pointer : private boost::mpl::if_, pointer_based, value_based>::type +{ + static const void* from(const T& obj) { return do_from(obj); } +}; + +struct thread_equals +{ + thread_equals(boost::thread& thrd) : m_thrd(thrd) { } + bool operator()(boost::thread* thrd) { return *thrd == m_thrd; } + boost::thread& m_thrd; +}; class thread_data { @@ -57,14 +83,10 @@ public: void disable_cancellation(); void test_cancel(); void run(); -#if defined(BOOST_HAS_WINTHREADS) - long id() const; -#else - const void* id() const; -#endif + boost::thread::id_type id() const; - void set_scheduling_parameter(int policy, const sched_param& param); - void get_scheduling_parameter(int& policy, sched_param& param) const; + void set_scheduling_parameter(int policy, const boost::sched_param& param); + void get_scheduling_parameter(int& policy, boost::sched_param& param) const; static thread_data* get_current(); @@ -88,88 +110,24 @@ private: bool m_native; }; -} // namespace boost - -namespace { - -struct pointer_based -{ - template - static const void* do_from(const T& obj) { return obj; } -}; - -struct value_based -{ - template - static const void* do_from(const T& obj) { return 0; } -}; - -template -struct as_pointer : private boost::mpl::if_, pointer_based, value_based>::type -{ - static const void* from(const T& obj) { return do_from(obj); } -}; - -void release_tss_data(boost::thread_data* data) +void release_tss_data(thread_data* data) { assert(data); if (data->release()) delete data; } -boost::thread_specific_ptr tss_thread_data(&release_tss_data); - -struct thread_equals -{ - thread_equals(boost::thread& thrd) : m_thrd(thrd) { } - bool operator()(boost::thread* thrd) { return *thrd == m_thrd; } - boost::thread& m_thrd; -}; - -} // unnamed namespace - -extern "C" { - -#if defined(BOOST_HAS_WINTHREADS) -unsigned __stdcall thread_proxy(void* param) -#elif defined(BOOST_HAS_PTHREADS) -static void* thread_proxy(void* param) -#elif defined(BOOST_HAS_MPTASKS) -static OSStatus thread_proxy(void* param) -#endif -{ - try - { - boost::thread_data* tdata = static_cast(param); - tss_thread_data.reset(tdata); - tdata->run(); - } - catch (boost::thread_cancel) - { - } - catch (...) - { - std::terminate(); - } -#if defined(BOOST_HAS_MPTASKS) - ::boost::detail::thread_cleanup(); -#endif - return 0; -} - -} // extern "C" - -namespace boost { +boost::thread_specific_ptr tss_thread_data(&release_tss_data); thread_data::thread_data(const boost::function0& threadfunc) - : m_threadfunc(threadfunc), m_refcount(2), m_state(creating), m_canceled(false), m_native(false), - m_cancellation_disabled_level(0) + : m_threadfunc(threadfunc), m_refcount(2), m_state(creating), m_canceled(false), + m_cancellation_disabled_level(0), m_native(false) { } thread_data::thread_data() - : m_refcount(1), m_state(running), m_canceled(false), m_native(true), - m_cancellation_disabled_level(0) + : m_refcount(1), m_state(running), m_canceled(false), + m_cancellation_disabled_level(0), m_native(true) { #if defined(BOOST_HAS_WINTHREADS) DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), @@ -304,45 +262,35 @@ void thread_data::run() m_threadfunc(); } +boost::thread::id_type thread_data::id() const +{ + boost::mutex::scoped_lock lock(m_mutex); + while (m_state == creating) + m_cond.wait(lock); + + if (m_state != joined) #if defined(BOOST_HAS_WINTHREADS) -long thread_data::id() const -{ - boost::mutex::scoped_lock lock(m_mutex); - while (m_state == creating) - m_cond.wait(lock); - - if (m_state != joined) return m_id; - - return 0; // throw instead? -} #else -const void* thread_data::id() const -{ - boost::mutex::scoped_lock lock(m_mutex); - while (m_state == creating) - m_cond.wait(lock); - - if (m_state != joined) { const void* res = as_pointer::from(m_thread); if (res == 0) res = this; return res; } +#endif return 0; // throw instead? } -#endif -void thread_data::set_scheduling_parameter(int policy, const sched_param& param) +void thread_data::set_scheduling_parameter(int policy, const boost::sched_param& param) { boost::mutex::scoped_lock lock(m_mutex); while (m_state == creating) m_cond.wait(lock); #if defined(BOOST_HAS_WINTHREADS) - if (policy != sched_other) + if (policy != boost::sched_other) throw boost::invalid_thread_argument(); if (param.priority < THREAD_PRIORITY_LOWEST || param.priority > THREAD_PRIORITY_HIGHEST) throw boost::invalid_thread_argument(); @@ -368,14 +316,14 @@ void thread_data::set_scheduling_parameter(int policy, const sched_param& param) #endif } -void thread_data::get_scheduling_parameter(int& policy, sched_param& param) const +void thread_data::get_scheduling_parameter(int& policy, boost::sched_param& param) const { boost::mutex::scoped_lock lock(m_mutex); while (m_state == creating) m_cond.wait(lock); #if defined(BOOST_HAS_WINTHREADS) - policy = sched_other; + policy = boost::sched_other; param.priority = GetThreadPriority(m_thread); #elif defined(BOOST_HAS_PTHREADS) # if defined(_POSIX_THREAD_PRIORITY_SCHEDULING) @@ -393,14 +341,50 @@ thread_data* thread_data::get_current() thread_data* data = tss_thread_data.get(); if (data == 0) { - data = new(std::nothrow) thread_data; + data = new thread_data; if (!data) - throw thread_resource_error(); + throw std::bad_alloc(); tss_thread_data.reset(data); } return data; } +} // unnamed namespace + +extern "C" { + +#if defined(BOOST_HAS_WINTHREADS) +unsigned __stdcall thread_proxy(void* param) +#elif defined(BOOST_HAS_PTHREADS) +static void* thread_proxy(void* param) +#elif defined(BOOST_HAS_MPTASKS) +static OSStatus thread_proxy(void* param) +#endif +{ + try + { + thread_data* data = static_cast(param); + tss_thread_data.reset(data); + data->run(); + } + catch (boost::thread_cancel) + { + } + catch (...) + { + using namespace std; + terminate(); + } +#if defined(BOOST_HAS_MPTASKS) + ::boost::detail::thread_cleanup(); +#endif + return 0; +} + +} // extern "C" + +namespace boost { + thread_cancel::thread_cancel() { } @@ -654,7 +638,7 @@ thread::thread() thread::thread(const function0& threadfunc, attributes attr) : m_handle(0) { - std::auto_ptr param(new(std::nothrow) thread_data(threadfunc)); + std::auto_ptr param(new thread_data(threadfunc)); if (param.get() == 0) throw thread_resource_error(); #if defined(BOOST_HAS_WINTHREADS) @@ -852,13 +836,8 @@ void thread::yield() thread::test_cancel(); } -#if defined(BOOST_HAS_WINTHREADS) -long thread::id() const -#else -const void* thread::id() const -#endif +thread::id_type thread::id() const { - std::cout << *this; return static_cast(m_handle)->id(); } diff --git a/test/test_thread.cpp b/test/test_thread.cpp index b5da0c7a..56789cc6 100644 --- a/test/test_thread.cpp +++ b/test/test_thread.cpp @@ -2,26 +2,10 @@ #include //#include #include +#include namespace { - inline bool xtime_in_range(boost::xtime& xt, int less_seconds, - int greater_seconds) - { - boost::xtime cur; - BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), - static_cast(boost::TIME_UTC)); - - boost::xtime less = cur; - less.sec += less_seconds; - - boost::xtime greater = cur; - greater.sec += greater_seconds; - - return (boost::xtime_cmp(xt, less) >= 0) && - (boost::xtime_cmp(xt, greater) <= 0); - } - int test_value; void simple_thread() @@ -31,19 +15,19 @@ namespace void cancel_thread() { - // Sleep long enough to let the main thread cancel us - boost::xtime xt; - BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), - static_cast(boost::TIME_UTC)); - xt.sec += 3; - boost::thread::sleep(xt); - // This block will test the cancellation guard. If it // doesn't work, we'll be cancelled with out setting // the test_value to 999. + try { boost::cancellation_guard guard; - boost::thread::test_cancel(); + // Sleep long enough to let the main thread cancel us + boost::thread::sleep(xtime_get_future(3)); + } + catch (boost::thread_cancel& cancel) + { + test_value = 666; // indicates unexpected cancellation + throw; // Make sure to re-throw! } // This block tests the cancellation itself. If it @@ -77,6 +61,17 @@ namespace boost::thread& parent; }; + struct indirect_adapter + { + indirect_adapter(void (*func)()) : func(func) { } + void operator()() + { + boost::thread thrd(func); + thrd.join(); + } + void (*func)(); + }; + void comparison_thread(boost::thread& parent) { boost::thread thrd; @@ -87,11 +82,7 @@ namespace void test_sleep() { - boost::xtime xt; - BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), - static_cast(boost::TIME_UTC)); - xt.sec += 3; - + boost::xtime xt = xtime_get_future(3); boost::thread::sleep(xt); // Insure it's in a range instead of checking actual equality due to time @@ -103,14 +94,22 @@ void test_creation() { test_value = 0; boost::thread thrd(&simple_thread); - thrd.join(); + boost::thread::sleep(xtime_get_future(2)); BOOST_CHECK_EQUAL(test_value, 999); } +void test_join() +{ + test_value = 0; + boost::thread thrd = boost::thread(indirect_adapter(&simple_thread)); + boost::thread::sleep(xtime_get_future(2)); + BOOST_CHECK_EQUAL(test_value, 999); +} + void test_comparison() { boost::thread self; - BOOST_CHECK_EQUAL(self, boost::thread()); + BOOST_CHECK(self == boost::thread()); boost::thread thrd(thread_adapter(comparison_thread, self)); boost::thread thrd2 = thrd; @@ -126,6 +125,7 @@ void test_cancel() test_value = 0; boost::thread thrd(&cancel_thread); thrd.cancel(); + thrd.join(); BOOST_CHECK_EQUAL(test_value, 999); // only true if thread was cancelled } @@ -137,6 +137,8 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(test_sleep)); test->add(BOOST_TEST_CASE(test_creation)); test->add(BOOST_TEST_CASE(test_comparison)); + test->add(BOOST_TEST_CASE(test_join)); + test->add(BOOST_TEST_CASE(test_cancel)); return test; } diff --git a/test/utils.inl b/test/utils.inl index 6422c07e..bec27ae9 100644 --- a/test/utils.inl +++ b/test/utils.inl @@ -1,3 +1,6 @@ +#if !defined(BOOST_UTILS_INL_WEK01212003) +#define BOOST_UTILS_INL_WEK01212003 + #include namespace { @@ -9,29 +12,40 @@ typedef boost::int_fast64_t sec_type; #endif typedef boost::int_fast32_t nsec_type; -static void xtime_get(boost::xtime& xt, sec_type secs, nsec_type nsecs=0) +inline boost::xtime xtime_get_future(sec_type secs, nsec_type nsecs=0) +{ + boost::xtime xt; + BOOST_CHECK_EQUAL(boost::xtime_get(&xt, boost::TIME_UTC), + static_cast(boost::TIME_UTC)); + xt.sec += secs; + xt.nsec += nsecs; + return xt; +} + +inline void xtime_get(boost::xtime& xt, sec_type secs, nsec_type nsecs=0) { boost::xtime_get(&xt, boost::TIME_UTC); xt.sec += secs; xt.nsec += nsecs; } -static int xtime_cmp(const boost::xtime& xt1, const boost::xtime& xt2) +inline bool xtime_in_range(const boost::xtime& xt, sec_type less_secs, + sec_type greater_secs) { - int cmp = (int)(xt1.sec - xt2.sec); - if (cmp == 0) - cmp = (int)(xt1.nsec - xt2.nsec); - return cmp; + boost::xtime cur; + BOOST_CHECK_EQUAL(boost::xtime_get(&cur, boost::TIME_UTC), + static_cast(boost::TIME_UTC)); + + boost::xtime less = cur; + less.sec += less_secs; + + boost::xtime greater = cur; + greater.sec += greater_secs; + + return (boost::xtime_cmp(xt, less) >= 0) && + (boost::xtime_cmp(xt, greater) <= 0); } -static bool xtime_in_range(const boost::xtime& xt, sec_type min, sec_type max) -{ - boost::xtime xt_min, xt_max; - boost::xtime_get(&xt_min, boost::TIME_UTC); - xt_max = xt_min; - xt_min.sec += min; - xt_max.sec += max; - return (xtime_cmp(xt, xt_min) >= 0) && (xtime_cmp(xt, xt_max) <= 0); -} +} // namespace -} // namespace \ No newline at end of file +#endif