diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index b38e9d18..dbd01187 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -43,6 +43,7 @@ project boost/thread shared:BOOST_THREAD_BUILD_DLL=1 -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag @$(__name__).tag + gcc:-Wno-long-long : default-build multi ; diff --git a/doc/thread_ref.qbk b/doc/thread_ref.qbk index d5225221..9a3b5640 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -219,6 +219,7 @@ __thread_id__ yield a total order for every non-equal thread ID. }; void swap(thread& lhs,thread& rhs); + detail::thread_move_t move(detail::thread_move_t t); [section:default_constructor Default Constructor] @@ -234,6 +235,40 @@ __thread_id__ yield a total order for every non-equal thread ID. [endsect] +[section:move_constructor Move Constructor] + + thread(detail::thread_move_t other); + +[variablelist + +[[Effects:] [Transfers ownership of the thread managed by `other` (if any) to the newly constructed __thread__ instance.]] + +[[Postconditions:] [`other->get_id()==thread::id()`]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:move_assignment Move assignment operator] + + thread& operator=(detail::thread_move_t other); + +[variablelist + +[[Effects:] [Transfers ownership of the thread managed by `other` (if +any) to `*this`. If there was a thread previously associated with +`*this` then that thread is detached.]] + +[[Postconditions:] [`other->get_id()==thread::id()`]] + +[[Throws:] [Nothing]] + +] + +[endsect] + [section:callable_constructor Thread Constructor] template @@ -521,6 +556,26 @@ value as `this->get_id()` prior to the call.]] [endsect] +[section:non_member_move Non-member function `move()`] + + #include + + detail::thread_move_t move(detail::thread_move_t t) + +[variablelist + +[[Returns:] [`t`.]] + +] + +Enables moving thread objects. e.g. + + extern void some_func(); + boost::thread t(some_func); + boost::thread t2(boost::move(t)); // transfer thread from t to t2 + +[endsect] + [section:id Class `boost::thread::id`] @@ -756,11 +811,14 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if ` { template void sleep(TimeDuration const& rel_time); + void sleep(system_time const& abs_time) } [variablelist -[[Effects:] [Suspends the current thread until the specified time has elapsed.]] +[[Effects:] [Suspends the current thread until the time period +specified by `rel_time` has elapsed or the time point specified by +`abs_time` has been reached.]] [[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted.]] diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index 7661507f..4015a6c7 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -19,8 +19,14 @@ #include "platform.hpp" +// provided for backwards compatibility, since this +// macro was used for several releases by mistake. +#if defined(BOOST_THREAD_DYN_DLL) +# define BOOST_THREAD_DYN_LINK +#endif + // compatibility with the rest of Boost's auto-linking code: -#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK) +#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) # undef BOOST_THREAD_USE_LIB # define BOOST_THREAD_USE_DLL #endif diff --git a/include/boost/thread/detail/platform.hpp b/include/boost/thread/detail/platform.hpp index 4a37cf38..58601b04 100644 --- a/include/boost/thread/detail/platform.hpp +++ b/include/boost/thread/detail/platform.hpp @@ -29,7 +29,7 @@ # define BOOST_THREAD_HPUX #elif defined(__CYGWIN__) # define BOOST_THREAD_CYGWIN -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32) # define BOOST_THREAD_WIN32 #elif defined(__BEOS__) # define BOOST_THREAD_BEOS diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 9615a39e..26224baa 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -3,10 +3,12 @@ // 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-8 Anthony Williams +// (C) Copyright 2007-10 Anthony Williams #include +#ifndef BOOST_NO_IOSTREAM #include +#endif #include #include #include @@ -113,14 +115,13 @@ namespace boost void release_handle(); - 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; + detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; #ifndef BOOST_NO_RVALUE_REFERENCES template @@ -147,7 +148,7 @@ namespace boost #endif struct dummy; public: -#ifdef __SUNPRO_CC +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread(const volatile thread&); #endif thread(); @@ -157,7 +158,7 @@ namespace boost #ifdef BOOST_MSVC template explicit thread(F f,typename disable_if >, dummy* >::type=0): - thread_info(make_thread_info(f)) + thread_info(make_thread_info(static_cast(f))) { start_thread(); } @@ -217,7 +218,7 @@ namespace boost x->thread_info.reset(); } -#ifdef __SUNPRO_CC +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) thread& operator=(thread x) { swap(x); @@ -394,7 +395,7 @@ namespace boost thread_data(thread_data_) {} friend class thread; - friend id this_thread::get_id(); + friend id BOOST_THREAD_DECL this_thread::get_id(); public: id(): thread_data() @@ -430,6 +431,8 @@ namespace boost return !(thread_data friend std::basic_ostream& operator<<(std::basic_ostream& os, const id& x) @@ -443,8 +446,34 @@ namespace boost return os<<"{Not-any-thread}"; } } +#else + template + std::basic_ostream& + print(std::basic_ostream& os) + { + if(thread_data) + { + return os< + std::basic_ostream& + operator<<(std::basic_ostream& os, const thread::id& x) + { + return x.print(os); + } +#endif + inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); diff --git a/include/boost/thread/detail/thread_group.hpp b/include/boost/thread/detail/thread_group.hpp index 823b92e7..f1ccdf84 100644 --- a/include/boost/thread/detail/thread_group.hpp +++ b/include/boost/thread/detail/thread_group.hpp @@ -18,10 +18,13 @@ namespace boost { - class thread_group: - private noncopyable + class thread_group { + private: + thread_group(thread_group const&); + thread_group& operator=(thread_group const&); public: + thread_group() {} ~thread_group() { for(std::list::iterator it=threads.begin(),end=threads.end(); diff --git a/include/boost/thread/detail/tss_hooks.hpp b/include/boost/thread/detail/tss_hooks.hpp index c4968442..b2ceece3 100644 --- a/include/boost/thread/detail/tss_hooks.hpp +++ b/include/boost/thread/detail/tss_hooks.hpp @@ -12,27 +12,9 @@ #if defined(BOOST_HAS_WINTHREADS) - typedef void (__cdecl *thread_exit_handler)(void); - - extern "C" BOOST_THREAD_DECL int at_thread_exit( - thread_exit_handler exit_handler - ); - //Add a function to the list of functions that will - //be called when a thread is about to exit. - //Currently only implemented for Win32, but should - //later be implemented for all platforms. - //Used by Win32 implementation of Boost.Threads - //tss to perform cleanup. - //Like the C runtime library atexit() function, - //which it mimics, at_thread_exit() returns - //zero if successful and a nonzero - //value if an error occurs. - -#endif //defined(BOOST_HAS_WINTHREADS) - -#if defined(BOOST_HAS_WINTHREADS) - - extern "C" BOOST_THREAD_DECL void on_process_enter(void); +namespace boost +{ + BOOST_THREAD_DECL void __cdecl on_process_enter(void); //Function to be called when the exe or dll //that uses Boost.Threads first starts //or is first loaded. @@ -42,7 +24,7 @@ //a method for doing so has been discovered. //May be omitted; may be called multiple times. - extern "C" BOOST_THREAD_DECL void on_process_exit(void); + BOOST_THREAD_DECL void __cdecl on_process_exit(void); //Function to be called when the exe or dll //that uses Boost.Threads first starts //or is first loaded. @@ -52,7 +34,7 @@ //a method for doing so has been discovered. //Must not be omitted; may be called multiple times. - extern "C" BOOST_THREAD_DECL void on_thread_enter(void); + BOOST_THREAD_DECL void __cdecl on_thread_enter(void); //Function to be called just after a thread starts //in an exe or dll that uses Boost.Threads. //Must be called in the context of the thread @@ -61,7 +43,7 @@ //a method for doing so has been discovered. //May be omitted; may be called multiple times. - extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void); + BOOST_THREAD_DECL void __cdecl on_thread_exit(void); //Function to be called just be fore a thread ends //in an exe or dll that uses Boost.Threads. //Must be called in the context of the thread @@ -70,10 +52,11 @@ //a method for doing so has been discovered. //Must not be omitted; may be called multiple times. - extern "C" void tss_cleanup_implemented(void); + void tss_cleanup_implemented(); //Dummy function used both to detect whether tss cleanup //cleanup has been implemented and to force //it to be linked into the Boost.Threads library. +} #endif //defined(BOOST_HAS_WINTHREADS) diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 8111d9ed..7f766c1f 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include #include @@ -140,6 +142,8 @@ namespace boost { lock.lock(); } + private: + relocker& operator=(relocker const&); }; void do_callback(boost::unique_lock& lock) @@ -388,15 +392,18 @@ namespace boost class future_waiter { + struct registered_waiter; + typedef std::vector::size_type count_type; + struct registered_waiter { boost::shared_ptr future; detail::future_object_base::waiter_list::iterator wait_iterator; - unsigned index; + count_type index; registered_waiter(boost::shared_ptr const& future_, detail::future_object_base::waiter_list::iterator wait_iterator_, - unsigned index_): + count_type index_): future(future_),wait_iterator(wait_iterator_),index(index_) {} @@ -404,7 +411,6 @@ namespace boost struct all_futures_lock { - typedef std::vector::size_type count_type; count_type count; boost::scoped_array > locks; @@ -424,7 +430,7 @@ namespace boost void unlock() { - for(unsigned i=0;i futures; - unsigned future_count; + count_type future_count; public: future_waiter(): @@ -450,12 +456,12 @@ namespace boost ++future_count; } - unsigned wait() + count_type wait() { all_futures_lock lk(futures); for(;;) { - for(unsigned i=0;idone) { @@ -468,7 +474,7 @@ namespace boost ~future_waiter() { - for(unsigned i=0;iremove_external_waiter(futures[i].wait_iterator); } diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index 3cd6f282..d23e6194 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -27,40 +28,100 @@ namespace boost #ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES namespace detail { - template +#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \ + template::value> \ + struct has_member_called_##member_name \ + { \ + BOOST_STATIC_CONSTANT(bool, value=false); \ + }; \ + \ + template \ + struct has_member_called_##member_name \ + { \ + typedef char true_type; \ + struct false_type \ + { \ + true_type dummy[2]; \ + }; \ + \ + struct fallback { int member_name; }; \ + struct derived: \ + T, fallback \ + { \ + derived(); \ + }; \ + \ + template struct tester; \ + \ + template \ + static false_type has_member(tester<&U::member_name>*); \ + template \ + static true_type has_member(...); \ + \ + BOOST_STATIC_CONSTANT( \ + bool, value=sizeof(has_member(0))==sizeof(true_type)); \ + } + + BOOST_DEFINE_HAS_MEMBER_CALLED(lock); + BOOST_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock); + + template::value > struct has_member_lock { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(U*,void (U::*dummy)()=&U::lock); - static false_type has_member(void*); - - BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_lock::has_member((T*)NULL))==sizeof(true_type)); - }; - - template - struct has_member_unlock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(U*,void (U::*dummy)()=&U::unlock); - static false_type has_member(void*); - - BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_unlock::has_member((T*)NULL))==sizeof(true_type)); + BOOST_STATIC_CONSTANT(bool, value=false); }; template + struct has_member_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); + }; + + template::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); + }; + + template::value > struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_try_lock { typedef char true_type; struct false_type @@ -69,10 +130,12 @@ namespace boost }; template - static true_type has_member(U*,bool (U::*dummy)()=&U::try_lock); - static false_type has_member(void*); + static true_type has_member(bool (U::*)()); + template + static false_type has_member(U); - BOOST_STATIC_CONSTANT(bool, value=sizeof(has_member_try_lock::has_member((T*)NULL))==sizeof(true_type)); + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); }; } @@ -214,7 +277,7 @@ namespace boost unique_lock& operator=(unique_lock&); unique_lock& operator=(upgrade_lock& other); public: -#ifdef __SUNPRO_CC +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) unique_lock(const volatile unique_lock&); #endif unique_lock(): @@ -300,7 +363,7 @@ namespace boost return detail::thread_move_t >(*this); } -#ifdef __SUNPRO_CC +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) unique_lock& operator=(unique_lock other) { swap(other); @@ -422,6 +485,18 @@ namespace boost { lhs.swap(rhs); } + + template + inline upgrade_lock&& move(upgrade_lock&& ul) + { + return static_cast&&>(ul); + } + + template + inline upgrade_lock&& move(upgrade_lock& ul) + { + return static_cast&&>(ul); + } #endif template void swap(unique_lock& lhs,unique_lock& rhs) @@ -678,6 +753,39 @@ namespace boost { try_lock(); } +#ifdef BOOST_HAS_RVALUE_REFS + upgrade_lock(upgrade_lock&& other): + m(other.m),is_locked(other.is_locked) + { + other.is_locked=false; + other.m=0; + } + + upgrade_lock(unique_lock&& other): + m(other.m),is_locked(other.is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + other.is_locked=false; + other.m=0; + } + + upgrade_lock& operator=(upgrade_lock&& other) + { + upgrade_lock temp(static_cast&&>(other)); + swap(temp); + return *this; + } + + upgrade_lock& operator=(unique_lock&& other) + { + upgrade_lock temp(static_cast&&>(other)); + swap(temp); + return *this; + } +#else upgrade_lock(detail::thread_move_t > other): m(other->m),is_locked(other->is_locked) { @@ -720,6 +828,7 @@ namespace boost swap(temp); return *this; } +#endif void swap(upgrade_lock& other) { @@ -824,6 +933,20 @@ namespace boost } } +#ifdef BOOST_HAS_RVALUE_REFS + upgrade_to_unique_lock(upgrade_to_unique_lock&& other): + source(other.source),exclusive(move(other.exclusive)) + { + other.source=0; + } + + upgrade_to_unique_lock& operator=(upgrade_to_unique_lock&& other) + { + upgrade_to_unique_lock temp(other); + swap(temp); + return *this; + } +#else upgrade_to_unique_lock(detail::thread_move_t > other): source(other->source),exclusive(move(other->exclusive)) { @@ -836,6 +959,7 @@ namespace boost swap(temp); return *this; } +#endif void swap(upgrade_to_unique_lock& other) { std::swap(source,other.source); @@ -923,15 +1047,15 @@ namespace boost return *this; } - void swap(try_lock_wrapper& other) - { - base::swap(other); - } void swap(detail::thread_move_t > other) { base::swap(*other); } #endif + void swap(try_lock_wrapper& other) + { + base::swap(other); + } void lock() { base::lock(); @@ -1116,7 +1240,7 @@ namespace boost { unsigned const lock_count=2; unsigned lock_first=0; - while(true) + for(;;) { switch(lock_first) { @@ -1169,7 +1293,7 @@ namespace boost { unsigned const lock_count=3; unsigned lock_first=0; - while(true) + for(;;) { switch(lock_first) { @@ -1201,7 +1325,7 @@ namespace boost { unsigned const lock_count=4; unsigned lock_first=0; - while(true) + for(;;) { switch(lock_first) { @@ -1239,7 +1363,7 @@ namespace boost { unsigned const lock_count=5; unsigned lock_first=0; - while(true) + for(;;) { switch(lock_first) { diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index 8e8f5b5a..30470be9 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -3,7 +3,7 @@ // 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-8 Anthony Williams +// (C) Copyright 2007-10 Anthony Williams #include "timespec.hpp" #include "pthread_mutex_scoped_lock.hpp" @@ -48,8 +48,8 @@ namespace boost pthread_mutex_t internal_mutex; pthread_cond_t cond; - condition_variable_any(condition_variable&); - condition_variable_any& operator=(condition_variable&); + condition_variable_any(condition_variable_any&); + condition_variable_any& operator=(condition_variable_any&); public: condition_variable_any() diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 59908f42..0224d3ac 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -47,7 +47,8 @@ namespace boost while(!pred()) wait(m); } - bool timed_wait(unique_lock& m,boost::system_time const& wait_until); + inline bool timed_wait(unique_lock& m, + boost::system_time const& wait_until); bool timed_wait(unique_lock& m,xtime const& wait_until) { return timed_wait(m,system_time(wait_until)); diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 1f7f790d..2a326d76 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -27,10 +27,11 @@ namespace boost { - class mutex: - boost::noncopyable + class mutex { private: + mutex(mutex const&); + mutex& operator=(mutex const&); pthread_mutex_t m; public: mutex() @@ -48,7 +49,11 @@ namespace boost void lock() { - BOOST_VERIFY(!pthread_mutex_lock(&m)); + int const res=pthread_mutex_lock(&m); + if(res) + { + boost::throw_exception(lock_error(res)); + } } void unlock() @@ -59,7 +64,11 @@ namespace boost bool try_lock() { int const res=pthread_mutex_trylock(&m); - BOOST_ASSERT(!res || res==EBUSY); + if(res && (res!=EBUSY)) + { + boost::throw_exception(lock_error(res)); + } + return !res; } @@ -75,9 +84,11 @@ namespace boost typedef mutex try_mutex; - class timed_mutex: - boost::noncopyable + class timed_mutex { + private: + timed_mutex(timed_mutex const&); + timed_mutex& operator=(timed_mutex const&); private: pthread_mutex_t m; #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index ad3b7e15..f3783f40 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -26,18 +26,30 @@ #endif #endif +#if defined(BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK) +#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK +#endif + #include namespace boost { - class recursive_mutex: - boost::noncopyable + class recursive_mutex { private: + recursive_mutex(recursive_mutex const&); + recursive_mutex& operator=(recursive_mutex const&); pthread_mutex_t m; +#ifndef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE + pthread_cond_t cond; + bool is_locked; + pthread_t owner; + unsigned count; +#endif public: recursive_mutex() { +#ifdef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE pthread_mutexattr_t attr; int const init_attr_res=pthread_mutexattr_init(&attr); @@ -54,15 +66,35 @@ namespace boost int const res=pthread_mutex_init(&m,&attr); if(res) { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); boost::throw_exception(thread_resource_error()); } BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=pthread_mutex_init(&m,NULL); + if(res) + { + boost::throw_exception(thread_resource_error()); + } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error()); + } + is_locked=false; + count=0; +#endif } ~recursive_mutex() { BOOST_VERIFY(!pthread_mutex_destroy(&m)); +#ifndef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE + BOOST_VERIFY(!pthread_cond_destroy(&cond)); +#endif } - + +#ifdef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE void lock() { BOOST_VERIFY(!pthread_mutex_lock(&m)); @@ -79,25 +111,70 @@ namespace boost BOOST_ASSERT(!res || res==EBUSY); return !res; } - typedef pthread_mutex_t* native_handle_type; native_handle_type native_handle() { return &m; } +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + +#endif + typedef unique_lock scoped_lock; typedef detail::try_lock_wrapper scoped_try_lock; }; typedef recursive_mutex recursive_try_mutex; - class recursive_timed_mutex: - boost::noncopyable + class recursive_timed_mutex { + private: + recursive_timed_mutex(recursive_timed_mutex const&); + recursive_timed_mutex& operator=(recursive_timed_mutex const&); private: pthread_mutex_t m; -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK pthread_cond_t cond; bool is_locked; pthread_t owner; @@ -106,7 +183,7 @@ namespace boost public: recursive_timed_mutex() { -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK pthread_mutexattr_t attr; int const init_attr_res=pthread_mutexattr_init(&attr); @@ -146,7 +223,7 @@ namespace boost ~recursive_timed_mutex() { BOOST_VERIFY(!pthread_mutex_destroy(&m)); -#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK BOOST_VERIFY(!pthread_cond_destroy(&cond)); #endif } @@ -157,7 +234,7 @@ namespace boost return timed_lock(get_system_time()+relative_time); } -#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK void lock() { BOOST_VERIFY(!pthread_mutex_lock(&m)); diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index 30440ebb..bc262828 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -225,7 +225,7 @@ namespace boost template bool timed_lock_upgrade(TimeDuration const & relative_time) { - return timed_lock(get_system_time()+relative_time); + return timed_lock_upgrade(get_system_time()+relative_time); } bool try_lock_upgrade() diff --git a/include/boost/thread/tss.hpp b/include/boost/thread/tss.hpp index e38e3e96..c920024b 100644 --- a/include/boost/thread/tss.hpp +++ b/include/boost/thread/tss.hpp @@ -62,6 +62,8 @@ namespace boost boost::shared_ptr cleanup; public: + typedef T element_type; + thread_specific_ptr(): cleanup(detail::heap_new(),detail::do_heap_delete()) {} diff --git a/include/boost/thread/win32/mutex.hpp b/include/boost/thread/win32/mutex.hpp index efe6241d..d59fbfa3 100644 --- a/include/boost/thread/win32/mutex.hpp +++ b/include/boost/thread/win32/mutex.hpp @@ -20,9 +20,11 @@ namespace boost } class mutex: - boost::noncopyable, public ::boost::detail::underlying_mutex { + private: + mutex(mutex const&); + mutex& operator=(mutex const&); public: mutex() { @@ -40,9 +42,11 @@ namespace boost typedef mutex try_mutex; class timed_mutex: - boost::noncopyable, public ::boost::detail::basic_timed_mutex { + private: + timed_mutex(timed_mutex const&); + timed_mutex& operator=(timed_mutex const&); public: timed_mutex() { diff --git a/include/boost/thread/win32/recursive_mutex.hpp b/include/boost/thread/win32/recursive_mutex.hpp index 2360a92b..e83d3bc0 100644 --- a/include/boost/thread/win32/recursive_mutex.hpp +++ b/include/boost/thread/win32/recursive_mutex.hpp @@ -20,9 +20,11 @@ namespace boost { class recursive_mutex: - boost::noncopyable, public ::boost::detail::basic_recursive_mutex { + private: + recursive_mutex(recursive_mutex const&); + recursive_mutex& operator=(recursive_mutex const&); public: recursive_mutex() { @@ -40,9 +42,11 @@ namespace boost typedef recursive_mutex recursive_try_mutex; class recursive_timed_mutex: - boost::noncopyable, public ::boost::detail::basic_recursive_timed_mutex { + private: + recursive_timed_mutex(recursive_timed_mutex const&); + recursive_timed_mutex& operator=(recursive_timed_mutex const&); public: recursive_timed_mutex() { diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index 58e8093a..58fc6224 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -19,9 +19,11 @@ namespace boost { - class shared_mutex: - private boost::noncopyable + class shared_mutex { + private: + shared_mutex(shared_mutex const&); + shared_mutex& operator=(shared_mutex const&); private: struct state_data { @@ -49,33 +51,35 @@ namespace boost return *reinterpret_cast(&res); } + enum + { + unlock_sem = 0, + exclusive_sem = 1 + }; + state_data state; detail::win32::handle semaphores[2]; - detail::win32::handle &unlock_sem; - detail::win32::handle &exclusive_sem; detail::win32::handle upgrade_sem; void release_waiters(state_data old_state) { if(old_state.exclusive_waiting) { - BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0); + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); } if(old_state.shared_waiting || old_state.exclusive_waiting) { - BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); } } public: - shared_mutex(): - unlock_sem(semaphores[0]), - exclusive_sem(semaphores[1]) + shared_mutex() { - unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); - exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); state_data state_={0}; state=state_; @@ -84,8 +88,8 @@ namespace boost ~shared_mutex() { detail::win32::CloseHandle(upgrade_sem); - detail::win32::CloseHandle(unlock_sem); - detail::win32::CloseHandle(exclusive_sem); + detail::win32::CloseHandle(semaphores[unlock_sem]); + detail::win32::CloseHandle(semaphores[exclusive_sem]); } bool try_lock_shared() @@ -97,6 +101,10 @@ namespace boost if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) { ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } } state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); @@ -131,10 +139,18 @@ namespace boost if(new_state.exclusive || new_state.exclusive_waiting_blocked) { ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } } else { ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } } state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); @@ -150,7 +166,7 @@ namespace boost return true; } - unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until)); + unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until)); if(res==detail::win32::timeout) { for(;;) @@ -166,6 +182,10 @@ namespace boost else { ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } } state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); @@ -282,6 +302,11 @@ namespace boost if(new_state.shared_count || new_state.exclusive) { ++new_state.exclusive_waiting; + if(!new_state.exclusive_waiting) + { + boost::throw_exception(boost::lock_error()); + } + new_state.exclusive_waiting_blocked=true; } else @@ -374,10 +399,18 @@ namespace boost if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) { ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } } else { ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } new_state.upgrade=true; } @@ -394,7 +427,7 @@ namespace boost return; } - BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite)); + BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite)); } } @@ -411,6 +444,10 @@ namespace boost else { ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } new_state.upgrade=true; } diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp index 1a6a1e03..c86b0fa1 100644 --- a/include/boost/thread/win32/thread_data.hpp +++ b/include/boost/thread/win32/thread_data.hpp @@ -144,6 +144,11 @@ namespace boost start(0),milliseconds(~uintmax_t(0)),relative(true) {} }; + + inline unsigned long pin_to_zero(long value) + { + return (value<0)?0u:(unsigned long)value; + } } namespace this_thread @@ -163,7 +168,7 @@ namespace boost template inline void sleep(TimeDuration const& rel_time) { - interruptible_wait(static_cast(rel_time.total_milliseconds())); + interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); } inline void sleep(system_time const& abs_time) { diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 1c13a9a2..4ff40a90 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -75,7 +75,7 @@ namespace boost { current=next; ++next; - if(current->second.func && current->second.value) + if(current->second.func && (current->second.value!=0)) { (*current->second.func)(current->second.value); } @@ -196,15 +196,14 @@ namespace boost detach(); } - detail::thread_data_ptr thread::get_thread_info() const + detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const { - lock_guard l(thread_info_mutex); return thread_info; } void thread::join() { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { bool do_join=false; @@ -238,7 +237,6 @@ namespace boost local_thread_info->done_condition.notify_all(); } - lock_guard l1(thread_info_mutex); if(thread_info==local_thread_info) { thread_info.reset(); @@ -248,7 +246,7 @@ namespace boost bool thread::timed_join(system_time const& wait_until) { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { bool do_join=false; @@ -285,7 +283,6 @@ namespace boost local_thread_info->done_condition.notify_all(); } - lock_guard l1(thread_info_mutex); if(thread_info==local_thread_info) { thread_info.reset(); @@ -296,17 +293,14 @@ namespace boost bool thread::joinable() const { - return get_thread_info(); + return (get_thread_info)(); } void thread::detach() { detail::thread_data_ptr local_thread_info; - { - lock_guard l1(thread_info_mutex); - thread_info.swap(local_thread_info); - } + thread_info.swap(local_thread_info); if(local_thread_info) { @@ -381,8 +375,6 @@ namespace boost { #if defined(PTW32_VERSION) || defined(__hpux) return pthread_num_processors_np(); -#elif defined(_GNU_SOURCE) - return get_nprocs(); #elif defined(__APPLE__) || defined(__FreeBSD__) int count; size_t size=sizeof(count); @@ -390,6 +382,8 @@ namespace boost #elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN) int const count=sysconf(_SC_NPROCESSORS_ONLN); return (count>0)?count:0; +#elif defined(_GNU_SOURCE) + return get_nprocs(); #else return 0; #endif @@ -397,7 +391,7 @@ namespace boost thread::id thread::get_id() const { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { return id(local_thread_info); @@ -410,7 +404,7 @@ namespace boost void thread::interrupt() { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { lock_guard lk(local_thread_info->data_mutex); @@ -424,7 +418,7 @@ namespace boost bool thread::interruption_requested() const { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { lock_guard lk(local_thread_info->data_mutex); @@ -438,7 +432,7 @@ namespace boost thread::native_handle_type thread::native_handle() { - detail::thread_data_ptr const local_thread_info=get_thread_info(); + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { lock_guard lk(local_thread_info->data_mutex); @@ -582,11 +576,11 @@ namespace boost { if(tss_data_node* const current_node=find_tss_data(key)) { - if(cleanup_existing && current_node->func && current_node->value) + if(cleanup_existing && current_node->func && (current_node->value!=0)) { (*current_node->func)(current_node->value); } - if(func || tss_data) + if(func || (tss_data!=0)) { current_node->func=func; current_node->value=tss_data; diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index b85e6505..756ce6dd 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -244,17 +244,17 @@ namespace boost thread::id thread::get_id() const { - return thread::id(get_thread_info()); + return thread::id((get_thread_info)()); } bool thread::joinable() const { - return get_thread_info(); + return (get_thread_info)(); } void thread::join() { - detail::thread_data_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); @@ -264,7 +264,7 @@ namespace boost bool thread::timed_join(boost::system_time const& wait_until) { - detail::thread_data_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until))) @@ -283,13 +283,12 @@ namespace boost void thread::release_handle() { - lock_guard l1(thread_info_mutex); thread_info=0; } void thread::interrupt() { - detail::thread_data_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { local_thread_info->interrupt(); @@ -298,26 +297,25 @@ namespace boost bool thread::interruption_requested() const { - detail::thread_data_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr local_thread_info=(get_thread_info)(); return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0); } unsigned thread::hardware_concurrency() { - SYSTEM_INFO info={0}; + SYSTEM_INFO info={{0}}; GetSystemInfo(&info); return info.dwNumberOfProcessors; } thread::native_handle_type thread::native_handle() { - detail::thread_data_ptr local_thread_info=get_thread_info(); + detail::thread_data_ptr local_thread_info=(get_thread_info)(); return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value; } - detail::thread_data_ptr thread::get_thread_info() const + detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const { - boost::mutex::scoped_lock l(thread_info_mutex); return thread_info; } @@ -327,7 +325,7 @@ namespace boost { LARGE_INTEGER get_due_time(detail::timeout const& target_time) { - LARGE_INTEGER due_time={0}; + LARGE_INTEGER due_time={{0}}; if(target_time.relative) { unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start; @@ -356,7 +354,23 @@ namespace boost else { long const hundred_nanoseconds_in_one_second=10000000; - due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second()); + posix_time::time_duration::tick_type const ticks_per_second= + target_time.abs_time.time_of_day().ticks_per_second(); + if(ticks_per_second>hundred_nanoseconds_in_one_second) + { + posix_time::time_duration::tick_type const + ticks_per_hundred_nanoseconds= + ticks_per_second/hundred_nanoseconds_in_one_second; + due_time.QuadPart+= + target_time.abs_time.time_of_day().fractional_seconds()/ + ticks_per_hundred_nanoseconds; + } + else + { + due_time.QuadPart+= + target_time.abs_time.time_of_day().fractional_seconds()* + (hundred_nanoseconds_in_one_second/ticks_per_second); + } } } return due_time; @@ -577,22 +591,22 @@ namespace boost } } } + BOOST_THREAD_DECL void __cdecl on_process_enter() + {} + + BOOST_THREAD_DECL void __cdecl on_thread_enter() + {} + + BOOST_THREAD_DECL void __cdecl on_process_exit() + { + boost::cleanup_tls_key(); + } + + BOOST_THREAD_DECL void __cdecl on_thread_exit() + { + boost::run_thread_exit_callbacks(); + } + } -extern "C" BOOST_THREAD_DECL void on_process_enter() -{} - -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() -{ - boost::run_thread_exit_callbacks(); -} - diff --git a/src/win32/tss_dll.cpp b/src/win32/tss_dll.cpp index 0522a123..9699a12b 100644 --- a/src/win32/tss_dll.cpp +++ b/src/win32/tss_dll.cpp @@ -24,27 +24,27 @@ { case DLL_PROCESS_ATTACH: { - on_process_enter(); - on_thread_enter(); + boost::on_process_enter(); + boost::on_thread_enter(); break; } case DLL_THREAD_ATTACH: { - on_thread_enter(); + boost::on_thread_enter(); break; } case DLL_THREAD_DETACH: { - on_thread_exit(); + boost::on_thread_exit(); break; } case DLL_PROCESS_DETACH: { - on_thread_exit(); - on_process_exit(); + boost::on_thread_exit(); + boost::on_process_exit(); break; } } @@ -52,7 +52,9 @@ return TRUE; } - extern "C" void tss_cleanup_implemented(void) +namespace boost +{ + void tss_cleanup_implemented() { /* This function's sole purpose is to cause a link error in cases where @@ -68,5 +70,7 @@ longer needed and can be removed. */ } +} + #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL) diff --git a/src/win32/tss_pe.cpp b/src/win32/tss_pe.cpp index ea831218..fb49ac3e 100644 --- a/src/win32/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -19,7 +19,10 @@ #include -extern "C" void tss_cleanup_implemented(void) {} +namespace boost +{ + void tss_cleanup_implemented() {} +} namespace { void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv) @@ -28,33 +31,18 @@ namespace { { case DLL_THREAD_DETACH: { - on_thread_exit(); + boost::on_thread_exit(); break; } } } - - void on_after_ctors(void) - { - on_process_enter(); - } - - void on_before_dtors(void) - { - on_thread_exit(); - } - - void on_after_dtors(void) - { - on_process_exit(); - } } extern "C" { - void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors; - void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors; - void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors; + void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter; + void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit; + void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit; ULONG __tls_index__ = 0; char __tls_end__ __attribute__((section(".tls$zzz"))) = 0; @@ -89,13 +77,13 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata //Definitions required by implementation #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 - typedef void (__cdecl *_PVFV)(void); + typedef void (__cdecl *_PVFV)(); #define INIRETSUCCESS - #define PVAPI void + #define PVAPI void __cdecl #else - typedef int (__cdecl *_PVFV)(void); + typedef int (__cdecl *_PVFV)(); #define INIRETSUCCESS 0 - #define PVAPI int + #define PVAPI int __cdecl #endif typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); @@ -112,9 +100,9 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata { //Forward declarations - static PVAPI on_tls_prepare(void); - static PVAPI on_process_init(void); - static PVAPI on_process_term(void); + static PVAPI on_tls_prepare(); + static PVAPI on_process_init(); + static PVAPI on_process_term(); static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID); //The .CRT$Xxx information is taken from Codeguru: @@ -169,7 +157,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata #pragma warning(disable:4189) #endif - PVAPI on_tls_prepare(void) + PVAPI on_tls_prepare() { //The following line has an important side effect: //if the TLS directory is not already there, it will @@ -210,7 +198,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata #pragma warning(pop) #endif - PVAPI on_process_init(void) + PVAPI on_process_init() { //Schedule on_thread_exit() to be called for the main //thread before destructors of global objects have been @@ -221,18 +209,18 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata //for destructors of global objects, so that //shouldn't be a problem. - atexit(on_thread_exit); + atexit(boost::on_thread_exit); //Call Boost process entry callback here - on_process_enter(); + boost::on_process_enter(); return INIRETSUCCESS; } - PVAPI on_process_term(void) + PVAPI on_process_term() { - on_process_exit(); + boost::on_process_exit(); return INIRETSUCCESS; } @@ -241,7 +229,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata switch (dwReason) { case DLL_THREAD_DETACH: - on_thread_exit(); + boost::on_thread_exit(); break; } } @@ -251,10 +239,10 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata switch (dwReason) { case DLL_THREAD_DETACH: - on_thread_exit(); + boost::on_thread_exit(); break; case DLL_PROCESS_DETACH: - on_process_exit(); + boost::on_process_exit(); break; } return true; @@ -265,8 +253,9 @@ extern "C" { extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback; } - - extern "C" void tss_cleanup_implemented(void) +namespace boost +{ + void tss_cleanup_implemented() { /* This function's sole purpose is to cause a link error in cases where @@ -282,6 +271,8 @@ extern "C" longer needed and can be removed. */ } +} + #endif //defined(_MSC_VER) && !defined(UNDER_CE) #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) diff --git a/test/test_futures.cpp b/test/test_futures.cpp index 1e815d82..d19484fc 100644 --- a/test/test_futures.cpp +++ b/test/test_futures.cpp @@ -18,7 +18,7 @@ template typename boost::remove_reference::type&& cast_to_rval(T&& t) { - return t; + return static_cast::type&&>(t); } #else template @@ -556,7 +556,7 @@ void wait_callback(boost::promise& pi) } } -void do_nothing_callback(boost::promise& pi) +void do_nothing_callback(boost::promise& /*pi*/) { boost::lock_guard lk(callback_mutex); ++callback_called; diff --git a/test/test_generic_locks.cpp b/test/test_generic_locks.cpp index d3880d5c..c1dd85de 100644 --- a/test/test_generic_locks.cpp +++ b/test/test_generic_locks.cpp @@ -296,10 +296,80 @@ void test_lock_five_in_range() } } -void test_lock_ten_in_range() +class dummy_iterator: + public std::iterator +{ +private: + dummy_mutex* p; +public: + explicit dummy_iterator(dummy_mutex* p_): + p(p_) + {} + + bool operator==(dummy_iterator const& other) const + { + return p==other.p; + } + + bool operator!=(dummy_iterator const& other) const + { + return p!=other.p; + } + + bool operator<(dummy_iterator const& other) const + { + return p() const + { + return p; + } + + dummy_iterator operator++(int) + { + dummy_iterator temp(*this); + ++p; + return temp; + } + + dummy_iterator& operator++() + { + ++p; + return *this; + } + +}; + + +void test_lock_five_in_range_custom_iterator() +{ + unsigned const num_mutexes=5; + dummy_mutex mutexes[num_mutexes]; + + boost::lock(dummy_iterator(mutexes),dummy_iterator(mutexes+num_mutexes)); + + for(unsigned i=0;iadd(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order)); test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order)); test->add(BOOST_TEST_CASE(&test_lock_five_in_range)); - test->add(BOOST_TEST_CASE(&test_lock_ten_in_range)); + test->add(BOOST_TEST_CASE(&test_lock_five_in_range_custom_iterator)); + test->add(BOOST_TEST_CASE(&test_lock_ten_in_range_inherited_mutex)); test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order)); test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended)); test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked)); diff --git a/test/test_shared_mutex_part_2.cpp b/test/test_shared_mutex_part_2.cpp index ae38838b..bd5d1b9b 100644 --- a/test/test_shared_mutex_part_2.cpp +++ b/test/test_shared_mutex_part_2.cpp @@ -138,6 +138,14 @@ void test_can_lock_upgrade_if_currently_locked_shared() CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1); } +void test_can_lock_upgrade_to_unique_if_currently_locked_upgrade() +{ + boost::shared_mutex mtx; + boost::upgrade_lock l(mtx); + boost::upgrade_to_unique_lock ul(l); + BOOST_CHECK(ul.owns_lock()); +} + void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() { @@ -282,6 +290,7 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted)); test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared)); + test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_to_unique_if_currently_locked_upgrade)); test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false)); test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true)); test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));