diff --git a/doc/changes.qbk b/doc/changes.qbk index 30c4a2c2..62a6630f 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -52,4 +52,6 @@ been moved to __thread_id__. * The broken `boost::read_write_mutex` has been replaced with __shared_mutex__. +* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms. + [endsect] diff --git a/include/boost/thread/win32/thread.hpp b/include/boost/thread/detail/thread.hpp similarity index 63% rename from include/boost/thread/win32/thread.hpp rename to include/boost/thread/detail/thread.hpp index ab881c9e..10810ef0 100644 --- a/include/boost/thread/win32/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -1,19 +1,16 @@ -#ifndef BOOST_THREAD_THREAD_WIN32_HPP -#define BOOST_THREAD_THREAD_WIN32_HPP +#ifndef BOOST_THREAD_THREAD_COMMON_HPP +#define BOOST_THREAD_THREAD_COMMON_HPP // 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 - -#include +// (C) Copyright 2007-8 Anthony Williams + #include #include #include -#include #include -#include -#include "thread_primitives.hpp" -#include "thread_heap_alloc.hpp" +#include +#include #include #include #include @@ -31,135 +28,6 @@ namespace boost { - class thread_interrupted - {}; - - namespace detail - { - struct thread_exit_callback_node; - struct tss_data_node; - - struct thread_data_base - { - long count; - detail::win32::handle_manager thread_handle; - detail::win32::handle_manager interruption_handle; - boost::detail::thread_exit_callback_node* thread_exit_callbacks; - boost::detail::tss_data_node* tss_data; - bool interruption_enabled; - unsigned id; - - thread_data_base(): - count(0),thread_handle(detail::win32::invalid_handle_value), - interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), - thread_exit_callbacks(0),tss_data(0), - interruption_enabled(true), - id(0) - {} - virtual ~thread_data_base() - {} - - friend void intrusive_ptr_add_ref(thread_data_base * p) - { - BOOST_INTERLOCKED_INCREMENT(&p->count); - } - - friend void intrusive_ptr_release(thread_data_base * p) - { - if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) - { - detail::heap_delete(p); - } - } - - void interrupt() - { - BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); - } - - - virtual void run()=0; - }; - - typedef boost::intrusive_ptr thread_data_ptr; - - struct timeout - { - unsigned long start; - uintmax_t milliseconds; - bool relative; - boost::system_time abs_time; - - static unsigned long const max_non_infinite_wait=0xfffffffe; - - timeout(uintmax_t milliseconds_): - start(win32::GetTickCount()), - milliseconds(milliseconds_), - relative(true), - abs_time(boost::get_system_time()) - {} - - timeout(boost::system_time const& abs_time_): - start(win32::GetTickCount()), - milliseconds(0), - relative(false), - abs_time(abs_time_) - {} - - struct remaining_time - { - bool more; - unsigned long milliseconds; - - remaining_time(uintmax_t remaining): - more(remaining>max_non_infinite_wait), - milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) - {} - }; - - remaining_time remaining_milliseconds() const - { - if(is_sentinel()) - { - return remaining_time(win32::infinite); - } - else if(relative) - { - unsigned long const now=win32::GetTickCount(); - unsigned long const elapsed=now-start; - return remaining_time((elapsed static inline detail::thread_data_ptr make_thread_info(F&& f) { - return detail::heap_new >(static_cast(f)); + return detail::thread_data_ptr(detail::heap_new >(static_cast(f))); } #else template static inline detail::thread_data_ptr make_thread_info(F f) { - return detail::heap_new >(f); + return detail::thread_data_ptr(detail::heap_new >(f)); } template static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t f) { - return detail::heap_new >(f); + return detail::thread_data_ptr(detail::heap_new >(f)); } #endif public: @@ -235,6 +101,24 @@ namespace boost { start_thread(); } + + thread(thread&& other) + { + thread_info.swap(other.thread_info); + } + + thread& operator=(thread&& other) + { + thread_info=other.thread_info; + other.thread_info.reset(); + return *this; + } + + thread&& move() + { + return static_cast(*this); + } + #else template explicit thread(F f): @@ -249,33 +133,99 @@ namespace boost { start_thread(); } + + thread(detail::thread_move_t x) + { + thread_info=x->thread_info; + x->thread_info.reset(); + } + + thread& operator=(detail::thread_move_t x) + { + thread new_thread(x); + swap(new_thread); + return *this; + } + + operator detail::thread_move_t() + { + return move(); + } + + detail::thread_move_t move() + { + detail::thread_move_t x(*this); + return x; + } + #endif template thread(F f,A1 a1): - thread_info(make_thread_info(boost::bind(f,a1))) + thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) { start_thread(); } template thread(F f,A1 a1,A2 a2): - thread_info(make_thread_info(boost::bind(f,a1,a2))) + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2))) { start_thread(); } + template thread(F f,A1 a1,A2 a2,A3 a3): - thread_info(make_thread_info(boost::bind(f,a1,a2,a3))) + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3))) { start_thread(); } - thread(detail::thread_move_t x); - thread& operator=(detail::thread_move_t x); - operator detail::thread_move_t(); - detail::thread_move_t move(); + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4))) + { + start_thread(); + } - void swap(thread& x); + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) + { + start_thread(); + } + + void swap(thread& x) + { + thread_info.swap(x.thread_info); + } class id; id get_id() const; @@ -294,25 +244,39 @@ namespace boost static unsigned hardware_concurrency(); - typedef detail::win32::handle native_handle_type; + typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; - static void yield(); - static void sleep(const system_time& xt); + static inline void yield() + { + this_thread::yield(); + } + + static inline void sleep(const system_time& xt) + { + this_thread::sleep(xt); + } // extensions void interrupt(); bool interruption_requested() const; }; +#ifdef BOOST_HAS_RVALUE_REFS + inline thread&& move(thread&& t) + { + return t; + } +#else inline detail::thread_move_t move(detail::thread_move_t t) { return t; } +#endif template struct thread::thread_data >: @@ -329,6 +293,22 @@ namespace boost f(); } }; + + template + struct thread::thread_data >: + detail::thread_data_base + { + F& f; + + thread_data(const boost::reference_wrapper f_): + f(f_) + {} + + void run() + { + f(); + } + }; namespace this_thread @@ -356,21 +336,13 @@ namespace boost thread::id BOOST_THREAD_DECL get_id(); - bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); - inline bool interruptible_wait(unsigned long milliseconds) - { - return interruptible_wait(detail::win32::invalid_handle_value,milliseconds); - } - void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled(); bool BOOST_THREAD_DECL interruption_requested(); - void BOOST_THREAD_DECL yield(); - template - void sleep(TimeDuration const& rel_time) + inline void sleep(xtime const& abs_time) { - interruptible_wait(static_cast(rel_time.total_milliseconds())); + sleep(system_time(abs_time)); } } @@ -386,7 +358,7 @@ namespace boost friend id this_thread::get_id(); public: id(): - thread_data(0) + thread_data() {} bool operator==(const id& y) const @@ -432,15 +404,6 @@ namespace boost return os<<"{Not-any-thread}"; } } - - void interrupt() - { - if(thread_data) - { - thread_data->interrupt(); - } - } - }; inline bool thread::operator==(const thread& other) const diff --git a/include/boost/thread/detail/thread_heap_alloc.hpp b/include/boost/thread/detail/thread_heap_alloc.hpp new file mode 100644 index 00000000..2f9bfd5c --- /dev/null +++ b/include/boost/thread/detail/thread_heap_alloc.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP +#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP + +// thread_heap_alloc.hpp +// +// (C) Copyright 2008 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 + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + + +#endif diff --git a/include/boost/thread/exceptions.hpp b/include/boost/thread/exceptions.hpp index e3ff59a5..e46b30d2 100644 --- a/include/boost/thread/exceptions.hpp +++ b/include/boost/thread/exceptions.hpp @@ -19,7 +19,11 @@ #include #include -namespace boost { +namespace boost +{ + + class BOOST_THREAD_DECL thread_interrupted + {}; class BOOST_THREAD_DECL thread_exception : public std::exception { diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index e2a9e6eb..dee1bdf7 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -625,11 +625,19 @@ namespace boost using base::try_lock; using base::unlock; using base::owns_lock; - using base::operator!; using base::mutex; using base::release; + + bool operator!() const + { + return !this->owns_lock(); + } + typedef typename base::bool_type bool_type; - using base::operator bool_type; + operator bool_type() const + { + return static_cast(*this); + } }; template diff --git a/include/boost/thread/pthread/thread.hpp b/include/boost/thread/pthread/thread.hpp deleted file mode 100644 index cdfade0e..00000000 --- a/include/boost/thread/pthread/thread.hpp +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef BOOST_THREAD_THREAD_PTHREAD_HPP -#define BOOST_THREAD_THREAD_PTHREAD_HPP -// Copyright (C) 2001-2003 -// William E. Kempf -// 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 - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "thread_data.hpp" -#include -#include - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4251) -#endif - -namespace boost -{ - class thread; - - namespace detail - { - class thread_id; - } - - namespace this_thread - { - BOOST_THREAD_DECL detail::thread_id get_id(); - } - - namespace detail - { - class thread_id - { - private: - detail::thread_data_ptr thread_data; - - thread_id(detail::thread_data_ptr thread_data_): - thread_data(thread_data_) - {} - friend class boost::thread; - friend thread_id this_thread::get_id(); - public: - thread_id(): - thread_data() - {} - - bool operator==(const thread_id& y) const - { - return thread_data==y.thread_data; - } - - bool operator!=(const thread_id& y) const - { - return thread_data!=y.thread_data; - } - - bool operator<(const thread_id& y) const - { - return thread_data(const thread_id& y) const - { - return y.thread_data=(const thread_id& y) const - { - return !(thread_data - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const thread_id& x) - { - if(x.thread_data) - { - return os< - struct thread_data: - detail::thread_data_base - { - F f; - - thread_data(F f_): - f(f_) - {} - thread_data(detail::thread_move_t f_): - f(f_) - {} - - void run() - { - f(); - } - }; - - mutable boost::mutex thread_info_mutex; - detail::thread_data_ptr thread_info; - - void start_thread(); - - explicit thread(detail::thread_data_ptr data); - - detail::thread_data_ptr get_thread_info() const; - - template - static inline detail::thread_data_ptr make_thread_info(F f) - { - return detail::thread_data_ptr(new thread_data(f)); - } - - public: - thread(); - ~thread(); - - template - explicit thread(F f): - thread_info(make_thread_info(f)) - { - start_thread(); - } - template - thread(detail::thread_move_t f): - thread_info(make_thread_info(f)) - { - start_thread(); - } - - template - thread(F f,A1 a1): - thread_info(make_thread_info(boost::bind(f,a1))) - { - start_thread(); - } - template - thread(F f,A1 a1,A2 a2): - thread_info(make_thread_info(boost::bind(f,a1,a2))) - { - start_thread(); - } - template - thread(F f,A1 a1,A2 a2,A3 a3): - thread_info(make_thread_info(boost::bind(f,a1,a2,a3))) - { - start_thread(); - } - - thread(detail::thread_move_t x); - thread& operator=(detail::thread_move_t x); - operator detail::thread_move_t(); - detail::thread_move_t move(); - - void swap(thread& x); - - typedef detail::thread_id id; - - id get_id() const; - - bool joinable() const; - void join(); - bool timed_join(const system_time& wait_until); - - template - inline bool timed_join(TimeDuration const& rel_time) - { - return timed_join(get_system_time()+rel_time); - } - void detach(); - - static unsigned hardware_concurrency(); - - // backwards compatibility - bool operator==(const thread& other) const; - bool operator!=(const thread& other) const; - - static void sleep(const system_time& xt); - static void yield(); - - typedef pthread_t native_handle_type; - native_handle_type native_handle(); - - // extensions - void interrupt(); - bool interruption_requested() const; - }; - - inline detail::thread_move_t move(detail::thread_move_t t) - { - return t; - } - - template - struct thread::thread_data >: - detail::thread_data_base - { - F& f; - - thread_data(boost::reference_wrapper f_): - f(f_) - {} - - void run() - { - f(); - } - }; - - namespace this_thread - { - class BOOST_THREAD_DECL disable_interruption - { - disable_interruption(const disable_interruption&); - disable_interruption& operator=(const disable_interruption&); - - bool interruption_was_enabled; - friend class restore_interruption; - public: - disable_interruption(); - ~disable_interruption(); - }; - - class BOOST_THREAD_DECL restore_interruption - { - restore_interruption(const restore_interruption&); - restore_interruption& operator=(const restore_interruption&); - public: - explicit restore_interruption(disable_interruption& d); - ~restore_interruption(); - }; - - BOOST_THREAD_DECL thread::id get_id(); - - BOOST_THREAD_DECL void interruption_point(); - BOOST_THREAD_DECL bool interruption_enabled(); - BOOST_THREAD_DECL bool interruption_requested(); - - inline void yield() - { - thread::yield(); - } - - template - inline void sleep(TimeDuration const& rel_time) - { - thread::sleep(get_system_time()+rel_time); - } - } - - namespace detail - { - struct thread_exit_function_base - { - virtual ~thread_exit_function_base() - {} - virtual void operator()() const=0; - }; - - template - struct thread_exit_function: - thread_exit_function_base - { - F f; - - thread_exit_function(F f_): - f(f_) - {} - - void operator()() const - { - f(); - } - }; - - BOOST_THREAD_DECL void add_thread_exit_function(thread_exit_function_base*); - } - - namespace this_thread - { - template - inline void at_thread_exit(F f) - { - detail::thread_exit_function_base* const thread_exit_func=new detail::thread_exit_function(f); - detail::add_thread_exit_function(thread_exit_func); - } - } - - class BOOST_THREAD_DECL thread_group - { - public: - thread_group(); - ~thread_group(); - - thread* create_thread(const function0& threadfunc); - void add_thread(thread* thrd); - void remove_thread(thread* thrd); - void join_all(); - void interrupt_all(); - size_t size() const; - - private: - thread_group(thread_group&); - void operator=(thread_group&); - - std::list m_threads; - mutex m_mutex; - }; -} // namespace boost - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - - -#endif diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 52ca40e5..2532b854 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -6,6 +6,7 @@ // (C) Copyright 2007 Anthony Williams #include +#include #include #include #include @@ -15,9 +16,8 @@ namespace boost { - class thread_interrupted - {}; - + class thread; + namespace detail { struct thread_exit_callback_node; @@ -26,7 +26,7 @@ namespace boost struct thread_data_base; typedef boost::shared_ptr thread_data_ptr; - struct thread_data_base: + struct BOOST_THREAD_DECL thread_data_base: enable_shared_from_this { thread_data_ptr self; @@ -51,8 +51,9 @@ namespace boost interrupt_requested(false), current_cond(0) {} - virtual ~thread_data_base() - {} + virtual ~thread_data_base(); + + typedef pthread_t native_handle_type; virtual void run()=0; }; @@ -95,6 +96,19 @@ namespace boost } }; } + + namespace this_thread + { + void BOOST_THREAD_DECL yield(); + + void BOOST_THREAD_DECL sleep(system_time const& abs_time); + + template + inline void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(get_system_time()+rel_time); + } + } } diff --git a/include/boost/thread/pthread/thread_heap_alloc.hpp b/include/boost/thread/pthread/thread_heap_alloc.hpp new file mode 100644 index 00000000..338092da --- /dev/null +++ b/include/boost/thread/pthread/thread_heap_alloc.hpp @@ -0,0 +1,239 @@ +// 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 2008 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP +#define THREAD_HEAP_ALLOC_PTHREAD_HPP + +namespace boost +{ + namespace detail + { + template + inline T* heap_new() + { + return new T(); + } + +#ifdef BOOST_HAS_RVALUE_REFS + template + inline T* heap_new(A1&& a1) + { + return new T(static_cast(a1)); + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + return new T(static_cast(a1),static_cast(a2)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + } +#else + template + inline T* heap_new_impl(A1 a1) + { + return new T(a1); + } + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + return new T(a1,a2); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + return new T(a1,a2,a3); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + return new T(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif + template + inline void heap_delete(T* data) + { + delete data; + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + + +#endif diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index a1714981..6146132b 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -3,7 +3,7 @@ // thread.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -12,11 +12,14 @@ #include #if defined(BOOST_THREAD_PLATFORM_WIN32) -#include +#include #elif defined(BOOST_THREAD_PLATFORM_PTHREAD) -#include +#include #else #error "Boost threads unavailable on this platform" #endif +#include + + #endif diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index c74d3cc4..0581f459 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -46,21 +46,11 @@ namespace boost notified=true; detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); } - - friend void intrusive_ptr_add_ref(list_entry * p) - { - BOOST_INTERLOCKED_INCREMENT(&p->references); - } - - friend void intrusive_ptr_release(list_entry * p) - { - if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) - { - delete p; - } - } }; + friend void intrusive_ptr_add_ref(list_entry * p); + friend void intrusive_ptr_release(list_entry * p); + typedef boost::intrusive_ptr entry_ptr; typedef std::vector generation_list; @@ -206,7 +196,7 @@ namespace boost { if(detail::interlocked_read_acquire(&total_count)) { - boost::mutex::scoped_lock internal_lock(internal_mutex); + boost::lock_guard internal_lock(internal_mutex); if(!total_count) { return; @@ -227,7 +217,7 @@ namespace boost { if(detail::interlocked_read_acquire(&total_count)) { - boost::mutex::scoped_lock internal_lock(internal_mutex); + boost::lock_guard internal_lock(internal_mutex); if(!total_count) { return; @@ -239,11 +229,26 @@ namespace boost { (*it)->release(detail::interlocked_read_acquire(&(*it)->waiters)); } + generations.clear(); wake_sem=detail::win32::handle(0); } } }; + inline void intrusive_ptr_add_ref(basic_condition_variable::list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_condition_variable::list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + + } class condition_variable: diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp new file mode 100644 index 00000000..604569a5 --- /dev/null +++ b/include/boost/thread/win32/thread_data.hpp @@ -0,0 +1,175 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +// 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 2008 Anthony Williams + +#include +#include +#include +#include "thread_primitives.hpp" +#include "thread_heap_alloc.hpp" + +namespace boost +{ + namespace detail + { + struct thread_exit_callback_node; + struct tss_data_node; + + struct thread_data_base; + void intrusive_ptr_add_ref(thread_data_base * p); + void intrusive_ptr_release(thread_data_base * p); + + struct thread_data_base + { + long count; + detail::win32::handle_manager thread_handle; + detail::win32::handle_manager interruption_handle; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + boost::detail::tss_data_node* tss_data; + bool interruption_enabled; + unsigned id; + + thread_data_base(): + count(0),thread_handle(detail::win32::invalid_handle_value), + interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), + thread_exit_callbacks(0),tss_data(0), + interruption_enabled(true), + id(0) + {} + virtual ~thread_data_base() + {} + + friend void intrusive_ptr_add_ref(thread_data_base * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->count); + } + + friend void intrusive_ptr_release(thread_data_base * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) + { + detail::heap_delete(p); + } + } + + void interrupt() + { + BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); + } + + typedef detail::win32::handle native_handle_type; + + virtual void run()=0; + }; + + typedef boost::intrusive_ptr thread_data_ptr; + + struct timeout + { + unsigned long start; + uintmax_t milliseconds; + bool relative; + boost::system_time abs_time; + + static unsigned long const max_non_infinite_wait=0xfffffffe; + + timeout(uintmax_t milliseconds_): + start(win32::GetTickCount()), + milliseconds(milliseconds_), + relative(true), + abs_time(boost::get_system_time()) + {} + + timeout(boost::system_time const& abs_time_): + start(win32::GetTickCount()), + milliseconds(0), + relative(false), + abs_time(abs_time_) + {} + + struct remaining_time + { + bool more; + unsigned long milliseconds; + + remaining_time(uintmax_t remaining): + more(remaining>max_non_infinite_wait), + milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) + {} + }; + + remaining_time remaining_milliseconds() const + { + if(is_sentinel()) + { + return remaining_time(win32::infinite); + } + else if(relative) + { + unsigned long const now=win32::GetTickCount(); + unsigned long const elapsed=now-start; + return remaining_time((elapsed + inline void sleep(TimeDuration const& rel_time) + { + interruptible_wait(static_cast(rel_time.total_milliseconds())); + } + inline void sleep(system_time const& abs_time) + { + interruptible_wait(abs_time); + } + } + +} + + +#endif diff --git a/include/boost/thread/win32/thread_heap_alloc.hpp b/include/boost/thread/win32/thread_heap_alloc.hpp index b419f57e..a669654d 100644 --- a/include/boost/thread/win32/thread_heap_alloc.hpp +++ b/include/boost/thread/win32/thread_heap_alloc.hpp @@ -69,7 +69,7 @@ namespace boost } template - T* heap_new() + inline T* heap_new() { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -86,7 +86,7 @@ namespace boost #ifdef BOOST_HAS_RVALUE_REFS template - T* heap_new(A1&& a1) + inline T* heap_new(A1&& a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -100,9 +100,56 @@ namespace boost throw; } } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + try + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + return data; + } + catch(...) + { + free_raw_heap_memory(heap_memory); + throw; + } + } #else template - T* heap_new(A1 a1) + inline T* heap_new_impl(A1 a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -116,9 +163,9 @@ namespace boost throw; } } -#endif + template - T* heap_new(A1 a1,A2 a2) + inline T* heap_new_impl(A1 a1,A2 a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -134,7 +181,7 @@ namespace boost } template - T* heap_new(A1 a1,A2 a2,A3 a3) + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -148,9 +195,9 @@ namespace boost throw; } } - + template - T* heap_new(A1 a1,A2 a2,A3 a3,A4 a4) + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); try @@ -164,9 +211,168 @@ namespace boost throw; } } + + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif template - void heap_delete(T* data) + inline void heap_delete(T* data) { data->~T(); free_raw_heap_memory(data); diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index 3109f142..372f262d 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -279,9 +279,14 @@ namespace boost } #if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) -#if MSC_VER>=1400 +#if _MSC_VER>=1400 +#if _MSC_VER==1400 extern "C" unsigned char _interlockedbittestandset(long *a,long b); extern "C" unsigned char _interlockedbittestandreset(long *a,long b); +#else +extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); +extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); +#endif #pragma intrinsic(_interlockedbittestandset) #pragma intrinsic(_interlockedbittestandreset) @@ -294,12 +299,12 @@ namespace boost { inline bool interlocked_bit_test_and_set(long* x,long bit) { - return _interlockedbittestandset(x,bit); + return _interlockedbittestandset(x,bit)!=0; } inline bool interlocked_bit_test_and_reset(long* x,long bit) { - return _interlockedbittestandreset(x,bit); + return _interlockedbittestandreset(x,bit)!=0; } } diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 3cd6a86a..89fbf928 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -28,6 +28,9 @@ namespace boost { namespace detail { + thread_data_base::~thread_data_base() + {} + struct thread_exit_callback_node { boost::detail::thread_exit_function_base* func; @@ -119,7 +122,7 @@ namespace boost { void* thread_proxy(void* param) { - boost::shared_ptr thread_info = static_cast(param)->self; + boost::detail::thread_data_ptr thread_info = static_cast(param)->self; thread_info->self.reset(); detail::set_current_thread_data(thread_info.get()); try @@ -153,6 +156,10 @@ namespace boost void run() {} + + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); }; detail::thread_data_base* make_external_thread_data() @@ -196,47 +203,6 @@ namespace boost detach(); } - thread::thread(detail::thread_move_t x) - { - lock_guard lock(x->thread_info_mutex); - thread_info=x->thread_info; - x->thread_info.reset(); - } - - thread& thread::operator=(detail::thread_move_t x) - { - thread new_thread(x); - swap(new_thread); - return *this; - } - - thread::operator detail::thread_move_t() - { - return move(); - } - - detail::thread_move_t thread::move() - { - detail::thread_move_t x(*this); - return x; - } - - void thread::swap(thread& x) - { - thread_info.swap(x.thread_info); - } - - - bool thread::operator==(const thread& other) const - { - return get_id()==other.get_id(); - } - - bool thread::operator!=(const thread& other) const - { - return !operator==(other); - } - detail::thread_data_ptr thread::get_thread_info() const { lock_guard l(thread_info_mutex); @@ -361,57 +327,61 @@ namespace boost } } - void thread::sleep(const system_time& st) + namespace this_thread { - detail::thread_data_base* const thread_info=detail::get_current_thread_data(); - if(thread_info) + void sleep(const system_time& st) { - unique_lock lk(thread_info->sleep_mutex); - while(thread_info->sleep_condition.timed_wait(lk,st)); - } - else - { - xtime const xt=get_xtime(st); - - for (int foo=0; foo < 5; ++foo) + detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + + if(thread_info) { + unique_lock lk(thread_info->sleep_mutex); + while(thread_info->sleep_condition.timed_wait(lk,st)); + } + else + { + xtime const xt=get_xtime(st); + + for (int foo=0; foo < 5; ++foo) + { # if defined(BOOST_HAS_PTHREAD_DELAY_NP) - timespec ts; - to_timespec_duration(xt, ts); - BOOST_VERIFY(!pthread_delay_np(&ts)); + timespec ts; + to_timespec_duration(xt, ts); + BOOST_VERIFY(!pthread_delay_np(&ts)); # elif defined(BOOST_HAS_NANOSLEEP) - timespec ts; - to_timespec_duration(xt, ts); + timespec ts; + to_timespec_duration(xt, ts); - // nanosleep takes a timespec that is an offset, not - // an absolute time. - nanosleep(&ts, 0); + // nanosleep takes a timespec that is an offset, not + // an absolute time. + nanosleep(&ts, 0); # else - mutex mx; - mutex::scoped_lock lock(mx); - condition cond; - cond.timed_wait(lock, xt); + mutex mx; + mutex::scoped_lock lock(mx); + condition cond; + cond.timed_wait(lock, xt); # endif - xtime cur; - xtime_get(&cur, TIME_UTC); - if (xtime_cmp(xt, cur) <= 0) - return; + xtime cur; + xtime_get(&cur, TIME_UTC); + if (xtime_cmp(xt, cur) <= 0) + return; + } } } - } - void thread::yield() - { + void yield() + { # if defined(BOOST_HAS_SCHED_YIELD) - BOOST_VERIFY(!sched_yield()); + BOOST_VERIFY(!sched_yield()); # elif defined(BOOST_HAS_PTHREAD_YIELD) - BOOST_VERIFY(!pthread_yield()); + BOOST_VERIFY(!pthread_yield()); # else - xtime xt; - xtime_get(&xt, TIME_UTC); - sleep(xt); + xtime xt; + xtime_get(&xt, TIME_UTC); + sleep(xt); # endif + } } unsigned thread::hardware_concurrency() @@ -622,85 +592,85 @@ namespace boost } } - thread_group::thread_group() - { - } +// thread_group::thread_group() +// { +// } - thread_group::~thread_group() - { - // We shouldn't have to scoped_lock here, since referencing this object - // from another thread while we're deleting it in the current thread is - // going to lead to undefined behavior any way. - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - delete (*it); - } - } +// thread_group::~thread_group() +// { +// // We shouldn't have to scoped_lock here, since referencing this object +// // from another thread while we're deleting it in the current thread is +// // going to lead to undefined behavior any way. +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// delete (*it); +// } +// } - thread* thread_group::create_thread(const function0& threadfunc) - { - // No scoped_lock required here since the only "shared data" that's - // modified here occurs inside add_thread which does scoped_lock. - std::auto_ptr thrd(new thread(threadfunc)); - add_thread(thrd.get()); - return thrd.release(); - } +// thread* thread_group::create_thread(const function0& threadfunc) +// { +// // No scoped_lock required here since the only "shared data" that's +// // modified here occurs inside add_thread which does scoped_lock. +// std::auto_ptr thrd(new thread(threadfunc)); +// add_thread(thrd.get()); +// return thrd.release(); +// } - void thread_group::add_thread(thread* thrd) - { - mutex::scoped_lock scoped_lock(m_mutex); +// void thread_group::add_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); - // For now we'll simply ignore requests to add a thread object multiple - // times. Should we consider this an error and either throw or return an - // error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - BOOST_ASSERT(it == m_threads.end()); - if (it == m_threads.end()) - m_threads.push_back(thrd); - } +// // For now we'll simply ignore requests to add a thread object multiple +// // times. Should we consider this an error and either throw or return an +// // error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it == m_threads.end()); +// if (it == m_threads.end()) +// m_threads.push_back(thrd); +// } - void thread_group::remove_thread(thread* thrd) - { - mutex::scoped_lock scoped_lock(m_mutex); +// void thread_group::remove_thread(thread* thrd) +// { +// mutex::scoped_lock scoped_lock(m_mutex); - // For now we'll simply ignore requests to remove a thread object that's - // not in the group. Should we consider this an error and either throw or - // return an error value? - std::list::iterator it = std::find(m_threads.begin(), - m_threads.end(), thrd); - BOOST_ASSERT(it != m_threads.end()); - if (it != m_threads.end()) - m_threads.erase(it); - } +// // For now we'll simply ignore requests to remove a thread object that's +// // not in the group. Should we consider this an error and either throw or +// // return an error value? +// std::list::iterator it = std::find(m_threads.begin(), +// m_threads.end(), thrd); +// BOOST_ASSERT(it != m_threads.end()); +// if (it != m_threads.end()) +// m_threads.erase(it); +// } - void thread_group::join_all() - { - mutex::scoped_lock scoped_lock(m_mutex); - for (std::list::iterator it = m_threads.begin(); - it != m_threads.end(); ++it) - { - (*it)->join(); - } - } +// void thread_group::join_all() +// { +// mutex::scoped_lock scoped_lock(m_mutex); +// for (std::list::iterator it = m_threads.begin(); +// it != m_threads.end(); ++it) +// { +// (*it)->join(); +// } +// } - void thread_group::interrupt_all() - { - boost::lock_guard guard(m_mutex); +// void thread_group::interrupt_all() +// { +// boost::lock_guard guard(m_mutex); - for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); - it!=end; - ++it) - { - (*it)->interrupt(); - } - } +// for(std::list::iterator it=m_threads.begin(),end=m_threads.end(); +// it!=end; +// ++it) +// { +// (*it)->interrupt(); +// } +// } - size_t thread_group::size() const - { - return m_threads.size(); - } +// size_t thread_group::size() const +// { +// return m_threads.size(); +// } } diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index 40c3588b..e54b847d 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -81,25 +81,6 @@ namespace boost } - void thread::yield() - { - this_thread::yield(); - } - - void thread::sleep(const system_time& target) - { - system_time const now(get_system_time()); - - if(target<=now) - { - this_thread::yield(); - } - else - { - this_thread::sleep(target-now); - } - } - namespace detail { struct thread_exit_callback_node @@ -164,26 +145,24 @@ namespace boost set_current_thread_data(0); } - } - - - unsigned __stdcall thread::thread_start_function(void* param) - { - detail::thread_data_base* const thread_info(reinterpret_cast(param)); - set_current_thread_data(thread_info); - try + unsigned __stdcall thread_start_function(void* param) { - thread_info->run(); + detail::thread_data_base* const thread_info(reinterpret_cast(param)); + set_current_thread_data(thread_info); + try + { + thread_info->run(); + } + catch(thread_interrupted const&) + { + } + catch(...) + { + std::terminate(); + } + run_thread_exit_callbacks(); + return 0; } - catch(thread_interrupted const&) - { - } - catch(...) - { - std::terminate(); - } - run_thread_exit_callbacks(); - return 0; } thread::thread() @@ -247,36 +226,6 @@ namespace boost detach(); } - thread::thread(detail::thread_move_t x) - { - lock_guard lock(x->thread_info_mutex); - thread_info=x->thread_info; - x->thread_info=0; - } - - thread& thread::operator=(detail::thread_move_t x) - { - thread new_thread(x); - swap(new_thread); - return *this; - } - - thread::operator detail::thread_move_t() - { - return move(); - } - - detail::thread_move_t thread::move() - { - detail::thread_move_t x(*this); - return x; - } - - void thread::swap(thread& x) - { - thread_info.swap(x.thread_info); - } - thread::id thread::get_id() const { return thread::id(get_thread_info()); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 405e83bc..a6a769cb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -22,16 +22,16 @@ project : requirements /boost/test//boost_unit_test_framework/static multi ; - + rule thread-run ( sources ) { return - [ run $(sources) ../build//boost_thread ] - [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/static - : : : : $(sources[1]:B)_lib ] - ; + [ run $(sources) ../build//boost_thread ] + [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/static + : : : : $(sources[1]:B)_lib ] + ; } - + { test-suite "threads" : [ thread-run test_thread.cpp ] @@ -39,6 +39,7 @@ rule thread-run ( sources ) [ thread-run test_hardware_concurrency.cpp ] [ thread-run test_thread_move.cpp ] [ thread-run test_thread_launching.cpp ] + [ thread-run test_thread_mf.cpp ] [ thread-run test_move_function.cpp ] [ thread-run test_mutex.cpp ] [ thread-run test_condition_notify_one.cpp ] @@ -48,11 +49,12 @@ rule thread-run ( sources ) [ thread-run test_tss.cpp ] [ thread-run test_once.cpp ] [ thread-run test_xtime.cpp ] - [ thread-run test_barrier.cpp ] + [ thread-run test_barrier.cpp ] [ thread-run test_shared_mutex.cpp ] [ thread-run test_shared_mutex_part_2.cpp ] [ thread-run test_shared_mutex_timed_locks.cpp ] [ thread-run test_lock_concept.cpp ] + [ thread-run test_generic_locks.cpp ] [ compile-fail no_implicit_move_from_lvalue_thread.cpp ] [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ] ; diff --git a/test/test_generic_locks.cpp b/test/test_generic_locks.cpp new file mode 100644 index 00000000..b0023bab --- /dev/null +++ b/test/test_generic_locks.cpp @@ -0,0 +1,137 @@ +// (C) Copyright 2008 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 +#include +#include +#include +#include + +void test_lock_two_uncontended() +{ + boost::mutex m1,m2; + + boost::mutex::scoped_lock l1(m1,boost::defer_lock), + l2(m2,boost::defer_lock); + + BOOST_CHECK(!l1.owns_lock()); + BOOST_CHECK(!l2.owns_lock()); + + boost::lock(l1,l2); + + BOOST_CHECK(l1.owns_lock()); + BOOST_CHECK(l2.owns_lock()); +} + +struct wait_data +{ + boost::mutex m; + bool flag; + boost::condition_variable cond; + + wait_data(): + flag(false) + {} + + void wait() + { + boost::mutex::scoped_lock l(m); + while(!flag) + { + cond.wait(l); + } + } + + template + bool timed_wait(Duration d) + { + boost::system_time const target=boost::get_system_time()+d; + + boost::mutex::scoped_lock l(m); + while(!flag) + { + if(!cond.timed_wait(l,target)) + { + return flag; + } + } + return true; + } + + void signal() + { + boost::mutex::scoped_lock l(m); + flag=true; + cond.notify_all(); + } +}; + + +void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit) +{ + boost::lock_guard l1(*m1); + boost::this_thread::sleep(boost::posix_time::milliseconds(500)); + boost::lock_guard l2(*m2); + locked->signal(); + quit->wait(); +} + +void lock_pair(boost::mutex* m1,boost::mutex* m2) +{ + boost::lock(*m1,*m2); + boost::mutex::scoped_lock l1(*m1,boost::adopt_lock), + l2(*m2,boost::adopt_lock); +} + +void test_lock_two_other_thread_locks_in_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m1,&m2); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + +void test_lock_two_other_thread_locks_in_opposite_order() +{ + boost::mutex m1,m2; + wait_data locked; + wait_data release; + + boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release); + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); + + boost::thread t2(lock_pair,&m2,&m1); + BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1))); + + release.signal(); + + BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1))); + + t.join(); +} + + +boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) +{ + boost::unit_test_framework::test_suite* test = + BOOST_TEST_SUITE("Boost.Threads: generic locks test suite"); + + test->add(BOOST_TEST_CASE(&test_lock_two_uncontended)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order)); + test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order)); + + return test; +} diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp index 61e08b77..6400ada8 100644 --- a/test/test_move_function.cpp +++ b/test/test_move_function.cpp @@ -80,7 +80,7 @@ void test_unique_lock_move_from_rvalue_on_construction() BOOST_CHECK(l.mutex()==&m); } -namespace user +namespace user_test_ns { template T move(T& t) @@ -103,9 +103,9 @@ namespace user void test_move_for_user_defined_type_unaffected() { - user::nc src; - user::nc dest=move(src); - BOOST_CHECK(user::move_called); + user_test_ns::nc src; + user_test_ns::nc dest=move(src); + BOOST_CHECK(user_test_ns::move_called); } boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) diff --git a/test/test_thread_launching.cpp b/test/test_thread_launching.cpp index 0e03d69d..24a646f0 100644 --- a/test/test_thread_launching.cpp +++ b/test/test_thread_launching.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2007 Anthony Williams +// 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) @@ -23,6 +23,20 @@ void test_thread_function_no_arguments() BOOST_CHECK(normal_function_called); } +int nfoa_res=0; + +void normal_function_one_arg(int i) +{ + nfoa_res=i; +} + +void test_thread_function_one_argument() +{ + boost::thread function(normal_function_one_arg,42); + function.join(); + BOOST_CHECK_EQUAL(42,nfoa_res); +} + struct callable_no_args { static bool called; @@ -82,7 +96,8 @@ int callable_one_arg::called_arg=0; void test_thread_callable_object_one_argument() { - boost::thread callable(callable_one_arg(),42); + callable_one_arg func; + boost::thread callable(func,42); callable.join(); BOOST_CHECK(callable_one_arg::called); BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42); @@ -150,6 +165,47 @@ void test_thread_callable_object_multiple_arguments() BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg2,dbl); } +struct X +{ + bool function_called; + int arg_value; + + X(): + function_called(false), + arg_value(0) + {} + + + void f0() + { + function_called=true; + } + + void f1(int i) + { + arg_value=i; + } + +}; + +void test_thread_member_function_no_arguments() +{ + X x; + + boost::thread function(&X::f0,&x); + function.join(); + BOOST_CHECK(x.function_called); +} + + +void test_thread_member_function_one_argument() +{ + X x; + boost::thread function(&X::f1,&x,42); + function.join(); + BOOST_CHECK_EQUAL(42,x.arg_value); +} + boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { @@ -157,9 +213,12 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) BOOST_TEST_SUITE("Boost.Threads: thread launching test suite"); test->add(BOOST_TEST_CASE(test_thread_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_function_one_argument)); test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments)); test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments)); test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument)); test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments)); + test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument)); return test; } diff --git a/test/test_thread_mf.cpp b/test/test_thread_mf.cpp new file mode 100644 index 00000000..fa1f8a9e --- /dev/null +++ b/test/test_thread_mf.cpp @@ -0,0 +1,136 @@ +// +// Copyright (C) 2008 Peter Dimov +// +// 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 +#include + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + int f0() { f1(17); return 0; } + int g0() const { g1(17); return 0; } + + int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; } + int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; } + + int f2(int a1, int a2) { f1(a1); f1(a2); return 0; } + int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; } + + int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; } + int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; } + + int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; } + int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; } + + int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; } + int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; } + + int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; } + int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; } + + int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; } + int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; } + + int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; } + int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; } +}; + +int main() +{ + using namespace boost; + + X x; + + // 0 + + thread( &X::f0, &x ).join(); + thread( &X::f0, ref(x) ).join(); + + thread( &X::g0, &x ).join(); + thread( &X::g0, x ).join(); + thread( &X::g0, ref(x) ).join(); + + // 1 + + thread( &X::f1, &x, 1 ).join(); + thread( &X::f1, ref(x), 1 ).join(); + + thread( &X::g1, &x, 1 ).join(); + thread( &X::g1, x, 1 ).join(); + thread( &X::g1, ref(x), 1 ).join(); + + // 2 + + thread( &X::f2, &x, 1, 2 ).join(); + thread( &X::f2, ref(x), 1, 2 ).join(); + + thread( &X::g2, &x, 1, 2 ).join(); + thread( &X::g2, x, 1, 2 ).join(); + thread( &X::g2, ref(x), 1, 2 ).join(); + + // 3 + + thread( &X::f3, &x, 1, 2, 3 ).join(); + thread( &X::f3, ref(x), 1, 2, 3 ).join(); + + thread( &X::g3, &x, 1, 2, 3 ).join(); + thread( &X::g3, x, 1, 2, 3 ).join(); + thread( &X::g3, ref(x), 1, 2, 3 ).join(); + + // 4 + + thread( &X::f4, &x, 1, 2, 3, 4 ).join(); + thread( &X::f4, ref(x), 1, 2, 3, 4 ).join(); + + thread( &X::g4, &x, 1, 2, 3, 4 ).join(); + thread( &X::g4, x, 1, 2, 3, 4 ).join(); + thread( &X::g4, ref(x), 1, 2, 3, 4 ).join(); + + // 5 + + thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join(); + thread( &X::f5, ref(x), 1, 2, 3, 4, 5 ).join(); + + thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join(); + thread( &X::g5, x, 1, 2, 3, 4, 5 ).join(); + thread( &X::g5, ref(x), 1, 2, 3, 4, 5 ).join(); + + // 6 + + thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::f6, ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join(); + thread( &X::g6, ref(x), 1, 2, 3, 4, 5, 6 ).join(); + + // 7 + + thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::f7, ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join(); + thread( &X::g7, ref(x), 1, 2, 3, 4, 5, 6, 7).join(); + + // 8 + + thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::f8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + thread( &X::g8, ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join(); + + BOOST_TEST( x.hash == 23558 ); + + return report_errors(); +}