From 856d0d3f41f195cada4ae423fb68d30bc07bf159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Tue, 20 Aug 2013 08:47:17 +0000 Subject: [PATCH] Fixes #9008 [SVN r85401] --- .../detail/intermodule_singleton_common.hpp | 6 +- .../detail/managed_open_or_create_impl.hpp | 9 +- .../detail/os_thread_functions.hpp | 3 +- .../interprocess/detail/robust_emulation.hpp | 5 +- include/boost/interprocess/detail/yield_k.hpp | 136 ++++++++++++++++++ include/boost/interprocess/sync/file_lock.hpp | 7 +- .../boost/interprocess/sync/posix/mutex.hpp | 3 +- .../sync/posix/recursive_mutex.hpp | 4 +- .../sync/posix/semaphore_wrapper.hpp | 3 +- .../interprocess/sync/spin/condition.hpp | 12 +- .../boost/interprocess/sync/spin/mutex.hpp | 6 +- .../interprocess/sync/spin/semaphore.hpp | 6 +- test/robust_mutex_test.hpp | 6 +- 13 files changed, 177 insertions(+), 29 deletions(-) create mode 100644 include/boost/interprocess/detail/yield_k.hpp diff --git a/include/boost/interprocess/detail/intermodule_singleton_common.hpp b/include/boost/interprocess/detail/intermodule_singleton_common.hpp index 669194c..485f98d 100644 --- a/include/boost/interprocess/detail/intermodule_singleton_common.hpp +++ b/include/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -145,6 +145,7 @@ class intermodule_singleton_common //If previous state was initializing, this means that another winner thread is //trying to initialize the singleton. Just wait until completes its work. else if(previous_module_singleton_initialized == Initializing){ + unsigned int k = 0; while(1){ previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); if(previous_module_singleton_initialized >= Initialized){ @@ -152,7 +153,7 @@ class intermodule_singleton_common break; } else if(previous_module_singleton_initialized == Initializing){ - thread_yield(); + yield(k++); } else{ //This can't be happening! @@ -206,6 +207,7 @@ class intermodule_singleton_common static void initialize_global_map_handle() { //Obtain unique map name and size + unsigned k = 0; while(1){ //Try to pass map state to initializing ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized); @@ -218,7 +220,7 @@ class intermodule_singleton_common } //If some other thread is doing the work wait else if(tmp == Initializing){ - thread_yield(); + yield(k++); } else{ //(tmp == Uninitialized) //If not initialized try it again? diff --git a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp index f8154d0..389f9f2 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -354,6 +354,7 @@ class managed_open_or_create_impl //file and know if we have really created it or just open it //drop me a e-mail! bool completed = false; + unsigned k = 0; while(!completed){ try{ create_device(dev, id, size, perm, file_like_t()); @@ -384,7 +385,7 @@ class managed_open_or_create_impl catch(...){ throw; } - thread_yield(); + yield(k++); } } @@ -431,11 +432,12 @@ class managed_open_or_create_impl else{ if(FileBased){ offset_t filesize = 0; + unsigned k = 0; while(filesize == 0){ if(!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)){ throw interprocess_exception(error_info(system_error_code())); } - thread_yield(); + yield(k++); } if(filesize == 1){ throw interprocess_exception(error_info(corrupted_error)); @@ -447,8 +449,9 @@ class managed_open_or_create_impl boost::uint32_t *patomic_word = static_cast(region.get_address()); boost::uint32_t value = atomic_read32(patomic_word); + unsigned k = 0; while(value == InitializingSegment || value == UninitializedSegment){ - thread_yield(); + yield(k++); value = atomic_read32(patomic_word); } diff --git a/include/boost/interprocess/detail/os_thread_functions.hpp b/include/boost/interprocess/detail/os_thread_functions.hpp index f881a1f..dd86ba0 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -15,8 +15,9 @@ #include #include #include +#include -#if (defined BOOST_INTERPROCESS_WINDOWS) +#if defined(BOOST_INTERPROCESS_WINDOWS) # include #else # ifdef BOOST_HAS_UNISTD_H diff --git a/include/boost/interprocess/detail/robust_emulation.hpp b/include/boost/interprocess/detail/robust_emulation.hpp index cac6595..5722589 100644 --- a/include/boost/interprocess/detail/robust_emulation.hpp +++ b/include/boost/interprocess/detail/robust_emulation.hpp @@ -236,7 +236,7 @@ inline void robust_spin_mutex::lock() } else{ //Do the dead owner checking each spin_threshold lock tries - ipcdetail::thread_yield(); + yield(spin_count); ++spin_count; if(spin_count > spin_threshold){ //Check if owner dead and take ownership if possible @@ -292,6 +292,7 @@ inline bool robust_spin_mutex::timed_lock if(now >= abs_time) return this->try_lock(); + unsigned k = 0; do{ if(this->try_lock()){ break; @@ -302,7 +303,7 @@ inline bool robust_spin_mutex::timed_lock return this->try_lock(); } // relinquish current time slice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); }while (true); return true; diff --git a/include/boost/interprocess/detail/yield_k.hpp b/include/boost/interprocess/detail/yield_k.hpp new file mode 100644 index 0000000..bf05865 --- /dev/null +++ b/include/boost/interprocess/detail/yield_k.hpp @@ -0,0 +1,136 @@ +//This file was copied from boost/smart_ptr/detail and +//modified here to avoid dependencies with that library +#ifndef BOOST_INTERPROCESS_DETAIL_YIELD_K_HPP_INCLUDED +#define BOOST_INTERPROCESS_DETAIL_YIELD_K_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// yield_k.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// void yield( unsigned k ); +// +// Typical use: +// +// for( unsigned k = 0; !try_lock(); ++k ) yield( k ); +// +// 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 + +// BOOST_INTERPROCESS_SMT_PAUSE + +#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) + +extern "C" void _mm_pause(); +#pragma intrinsic( _mm_pause ) + +#define BOOST_INTERPROCESS_SMT_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_INTERPROCESS_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#endif + +// + +#if defined (BOOST_INTERPROCESS_WINDOWS) + +#include + +namespace boost +{ +namespace interprocess +{ +namespace ipcdetail +{ + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_INTERPROCESS_SMT_PAUSE ) + else if( k < 16 ){ + BOOST_INTERPROCESS_SMT_PAUSE + } +#endif + else if( k < 32 ){ + //Try to yield to another thread running on the current processor + if(!winapi::SwitchToThread()){ + //If not yield to any thread of same or higher priority on any processor + boost::interprocess::winapi::Sleep(0); + } + } + else{ + //Yields to any thread on any processor + boost::interprocess::winapi::Sleep(1); + } +} + +} // namespace ipcdetail +} // namespace interprocess +} // namespace boost + +#else + +#include +#include + +namespace boost +{ +namespace interprocess +{ +namespace ipcdetail +{ + +inline void yield( unsigned k ) +{ + if( k < 4 ) + { + } +#if defined( BOOST_INTERPROCESS_SMT_PAUSE ) + else if( k < 16 ) + { + BOOST_INTERPROCESS_SMT_PAUSE + } +#endif + else if( k < 32 || k & 1 ) + { + sched_yield(); + } + else + { + // g++ -Wextra warns on {} or {0} + struct timespec rqtp = { 0, 0 }; + + // POSIX says that timespec has tv_sec and tv_nsec + // But it doesn't guarantee order or placement + + rqtp.tv_sec = 0; + rqtp.tv_nsec = 1000; + + nanosleep( &rqtp, 0 ); + } +} + +} // namespace ipcdetail +} // namespace interprocess +} // namespace boost + +#endif + +#include + +#endif // #ifndef BOOST_INTERPROCESS_DETAIL_YIELD_K_HPP_INCLUDED diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index ef1c68a..81fd817 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -149,7 +149,7 @@ class file_lock using namespace boost::detail; if(now >= abs_time) return false; - + unsigned k = 0; do{ if(!ipcdetail::try_acquire_file_lock(hnd, acquired)) return false; @@ -164,7 +164,7 @@ class file_lock return true; } // relinquish current time slice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); } }while (true); } @@ -178,6 +178,7 @@ class file_lock if(now >= abs_time) return false; + unsigned k = 0; do{ if(!ipcdetail::try_acquire_file_lock_sharable(hnd, acquired)) return false; @@ -192,7 +193,7 @@ class file_lock return true; } // relinquish current time slice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); } }while (true); } diff --git a/include/boost/interprocess/sync/posix/mutex.hpp b/include/boost/interprocess/sync/posix/mutex.hpp index 344c5e9..13c2f48 100644 --- a/include/boost/interprocess/sync/posix/mutex.hpp +++ b/include/boost/interprocess/sync/posix/mutex.hpp @@ -119,6 +119,7 @@ inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) //Obtain current count and target time boost::posix_time::ptime now = microsec_clock::universal_time(); + unsigned k = 0; do{ if(this->try_lock()){ break; @@ -129,7 +130,7 @@ inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) return false; } // relinquish current time slice - thread_yield(); + ipcdetail::yield(k++); }while (true); return true; diff --git a/include/boost/interprocess/sync/posix/recursive_mutex.hpp b/include/boost/interprocess/sync/posix/recursive_mutex.hpp index 385d714..4fd06dc 100644 --- a/include/boost/interprocess/sync/posix/recursive_mutex.hpp +++ b/include/boost/interprocess/sync/posix/recursive_mutex.hpp @@ -108,7 +108,7 @@ inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &ab //Obtain current count and target time boost::posix_time::ptime now = microsec_clock::universal_time(); - + unsigned k = 0; do{ if(this->try_lock()){ break; @@ -119,7 +119,7 @@ inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &ab return false; } // relinquish current time slice - thread_yield(); + yield(k++); }while (true); return true; diff --git a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp index f6aef56..3e18d60 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -195,10 +195,11 @@ inline bool semaphore_timed_wait(sem_t *handle, const boost::posix_time::ptime & return false; #else //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS boost::posix_time::ptime now; + unsigned k = 0; do{ if(semaphore_try_wait(handle)) return true; - thread_yield(); + yield(k++); }while((now = microsec_clock::universal_time()) < abs_time); return false; #endif //#ifdef BOOST_INTERPROCESS_POSIX_TIMEOUTS diff --git a/include/boost/interprocess/sync/spin/condition.hpp b/include/boost/interprocess/sync/spin/condition.hpp index 7c3306d..641bf7f 100644 --- a/include/boost/interprocess/sync/spin/condition.hpp +++ b/include/boost/interprocess/sync/spin/condition.hpp @@ -140,15 +140,10 @@ inline void spin_condition::notify(boost::uint32_t command) } //Notify that all threads should execute wait logic + unsigned k = 0; while(SLEEP != atomic_cas32(const_cast(&m_command), command, SLEEP)){ - thread_yield(); + yield(k++); } -/* - //Wait until the threads are woken - while(SLEEP != atomic_cas32(const_cast(&m_command), 0)){ - thread_yield(); - } -*/ //The enter mutex will rest locked until the last waiting thread unlocks it } @@ -211,8 +206,9 @@ inline bool spin_condition::do_timed_wait(bool tout_enabled, while(1){ //The thread sleeps/spins until a spin_condition commands a notification //Notification occurred, we will lock the checking mutex so that + unsigned k = 0; while(atomic_read32(&m_command) == SLEEP){ - thread_yield(); + yield(k++); //Check for timeout if(tout_enabled){ diff --git a/include/boost/interprocess/sync/spin/mutex.hpp b/include/boost/interprocess/sync/spin/mutex.hpp index 94c26a1..fc43a9c 100644 --- a/include/boost/interprocess/sync/spin/mutex.hpp +++ b/include/boost/interprocess/sync/spin/mutex.hpp @@ -60,6 +60,7 @@ inline spin_mutex::~spin_mutex() inline void spin_mutex::lock(void) { + unsigned k = 0; do{ boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast(&m_s), 1, 0); @@ -67,7 +68,7 @@ inline void spin_mutex::lock(void) break; } // relinquish current timeslice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); }while (true); } @@ -86,6 +87,7 @@ inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) //Obtain current count and target time boost::posix_time::ptime now = microsec_clock::universal_time(); + unsigned k = 0; do{ if(this->try_lock()){ break; @@ -96,7 +98,7 @@ inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) return false; } // relinquish current time slice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); }while (true); return true; diff --git a/include/boost/interprocess/sync/spin/semaphore.hpp b/include/boost/interprocess/sync/spin/semaphore.hpp index a5ba3b1..a209d36 100644 --- a/include/boost/interprocess/sync/spin/semaphore.hpp +++ b/include/boost/interprocess/sync/spin/semaphore.hpp @@ -59,9 +59,10 @@ inline void spin_semaphore::post() inline void spin_semaphore::wait() { + unsigned k = 0; while(!ipcdetail::atomic_add_unless32(&m_count, boost::uint32_t(-1), boost::uint32_t(0))){ while(ipcdetail::atomic_read32(&m_count) == 0){ - ipcdetail::thread_yield(); + ipcdetail::yield(k++); } } } @@ -80,6 +81,7 @@ inline bool spin_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) //Obtain current count and target time boost::posix_time::ptime now(microsec_clock::universal_time()); + unsigned k = 0; do{ if(this->try_wait()){ break; @@ -90,7 +92,7 @@ inline bool spin_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) return this->try_wait(); } // relinquish current time slice - ipcdetail::thread_yield(); + ipcdetail::yield(k++); }while (true); return true; } diff --git a/test/robust_mutex_test.hpp b/test/robust_mutex_test.hpp index 513dba9..3ec0cb5 100644 --- a/test/robust_mutex_test.hpp +++ b/test/robust_mutex_test.hpp @@ -66,8 +66,9 @@ int robust_mutex_test(int argc, char *argv[]) return 1; //Wait until child locks the mutexes and dies + unsigned k = 0; while(!*go_ahead){ - ipcdetail::thread_yield(); + ipcdetail::yield(k++); } std::cout << "... recovering mutex[0]" << std::endl; @@ -163,8 +164,9 @@ int robust_mutex_test(int argc, char *argv[]) } //Wait until child locks the 2nd mutex and dies + unsigned k = 0; while(!*go_ahead2){ - ipcdetail::thread_yield(); + ipcdetail::yield(k++); } //Done, now try to lock number 3 to see if robust