From e559ac32753eaee006194eece9557ec4d9b27f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ion=20Gazta=C3=B1aga?= Date: Sun, 8 Sep 2013 20:07:03 +0000 Subject: [PATCH] Merged Interprocess to the release branch [SVN r85615] --- Jamfile.v2 | 2 +- doc/interprocess.qbk | 9 +- include/boost/interprocess/detail/atomic.hpp | 2 +- .../detail/intermodule_singleton_common.hpp | 9 +- .../detail/managed_open_or_create_impl.hpp | 13 +- .../detail/os_thread_functions.hpp | 266 +++++++++++++++++- .../interprocess/detail/robust_emulation.hpp | 17 +- .../interprocess/detail/tmp_dir_helpers.hpp | 2 +- .../boost/interprocess/detail/win32_api.hpp | 119 ++++++-- include/boost/interprocess/detail/yield_k.hpp | 136 --------- .../smart_ptr/detail/sp_counted_impl.hpp | 9 +- .../interprocess/streams/bufferstream.hpp | 137 +++++---- .../interprocess/streams/vectorstream.hpp | 113 ++++---- include/boost/interprocess/sync/file_lock.hpp | 9 +- .../boost/interprocess/sync/posix/mutex.hpp | 5 +- .../sync/posix/recursive_mutex.hpp | 5 +- .../sync/posix/semaphore_wrapper.hpp | 5 +- .../interprocess/sync/spin/condition.hpp | 9 +- .../boost/interprocess/sync/spin/mutex.hpp | 9 +- .../interprocess/sync/spin/semaphore.hpp | 11 +- include/boost/interprocess/sync/spin/wait.hpp | 186 ++++++++++++ test/bufferstream_test.cpp | 2 +- test/robust_mutex_test.hpp | 9 +- 23 files changed, 753 insertions(+), 331 deletions(-) delete mode 100644 include/boost/interprocess/detail/yield_k.hpp create mode 100644 include/boost/interprocess/sync/spin/wait.hpp diff --git a/Jamfile.v2 b/Jamfile.v2 index 9fbcdc6..8333597 100644 --- a/Jamfile.v2 +++ b/Jamfile.v2 @@ -2,4 +2,4 @@ import testing ; # Tests from Jamfiles in individual library test subdirectories build-project example ; # test-suite interprocess_example -build-project test ; # test-suite interprocess_test +build-project test ; # test-suite interprocess_test \ No newline at end of file diff --git a/doc/interprocess.qbk b/doc/interprocess.qbk index 25d6da8..3b33247 100644 --- a/doc/interprocess.qbk +++ b/doc/interprocess.qbk @@ -6715,8 +6715,13 @@ thank them: [section:release_notes_boost_1_55_00 Boost 1.55 Release] -* Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7164 #7164], - [@https://svn.boost.org/trac/boost/ticket/8277 #8277]. +* Fixed bugs [@https://svn.boost.org/trac/boost/ticket/7156 #7156], + [@https://svn.boost.org/trac/boost/ticket/7164 #7164], + [@https://svn.boost.org/trac/boost/ticket/8277 #8277], + [@https://svn.boost.org/trac/boost/ticket/8976 #8976], + [@https://svn.boost.org/trac/boost/ticket/9065 #9065], + [@https://svn.boost.org/trac/boost/ticket/9073 #9073], + [@https://svn.boost.org/trac/boost/ticket/8277 #9908]. [endsect] diff --git a/include/boost/interprocess/detail/atomic.hpp b/include/boost/interprocess/detail/atomic.hpp index 08481a4..fb56891 100644 --- a/include/boost/interprocess/detail/atomic.hpp +++ b/include/boost/interprocess/detail/atomic.hpp @@ -213,7 +213,7 @@ inline boost::uint32_t atomic_cas32 "bne- 1b\n\t" "2:" : "=&r"(prev) - : "b" (mem), "r"(cmp), "r" (with) + : "b" (mem), "r" (with), "r" (cmp) : "cc", "memory"); return prev; } diff --git a/include/boost/interprocess/detail/intermodule_singleton_common.hpp b/include/boost/interprocess/detail/intermodule_singleton_common.hpp index 485f98d..60ec593 100644 --- a/include/boost/interprocess/detail/intermodule_singleton_common.hpp +++ b/include/boost/interprocess/detail/intermodule_singleton_common.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -145,7 +146,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; + spin_wait swait; while(1){ previous_module_singleton_initialized = atomic_read32(&this_module_singleton_initialized); if(previous_module_singleton_initialized >= Initialized){ @@ -153,7 +154,7 @@ class intermodule_singleton_common break; } else if(previous_module_singleton_initialized == Initializing){ - yield(k++); + swait.yield(); } else{ //This can't be happening! @@ -207,7 +208,7 @@ class intermodule_singleton_common static void initialize_global_map_handle() { //Obtain unique map name and size - unsigned k = 0; + spin_wait swait; while(1){ //Try to pass map state to initializing ::boost::uint32_t tmp = atomic_cas32(&this_module_map_initialized, Initializing, Uninitialized); @@ -220,7 +221,7 @@ class intermodule_singleton_common } //If some other thread is doing the work wait else if(tmp == Initializing){ - yield(k++); + swait.yield(); } 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 389f9f2..948b4f4 100644 --- a/include/boost/interprocess/detail/managed_open_or_create_impl.hpp +++ b/include/boost/interprocess/detail/managed_open_or_create_impl.hpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -354,7 +355,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; + spin_wait swait; while(!completed){ try{ create_device(dev, id, size, perm, file_like_t()); @@ -385,7 +386,7 @@ class managed_open_or_create_impl catch(...){ throw; } - yield(k++); + swait.yield(); } } @@ -432,12 +433,12 @@ class managed_open_or_create_impl else{ if(FileBased){ offset_t filesize = 0; - unsigned k = 0; + spin_wait swait; 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())); } - yield(k++); + swait.yield(); } if(filesize == 1){ throw interprocess_exception(error_info(corrupted_error)); @@ -449,9 +450,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; + spin_wait swait; while(value == InitializingSegment || value == UninitializedSegment){ - yield(k++); + swait.yield(); 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 dd86ba0..32e019d 100644 --- a/include/boost/interprocess/detail/os_thread_functions.hpp +++ b/include/boost/interprocess/detail/os_thread_functions.hpp @@ -15,18 +15,36 @@ #include #include #include -#include +#include #if defined(BOOST_INTERPROCESS_WINDOWS) # include #else -# ifdef BOOST_HAS_UNISTD_H -# include -# include -# include -# include +# include +# include +# include +# include +# ifdef BOOST_INTERPROCESS_BSD_DERIVATIVE + //Some *BSD systems (OpenBSD & NetBSD) need sys/param.h before sys/sysctl.h, whereas + //others (FreeBSD & Darwin) need sys/types.h +# include +# include +# include +# endif +//According to the article "C/C++ tip: How to measure elapsed real time for benchmarking" +# if defined(CLOCK_MONOTONIC_PRECISE) //BSD +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_PRECISE +# elif defined(CLOCK_MONOTONIC_RAW) //Linux +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC_RAW +# elif defined(CLOCK_HIGHRES) //Solaris +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_HIGHRES +# elif defined(CLOCK_MONOTONIC) //POSIX (AIX, BSD, Linux, Solaris) +# define BOOST_INTERPROCESS_CLOCK_MONOTONIC CLOCK_MONOTONIC +# elif !defined(CLOCK_MONOTONIC) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) +# include // mach_absolute_time, mach_timebase_info_data_t +# define BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME # else -# error Unknown platform +# error "No high resolution steady clock in your system, please provide a patch" # endif #endif @@ -57,6 +75,75 @@ inline OS_thread_id_t get_invalid_thread_id() inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) { return id1 == id2; } +//return the system tick in ns +inline unsigned long get_system_tick_ns() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)*100ul; +} + +//return the system tick in us +inline unsigned long get_system_tick_us() +{ + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Windows API returns the value in hundreds of ns + return (curres - 1ul)/10ul + 1ul; +} + +typedef unsigned __int64 OS_highres_count_t; + +inline OS_highres_count_t get_system_tick_in_highres_counts() +{ + __int64 freq; + unsigned long curres; + winapi::set_timer_resolution(10000, 0, &curres); + //Frequency in counts per second + if(!winapi::query_performance_frequency(&freq)){ + //Tick resolution in ms + return (curres-1)/10000u + 1; + } + else{ + //In femtoseconds + __int64 count_fs = __int64(1000000000000000LL - 1LL)/freq + 1LL; + __int64 tick_counts = (__int64(curres)*100000000LL - 1LL)/count_fs + 1LL; + return static_cast(tick_counts); + } +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + __int64 count; + if(!winapi::query_performance_counter(&count)){ + count = winapi::get_tick_count(); + } + return count; +} + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +inline void thread_sleep_tick() +{ winapi::sleep_tick(); } + inline void thread_yield() { winapi::sched_yield(); } @@ -98,6 +185,13 @@ inline long double get_current_process_creation_time() CreationTime.dwLowDateTime*resolution; } +inline unsigned int get_num_cores() +{ + winapi::system_info sysinfo; + winapi::get_system_info( &sysinfo ); + //in Windows dw is long which is equal in bits to int + return static_cast(sysinfo.dwNumberOfProcessors); +} #else //#if (defined BOOST_INTERPROCESS_WINDOWS) @@ -165,9 +259,132 @@ inline bool equal_thread_id(OS_thread_id_t id1, OS_thread_id_t id2) inline void thread_yield() { ::sched_yield(); } +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME +typedef struct timespec OS_highres_count_t; +#else +typedef unsigned long long OS_highres_count_t; +#endif + +inline unsigned long get_system_tick_ns() +{ + #ifdef _SC_CLK_TCK + long hz =::sysconf(_SC_CLK_TCK); // ticks per sec + if(hz <= 0){ //Try a typical value on error + hz = 100; + } + return 999999999ul/static_cast(hz)+1ul; + #else + #error "Can't obtain system tick value for your system, please provide a patch" + #endif +} + +inline OS_highres_count_t get_system_tick_in_highres_counts() +{ + #ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = get_system_tick_ns(); + return ts; + #else + mach_timebase_info_data_t info; + mach_timebase_info(&info); + //ns + return static_cast + ( + static_cast(get_system_tick_ns()) + / (static_cast(info.numer) / info.denom) + ); + #endif +} + +//return system ticks in us +inline unsigned long get_system_tick_us() +{ + return (get_system_tick_ns()-1)/1000ul + 1ul; +} + +inline OS_highres_count_t get_current_system_highres_count() +{ + #if defined(BOOST_INTERPROCESS_CLOCK_MONOTONIC) + struct timespec count; + ::clock_gettime(BOOST_INTERPROCESS_CLOCK_MONOTONIC, &count); + return count; + #elif defined(BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME) + return ::mach_absolute_time(); + #endif +} + +#ifndef BOOST_INTERPROCESS_MATCH_ABSOLUTE_TIME + +inline void zero_highres_count(OS_highres_count_t &count) +{ count.tv_sec = 0; count.tv_nsec = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count.tv_sec == 0 && count.tv_nsec == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count.tv_sec << "s:" << count.tv_nsec << "ns"; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ + OS_highres_count_t res; + + if (l.tv_nsec < r.tv_nsec){ + res.tv_nsec = 1000000000 + l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - 1 - r.tv_sec; + } + else{ + res.tv_nsec = l.tv_nsec - r.tv_nsec; + res.tv_sec = l.tv_sec - r.tv_sec; + } + + return res; +} + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l.tv_sec < r.tv_sec || (l.tv_sec == r.tv_sec && l.tv_nsec < r.tv_nsec); } + +#else + +inline void zero_highres_count(OS_highres_count_t &count) +{ count = 0; } + +inline bool is_highres_count_zero(const OS_highres_count_t &count) +{ return count == 0; } + +template +inline Ostream &ostream_highres_count(Ostream &ostream, const OS_highres_count_t &count) +{ + ostream << count ; + return ostream; +} + +inline OS_highres_count_t system_highres_count_subtract(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l - r; } + +inline bool system_highres_count_less(const OS_highres_count_t &l, const OS_highres_count_t &r) +{ return l < r; } + +#endif + +inline void thread_sleep_tick() +{ + struct timespec rqt; + //Sleep for the half of the tick time + rqt.tv_sec = 0; + rqt.tv_nsec = get_system_tick_ns()/2; + ::nanosleep(&rqt, 0); +} + inline void thread_sleep(unsigned int ms) { - const struct timespec rqt = { ms/1000u, (ms%1000u)*1000000u }; + struct timespec rqt; + rqt.tv_sec = ms/1000u; + rqt.tv_nsec = (ms%1000u)*1000000u; ::nanosleep(&rqt, 0); } @@ -190,6 +407,39 @@ inline OS_systemwide_thread_id_t get_invalid_systemwide_thread_id() inline long double get_current_process_creation_time() { return 0.0L; } +inline unsigned int get_num_cores() +{ + #ifdef _SC_NPROCESSORS_ONLN + long cores = ::sysconf(_SC_NPROCESSORS_ONLN); + // sysconf returns -1 if the name is invalid, the option does not exist or + // does not have a definite limit. + // if sysconf returns some other negative number, we have no idea + // what is going on. Default to something safe. + if(cores <= 0){ + return 1; + } + //Check for overflow (unlikely) + else if(static_cast(cores) >= + static_cast(static_cast(-1))){ + return static_cast(-1); + } + else{ + return static_cast(cores); + } + #elif defined(BOOST_INTERPROCESS_BSD_DERIVATIVE) && defined(HW_NCPU) + int request[2] = { CTL_HW, HW_NCPU }; + int num_cores; + std::size_t result_len = sizeof(num_cores); + if ( (::sysctl (request, 2, &num_cores, &result_len, 0, 0) < 0) || (num_cores <= 0) ){ + //Return a safe value + return 1; + } + else{ + return static_cast(num_cores); + } + #endif +} + #endif //#if (defined BOOST_INTERPROCESS_WINDOWS) typedef char pid_str_t[sizeof(OS_process_id_t)*3+1]; diff --git a/include/boost/interprocess/detail/robust_emulation.hpp b/include/boost/interprocess/detail/robust_emulation.hpp index 5722589..e0866dc 100644 --- a/include/boost/interprocess/detail/robust_emulation.hpp +++ b/include/boost/interprocess/detail/robust_emulation.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include namespace boost{ @@ -228,7 +229,7 @@ inline void robust_spin_mutex::lock() //Now the logic. Try to lock, if successful mark the owner //if it fails, start recovery logic - unsigned int spin_count = 0; + spin_wait swait; while(1){ if (mtx.try_lock()){ atomic_write32(&this->owner, get_current_process_id()); @@ -236,14 +237,10 @@ inline void robust_spin_mutex::lock() } else{ //Do the dead owner checking each spin_threshold lock tries - yield(spin_count); - ++spin_count; - if(spin_count > spin_threshold){ + swait.yield(); + if(0 == (swait.count() & 255u)){ //Check if owner dead and take ownership if possible - if(!this->robust_check()){ - spin_count = 0; - } - else{ + if(this->robust_check()){ break; } } @@ -292,7 +289,7 @@ inline bool robust_spin_mutex::timed_lock if(now >= abs_time) return this->try_lock(); - unsigned k = 0; + spin_wait swait; do{ if(this->try_lock()){ break; @@ -303,7 +300,7 @@ inline bool robust_spin_mutex::timed_lock return this->try_lock(); } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); }while (true); return true; diff --git a/include/boost/interprocess/detail/tmp_dir_helpers.hpp b/include/boost/interprocess/detail/tmp_dir_helpers.hpp index e4e867e..2af1a8a 100644 --- a/include/boost/interprocess/detail/tmp_dir_helpers.hpp +++ b/include/boost/interprocess/detail/tmp_dir_helpers.hpp @@ -58,7 +58,7 @@ namespace ipcdetail { struct ::timeval result; std::size_t result_len = sizeof result; - if (::sysctl (request, 2, &result, &result_len, NULL, 0) < 0) + if (::sysctl (request, 2, &result, &result_len, 0, 0) < 0) return; char bootstamp_str[256]; diff --git a/include/boost/interprocess/detail/win32_api.hpp b/include/boost/interprocess/detail/win32_api.hpp index 4bffb51..67b5c13 100644 --- a/include/boost/interprocess/detail/win32_api.hpp +++ b/include/boost/interprocess/detail/win32_api.hpp @@ -883,6 +883,7 @@ extern "C" __declspec(dllimport) int __stdcall GetProcessTimes , interprocess_filetime *lpExitTime,interprocess_filetime *lpKernelTime , interprocess_filetime *lpUserTime ); extern "C" __declspec(dllimport) void __stdcall Sleep(unsigned long); +extern "C" __declspec(dllimport) unsigned long __stdcall GetTickCount(void); extern "C" __declspec(dllimport) int __stdcall SwitchToThread(); extern "C" __declspec(dllimport) unsigned long __stdcall GetLastError(); extern "C" __declspec(dllimport) void __stdcall SetLastError(unsigned long); @@ -943,7 +944,6 @@ extern "C" __declspec(dllimport) int __stdcall FreeLibrary(void *); extern "C" __declspec(dllimport) void *__stdcall GetProcAddress(void *, const char*); extern "C" __declspec(dllimport) void *__stdcall GetModuleHandleA(const char*); extern "C" __declspec(dllimport) void *__stdcall GetFileInformationByHandle(void *, interprocess_by_handle_file_information*); -extern "C" __declspec(dllimport) int __stdcall QueryPerformanceCounter(__int64 *lpPerformanceCount); //Advapi32.dll extern "C" __declspec(dllimport) long __stdcall RegOpenKeyExA(void *, const char *, unsigned long, unsigned long, void **); @@ -1013,6 +1013,12 @@ typedef long (__stdcall *NtQuerySection_t)(void*, section_information_class, int typedef long (__stdcall *NtQueryInformationFile_t)(void *,io_status_block_t *,void *, long, int); typedef long (__stdcall *NtOpenFile_t)(void*,unsigned long ,object_attributes_t*,io_status_block_t*,unsigned long,unsigned long); typedef long (__stdcall *NtClose_t) (void*); +typedef long (__stdcall *NtQueryTimerResolution_t) (unsigned long* LowestResolution, unsigned long* HighestResolution, unsigned long* CurrentResolution); +typedef long (__stdcall *NtSetTimerResolution_t) (unsigned long RequestedResolution, int Set, unsigned long* ActualResolution); + +//kernel32.dll +typedef int (__stdcall *QueryPerformanceCounter_t) (__int64 *lpPerformanceCount); +typedef int (__stdcall *QueryPerformanceFrequency_t)(__int64 *lpFrequency); } //namespace winapi { } //namespace interprocess { @@ -1047,10 +1053,13 @@ inline unsigned long make_lang_id(unsigned long p, unsigned long s) inline void sched_yield() { if(!SwitchToThread()){ - Sleep(1); + Sleep(0); } } +inline void sleep_tick() +{ Sleep(1); } + inline void sleep(unsigned long ms) { Sleep(ms); } @@ -1270,11 +1279,6 @@ inline long reg_query_value_ex(void *hKey, const char *lpValueName, unsigned lon inline long reg_close_key(void *hKey) { return RegCloseKey(hKey); } -inline bool query_performance_counter(__int64 *lpPerformanceCount) -{ - return 0 != QueryPerformanceCounter(lpPerformanceCount); -} - inline void initialize_object_attributes ( object_attributes_t *pobject_attr, unicode_string_t *name , unsigned long attr, void *rootdir, void *security_descr) @@ -1299,8 +1303,20 @@ inline void rtl_init_empty_unicode_string(unicode_string_t *ucStr, wchar_t *buf, template struct function_address_holder { - enum { NtSetInformationFile, NtQuerySystemInformation, NtQueryObject, NtQuerySemaphore, NtQuerySection, NtOpenFile, NtClose, NumFunction }; - enum { NtDll_dll, NumModule }; + enum { NtSetInformationFile + , NtQuerySystemInformation + , NtQueryObject + , NtQuerySemaphore + , NtQuerySection + , NtOpenFile + , NtClose + , NtQueryTimerResolution + , NtSetTimerResolution + , QueryPerformanceCounter + , QueryPerformanceFrequency + , NumFunction + }; + enum { NtDll_dll, Kernel32_dll, NumModule }; private: static const char *FunctionNames[NumFunction]; @@ -1314,21 +1330,26 @@ struct function_address_holder static void *get_module_from_id(unsigned int id) { BOOST_ASSERT(id < (unsigned int)NumModule); - return get_module_handle(ModuleNames[id]); + void *addr = get_module_handle(ModuleNames[id]); + BOOST_ASSERT(addr); + return addr; } static void *get_module(const unsigned int id) { BOOST_ASSERT(id < (unsigned int)NumModule); - while(ModuleStates[id] < 2){ + for(unsigned i = 0; ModuleStates[id] < 2; ++i){ if(interlocked_compare_exchange(&ModuleStates[id], 1, 0) == 0){ ModuleAddresses[id] = get_module_from_id(id); interlocked_increment(&ModuleStates[id]); break; } - else{ + else if(i & 1){ sched_yield(); } + else{ + sleep_tick(); + } } return ModuleAddresses[id]; } @@ -1336,22 +1357,27 @@ struct function_address_holder static void *get_address_from_dll(const unsigned int id) { BOOST_ASSERT(id < (unsigned int)NumFunction); - return get_proc_address(get_module(FunctionModules[id]), FunctionNames[id]); + void *addr = get_proc_address(get_module(FunctionModules[id]), FunctionNames[id]); + BOOST_ASSERT(addr); + return addr; } public: static void *get(const unsigned int id) { BOOST_ASSERT(id < (unsigned int)NumFunction); - while(FunctionStates[id] < 2){ + for(unsigned i = 0; FunctionStates[id] < 2; ++i){ if(interlocked_compare_exchange(&FunctionStates[id], 1, 0) == 0){ FunctionAddresses[id] = get_address_from_dll(id); interlocked_increment(&FunctionStates[id]); break; } - else{ + else if(i & 1){ sched_yield(); } + else{ + sleep_tick(); + } } return FunctionAddresses[id]; } @@ -1366,7 +1392,11 @@ const char *function_address_holder::FunctionNames[function_address_holde "NtQuerySemaphore", "NtQuerySection", "NtOpenFile", - "NtClose" + "NtClose", + "NtQueryTimerResolution", + "NtSetTimerResolution", + "QueryPerformanceCounter", + "QueryPerformanceFrequency" }; template @@ -1378,13 +1408,18 @@ unsigned int function_address_holder::FunctionModules[function_address_ho NtDll_dll, NtDll_dll, NtDll_dll, - NtDll_dll + NtDll_dll, + NtDll_dll, + NtDll_dll, + Kernel32_dll, + Kernel32_dll }; template const char *function_address_holder::ModuleNames[function_address_holder::NumModule] = { - "ntdll.dll" + "ntdll.dll", + "kernel32.dll" }; @@ -1549,7 +1584,7 @@ class nt_query_mem_deleter delete[]m_buf; } - void realloc(std::size_t num_bytes) + void realloc_mem(std::size_t num_bytes) { num_bytes += rename_suffix + rename_offset; char *buf = m_buf; @@ -1584,7 +1619,7 @@ class c_heap_deleter if(m_buf) ::free(m_buf); } - void realloc(std::size_t num_bytes) + void realloc_mem(std::size_t num_bytes) { void *buf = ::realloc(m_buf, num_bytes); if(!buf){ @@ -1639,7 +1674,7 @@ inline bool unlink_file(const char *filename) //Obtain file name with guessed length if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){ //Obtain file name with exact length buffer - nt_query_mem.realloc(size); + nt_query_mem.realloc_mem(size); if(pNtQueryObject(fh, object_name_information, nt_query_mem.query_mem(), nt_query_mem.object_name_information_size(), &size)){ return false; } @@ -2021,7 +2056,7 @@ inline bool get_last_bootup_time(std::string &stamp) if (error_insufficient_buffer == status) { status = 0; dwBytesToRead = dwMinimumBytesToRead; - heap_deleter.realloc(dwMinimumBytesToRead); + heap_deleter.realloc_mem(dwMinimumBytesToRead); if (!heap_deleter.get()){ return false; } @@ -2065,11 +2100,8 @@ inline bool get_file_mapping_size(void *file_mapping_hnd, __int64 &size) interprocess_section_basic_information info; unsigned long ntstatus = pNtQuerySection(file_mapping_hnd, section_basic_information, &info, sizeof(info), 0); - if(ntstatus){ - return false; - } size = info.section_size; - return true; + return !ntstatus; } inline bool get_semaphore_info(void *handle, long &count, long &limit) @@ -2079,14 +2111,41 @@ inline bool get_semaphore_info(void *handle, long &count, long &limit) (winapi::NtQuerySemaphore_t)dll_func::get(winapi::dll_func::NtQuerySemaphore); unsigned int ret_len; long status = pNtQuerySemaphore(handle, winapi::semaphore_basic_information, &info, sizeof(info), &ret_len); - if(status){ - return false; - } count = info.count; limit = info.limit; - return true; + return !status; } +inline bool query_timer_resolution(unsigned long *lowres, unsigned long *highres, unsigned long *curres) +{ + winapi::NtQueryTimerResolution_t pNtQueryTimerResolution = + (winapi::NtQueryTimerResolution_t)dll_func::get(winapi::dll_func::NtQueryTimerResolution); + return !pNtQueryTimerResolution(lowres, highres, curres); +} + +inline bool set_timer_resolution(unsigned long RequestedResolution, int Set, unsigned long* ActualResolution) +{ + winapi::NtSetTimerResolution_t pNtSetTimerResolution = + (winapi::NtSetTimerResolution_t)dll_func::get(winapi::dll_func::NtSetTimerResolution); + return !pNtSetTimerResolution(RequestedResolution, Set, ActualResolution); +} + +inline bool query_performance_counter(__int64 *lpPerformanceCount) +{ + QueryPerformanceCounter_t pQueryPerformanceCounter = (QueryPerformanceCounter_t) + dll_func::get(dll_func::QueryPerformanceCounter); + return 0 != pQueryPerformanceCounter(lpPerformanceCount); +} + +inline bool query_performance_frequency(__int64 *lpFrequency) +{ + QueryPerformanceCounter_t pQueryPerformanceFrequency = (QueryPerformanceFrequency_t) + dll_func::get(dll_func::QueryPerformanceFrequency); + return 0 != pQueryPerformanceFrequency(lpFrequency); +} + +inline unsigned long get_tick_count() +{ return GetTickCount(); } } //namespace winapi } //namespace interprocess diff --git a/include/boost/interprocess/detail/yield_k.hpp b/include/boost/interprocess/detail/yield_k.hpp deleted file mode 100644 index bf05865..0000000 --- a/include/boost/interprocess/detail/yield_k.hpp +++ /dev/null @@ -1,136 +0,0 @@ -//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/smart_ptr/detail/sp_counted_impl.hpp b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp index 2d29ae6..d5142fa 100644 --- a/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp +++ b/include/boost/interprocess/smart_ptr/detail/sp_counted_impl.hpp @@ -83,6 +83,8 @@ class sp_counted_impl_pd portable_rebind_alloc < const this_type >::type const_this_allocator; typedef typename this_allocator::pointer this_pointer; + typedef typename boost::intrusive:: + pointer_traits this_pointer_traits; sp_counted_impl_pd( sp_counted_impl_pd const & ); sp_counted_impl_pd & operator= ( sp_counted_impl_pd const & ); @@ -115,11 +117,10 @@ class sp_counted_impl_pd void destroy() // nothrow { - //Self destruction, so get a copy of the allocator - //(in the future we could move it) - this_allocator a_copy(*this); + //Self destruction, so move the allocator + this_allocator a_copy(::boost::move(static_cast(*this))); BOOST_ASSERT(a_copy == *this); - this_pointer this_ptr (this); + this_pointer this_ptr(this_pointer_traits::pointer_to(*this)); //Do it now! scoped_ptr< this_type, scoped_ptr_dealloc_functor > deleter_ptr(this_ptr, a_copy); diff --git a/include/boost/interprocess/streams/bufferstream.hpp b/include/boost/interprocess/streams/bufferstream.hpp index 9a2681a..404880d 100644 --- a/include/boost/interprocess/streams/bufferstream.hpp +++ b/include/boost/interprocess/streams/bufferstream.hpp @@ -251,8 +251,11 @@ class basic_bufferbuf //!A basic_istream class that uses a fixed size character buffer //!as its formatting buffer. template -class basic_ibufferstream - : public std::basic_istream +class basic_ibufferstream : + /// @cond + private basic_bufferbuf, + /// @endcond + public std::basic_istream { public: // Typedefs typedef typename std::basic_ios @@ -262,24 +265,40 @@ class basic_ibufferstream typedef typename std::basic_ios::off_type off_type; typedef typename std::basic_ios::traits_type traits_type; + /// @cond private: - typedef std::basic_ios basic_ios_t; - typedef std::basic_istream base_t; + typedef basic_bufferbuf bufferbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_istream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } + /// @endcond public: //!Constructor. //!Does not throw. basic_ibufferstream(std::ios_base::openmode mode = std::ios_base::in) - : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::in) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode | std::ios_base::in) + , base_t(&get_buf()) + {} //!Constructor. Assigns formatting buffer. //!Does not throw. basic_ibufferstream(const CharT *buf, std::size_t length, std::ios_base::openmode mode = std::ios_base::in) - : basic_ios_t(), base_t(0), - m_buf(const_cast(buf), length, mode | std::ios_base::in) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(const_cast(buf), length, mode | std::ios_base::in) + , base_t(&get_buf()) + {} ~basic_ibufferstream(){}; @@ -287,29 +306,27 @@ class basic_ibufferstream //!Returns the address of the stored //!stream buffer. basic_bufferbuf* rdbuf() const - { return const_cast*>(&m_buf); } + { return const_cast*>(&get_buf()); } //!Returns the pointer and size of the internal buffer. //!Does not throw. std::pair buffer() const - { return m_buf.buffer(); } + { return get_buf().buffer(); } //!Sets the underlying buffer to a new value. Resets //!stream position. Does not throw. void buffer(const CharT *buf, std::size_t length) - { m_buf.buffer(const_cast(buf), length); } - - /// @cond - private: - basic_bufferbuf m_buf; - /// @endcond + { get_buf().buffer(const_cast(buf), length); } }; //!A basic_ostream class that uses a fixed size character buffer //!as its formatting buffer. template -class basic_obufferstream - : public std::basic_ostream +class basic_obufferstream : + /// @cond + private basic_bufferbuf, + /// @endcond + public std::basic_ostream { public: typedef typename std::basic_ios @@ -321,23 +338,38 @@ class basic_obufferstream /// @cond private: + typedef basic_bufferbuf bufferbuf_t; typedef std::basic_ios basic_ios_t; typedef std::basic_ostream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } /// @endcond + public: //!Constructor. //!Does not throw. basic_obufferstream(std::ios_base::openmode mode = std::ios_base::out) - : basic_ios_t(), base_t(0), m_buf(mode | std::ios_base::out) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode | std::ios_base::out) + , base_t(&get_buf()) + {} //!Constructor. Assigns formatting buffer. //!Does not throw. basic_obufferstream(CharT *buf, std::size_t length, std::ios_base::openmode mode = std::ios_base::out) - : basic_ios_t(), base_t(0), - m_buf(buf, length, mode | std::ios_base::out) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(buf, length, mode | std::ios_base::out) + , base_t(&get_buf()) + {} ~basic_obufferstream(){} @@ -345,31 +377,28 @@ class basic_obufferstream //!Returns the address of the stored //!stream buffer. basic_bufferbuf* rdbuf() const - { return const_cast*>(&m_buf); } + { return const_cast*>(&get_buf()); } //!Returns the pointer and size of the internal buffer. //!Does not throw. std::pair buffer() const - { return m_buf.buffer(); } + { return get_buf().buffer(); } //!Sets the underlying buffer to a new value. Resets //!stream position. Does not throw. void buffer(CharT *buf, std::size_t length) - { m_buf.buffer(buf, length); } - - /// @cond - private: - basic_bufferbuf m_buf; - /// @endcond + { get_buf().buffer(buf, length); } }; //!A basic_iostream class that uses a fixed size character buffer //!as its formatting buffer. template -class basic_bufferstream - : public std::basic_iostream - +class basic_bufferstream : + /// @cond + private basic_bufferbuf, + /// @endcond + public std::basic_iostream { public: // Typedefs typedef typename std::basic_ios @@ -381,8 +410,11 @@ class basic_bufferstream /// @cond private: - typedef std::basic_ios basic_ios_t; - typedef std::basic_iostream base_t; + typedef basic_bufferbuf bufferbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream base_t; + bufferbuf_t & get_buf() { return *this; } + const bufferbuf_t & get_buf() const{ return *this; } /// @endcond public: @@ -390,16 +422,28 @@ class basic_bufferstream //!Does not throw. basic_bufferstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : basic_ios_t(), base_t(0), m_buf(mode) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(mode) + , base_t(&get_buf()) + {} //!Constructor. Assigns formatting buffer. //!Does not throw. basic_bufferstream(CharT *buf, std::size_t length, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : basic_ios_t(), base_t(0), m_buf(buf, length, mode) - { basic_ios_t::init(&m_buf); } + : //basic_ios_t() is called first (lefting it uninitialized) as it's a + //virtual base of basic_istream. The class will be initialized when + //basic_istream is constructed calling basic_ios_t::init(). + //As bufferbuf_t's constructor does not throw there is no risk of + //calling the basic_ios_t's destructor without calling basic_ios_t::init() + bufferbuf_t(buf, length, mode) + , base_t(&get_buf()) + {} ~basic_bufferstream(){} @@ -407,22 +451,17 @@ class basic_bufferstream //!Returns the address of the stored //!stream buffer. basic_bufferbuf* rdbuf() const - { return const_cast*>(&m_buf); } + { return const_cast*>(&get_buf()); } //!Returns the pointer and size of the internal buffer. //!Does not throw. std::pair buffer() const - { return m_buf.buffer(); } + { return get_buf().buffer(); } //!Sets the underlying buffer to a new value. Resets //!stream position. Does not throw. void buffer(CharT *buf, std::size_t length) - { m_buf.buffer(buf, length); } - - /// @cond - private: - basic_bufferbuf m_buf; - /// @endcond + { get_buf().buffer(buf, length); } }; //Some typedefs to simplify usage diff --git a/include/boost/interprocess/streams/vectorstream.hpp b/include/boost/interprocess/streams/vectorstream.hpp index 0c9f540..25dc5db 100644 --- a/include/boost/interprocess/streams/vectorstream.hpp +++ b/include/boost/interprocess/streams/vectorstream.hpp @@ -92,8 +92,6 @@ class basic_vectorbuf : base_t(), m_mode(mode), m_vect(param) { this->initialize_pointers(); } - virtual ~basic_vectorbuf(){} - public: //!Swaps the underlying vector with the passed vector. @@ -367,10 +365,10 @@ class basic_vectorbuf //!boost::interprocess::basic_string template class basic_ivectorstream + : public std::basic_istream /// @cond - : private basic_vectorbuf + , private basic_vectorbuf /// @endcond - , public std::basic_istream { public: typedef CharVector vector_type; @@ -384,56 +382,62 @@ class basic_ivectorstream /// @cond private: typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; typedef std::basic_istream base_t; - vectorbuf_t & m_buf() { return *this; } - const vectorbuf_t & m_buf() const{ return *this; } + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf() const{ return *this; } /// @endcond public: + //!Constructor. Throws if vector_type default //!constructor throws. basic_ivectorstream(std::ios_base::openmode mode = std::ios_base::in) - : vectorbuf_t(mode | std::ios_base::in), base_t(&m_buf()) - {} + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode | std::ios_base::in) + { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_ivectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::in) - : vectorbuf_t(param, mode | std::ios_base::in), base_t(&m_buf()) + : vectorbuf_t(param, mode | std::ios_base::in) + //basic_ios_t() is constructed uninitialized as virtual base + //and initialized inside base_t calling basic_ios::init() + , base_t(&get_buf()) {} - ~basic_ivectorstream(){}; - public: //!Returns the address of the stored //!stream buffer. basic_vectorbuf* rdbuf() const - { return const_cast*>(&m_buf()); } + { return const_cast*>(&get_buf()); } //!Swaps the underlying vector with the passed vector. //!This function resets the read position in the stream. //!Does not throw. void swap_vector(vector_type &vect) - { m_buf().swap_vector(vect); } + { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const - { return m_buf().vector(); } + { return get_buf().vector(); } //!Calls reserve() method of the internal vector. //!Resets the stream to the first position. //!Throws if the internals vector's reserve throws. void reserve(typename vector_type::size_type size) - { m_buf().reserve(size); } + { get_buf().reserve(size); } //!Calls clear() method of the internal vector. //!Resets the stream to the first position. void clear() - { m_buf().clear(); } + { get_buf().clear(); } }; //!A basic_ostream class that holds a character vector specified by CharVector @@ -442,10 +446,10 @@ class basic_ivectorstream //!boost::interprocess::basic_string template class basic_ovectorstream + : public std::basic_ostream /// @cond - : private basic_vectorbuf + , private basic_vectorbuf /// @endcond - , public std::basic_ostream { public: typedef CharVector vector_type; @@ -459,54 +463,58 @@ class basic_ovectorstream /// @cond private: typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; typedef std::basic_ostream base_t; - vectorbuf_t & m_buf() { return *this; } - const vectorbuf_t & m_buf()const { return *this; } + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf()const { return *this; } /// @endcond public: //!Constructor. Throws if vector_type default //!constructor throws. basic_ovectorstream(std::ios_base::openmode mode = std::ios_base::out) - : vectorbuf_t(mode | std::ios_base::out), base_t(&m_buf()) - {} + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode | std::ios_base::out) + { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_ovectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::out) - : vectorbuf_t(param, mode | std::ios_base::out), base_t(&m_buf()) - {} - - ~basic_ovectorstream(){} + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(param, mode | std::ios_base::out) + { this->base_t::rdbuf(&get_buf()); } public: //!Returns the address of the stored //!stream buffer. basic_vectorbuf* rdbuf() const - { return const_cast*>(&m_buf()); } + { return const_cast*>(&get_buf()); } //!Swaps the underlying vector with the passed vector. //!This function resets the write position in the stream. //!Does not throw. void swap_vector(vector_type &vect) - { m_buf().swap_vector(vect); } + { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const - { return m_buf().vector(); } + { return get_buf().vector(); } //!Calls reserve() method of the internal vector. //!Resets the stream to the first position. //!Throws if the internals vector's reserve throws. void reserve(typename vector_type::size_type size) - { m_buf().reserve(size); } + { get_buf().reserve(size); } }; - //!A basic_iostream class that holds a character vector specified by CharVector //!template parameter as its formatting buffer. The vector must have //!contiguous storage, like std::vector, boost::interprocess::vector or @@ -514,7 +522,9 @@ class basic_ovectorstream template class basic_vectorstream : public std::basic_iostream - + /// @cond + , private basic_vectorbuf + /// @endcond { public: typedef CharVector vector_type; @@ -527,8 +537,12 @@ class basic_vectorstream /// @cond private: - typedef std::basic_ios basic_ios_t; - typedef std::basic_iostream base_t; + typedef basic_vectorbuf vectorbuf_t; + typedef std::basic_ios basic_ios_t; + typedef std::basic_iostream base_t; + + vectorbuf_t & get_buf() { return *this; } + const vectorbuf_t & get_buf() const{ return *this; } /// @endcond public: @@ -536,50 +550,49 @@ class basic_vectorstream //!constructor throws. basic_vectorstream(std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : basic_ios_t(), base_t(0), m_buf(mode) - { basic_ios_t::init(&m_buf); } + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(mode) + { this->base_t::rdbuf(&get_buf()); } //!Constructor. Throws if vector_type(const VectorParameter ¶m) //!throws. template basic_vectorstream(const VectorParameter ¶m, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) - : basic_ios_t(), base_t(0), m_buf(param, mode) - { basic_ios_t::init(&m_buf); } - - ~basic_vectorstream(){} + : base_t(0) //Initializes first the base class to safely init the virtual basic_ios base + //(via basic_ios::init() call in base_t's constructor) without the risk of a + //previous throwing vectorbuf constructor. Set the streambuf after risk has gone. + , vectorbuf_t(param, mode) + { this->base_t::rdbuf(&get_buf()); } public: //Returns the address of the stored stream buffer. basic_vectorbuf* rdbuf() const - { return const_cast*>(&m_buf); } + { return const_cast*>(&get_buf()); } //!Swaps the underlying vector with the passed vector. //!This function resets the read/write position in the stream. //!Does not throw. void swap_vector(vector_type &vect) - { m_buf.swap_vector(vect); } + { get_buf().swap_vector(vect); } //!Returns a const reference to the internal vector. //!Does not throw. const vector_type &vector() const - { return m_buf.vector(); } + { return get_buf().vector(); } //!Calls reserve() method of the internal vector. //!Resets the stream to the first position. //!Throws if the internals vector's reserve throws. void reserve(typename vector_type::size_type size) - { m_buf.reserve(size); } + { get_buf().reserve(size); } //!Calls clear() method of the internal vector. //!Resets the stream to the first position. void clear() - { m_buf.clear(); } - - /// @cond - private: - basic_vectorbuf m_buf; - /// @endcond + { get_buf().clear(); } }; //Some typedefs to simplify usage diff --git a/include/boost/interprocess/sync/file_lock.hpp b/include/boost/interprocess/sync/file_lock.hpp index 81fd817..1b4dd39 100644 --- a/include/boost/interprocess/sync/file_lock.hpp +++ b/include/boost/interprocess/sync/file_lock.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include //!\file @@ -149,7 +150,7 @@ class file_lock using namespace boost::detail; if(now >= abs_time) return false; - unsigned k = 0; + spin_wait swait; do{ if(!ipcdetail::try_acquire_file_lock(hnd, acquired)) return false; @@ -164,7 +165,7 @@ class file_lock return true; } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); } }while (true); } @@ -178,7 +179,7 @@ class file_lock if(now >= abs_time) return false; - unsigned k = 0; + spin_wait swait; do{ if(!ipcdetail::try_acquire_file_lock_sharable(hnd, acquired)) return false; @@ -193,7 +194,7 @@ class file_lock return true; } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); } }while (true); } diff --git a/include/boost/interprocess/sync/posix/mutex.hpp b/include/boost/interprocess/sync/posix/mutex.hpp index 13c2f48..6bc45ca 100644 --- a/include/boost/interprocess/sync/posix/mutex.hpp +++ b/include/boost/interprocess/sync/posix/mutex.hpp @@ -44,6 +44,7 @@ #ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS # include +# include #endif #include @@ -119,7 +120,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; + spin_wait swait; do{ if(this->try_lock()){ break; @@ -130,7 +131,7 @@ inline bool posix_mutex::timed_lock(const boost::posix_time::ptime &abs_time) return false; } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); }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 4fd06dc..ce2ad68 100644 --- a/include/boost/interprocess/sync/posix/recursive_mutex.hpp +++ b/include/boost/interprocess/sync/posix/recursive_mutex.hpp @@ -38,6 +38,7 @@ #include #ifndef BOOST_INTERPROCESS_POSIX_TIMEOUTS # include +# include #endif #include @@ -108,7 +109,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; + spin_wait swait; do{ if(this->try_lock()){ break; @@ -119,7 +120,7 @@ inline bool posix_recursive_mutex::timed_lock(const boost::posix_time::ptime &ab return false; } // relinquish current time slice - yield(k++); + swait.yield(); }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 3e18d60..98cb128 100644 --- a/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp +++ b/include/boost/interprocess/sync/posix/semaphore_wrapper.hpp @@ -35,6 +35,7 @@ #include #else #include +#include #endif namespace boost { @@ -195,11 +196,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; + spin_wait swait; do{ if(semaphore_try_wait(handle)) return true; - yield(k++); + swait.yield(); }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 641bf7f..be86333 100644 --- a/include/boost/interprocess/sync/spin/condition.hpp +++ b/include/boost/interprocess/sync/spin/condition.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -140,9 +141,9 @@ inline void spin_condition::notify(boost::uint32_t command) } //Notify that all threads should execute wait logic - unsigned k = 0; + spin_wait swait; while(SLEEP != atomic_cas32(const_cast(&m_command), command, SLEEP)){ - yield(k++); + swait.yield(); } //The enter mutex will rest locked until the last waiting thread unlocks it } @@ -206,9 +207,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; + spin_wait swait; while(atomic_read32(&m_command) == SLEEP){ - yield(k++); + swait.yield(); //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 fc43a9c..7a77549 100644 --- a/include/boost/interprocess/sync/spin/mutex.hpp +++ b/include/boost/interprocess/sync/spin/mutex.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace boost { namespace interprocess { @@ -60,7 +61,7 @@ inline spin_mutex::~spin_mutex() inline void spin_mutex::lock(void) { - unsigned k = 0; + spin_wait swait; do{ boost::uint32_t prev_s = ipcdetail::atomic_cas32(const_cast(&m_s), 1, 0); @@ -68,7 +69,7 @@ inline void spin_mutex::lock(void) break; } // relinquish current timeslice - ipcdetail::yield(k++); + swait.yield(); }while (true); } @@ -87,7 +88,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; + spin_wait swait; do{ if(this->try_lock()){ break; @@ -98,7 +99,7 @@ inline bool spin_mutex::timed_lock(const boost::posix_time::ptime &abs_time) return false; } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); }while (true); return true; diff --git a/include/boost/interprocess/sync/spin/semaphore.hpp b/include/boost/interprocess/sync/spin/semaphore.hpp index a209d36..4b16235 100644 --- a/include/boost/interprocess/sync/spin/semaphore.hpp +++ b/include/boost/interprocess/sync/spin/semaphore.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace boost { @@ -59,11 +60,9 @@ inline void spin_semaphore::post() inline void spin_semaphore::wait() { - unsigned k = 0; + spin_wait swait; while(!ipcdetail::atomic_add_unless32(&m_count, boost::uint32_t(-1), boost::uint32_t(0))){ - while(ipcdetail::atomic_read32(&m_count) == 0){ - ipcdetail::yield(k++); - } + swait.yield(); } } @@ -81,7 +80,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; + spin_wait swait; do{ if(this->try_wait()){ break; @@ -92,7 +91,7 @@ inline bool spin_semaphore::timed_wait(const boost::posix_time::ptime &abs_time) return this->try_wait(); } // relinquish current time slice - ipcdetail::yield(k++); + swait.yield(); }while (true); return true; } diff --git a/include/boost/interprocess/sync/spin/wait.hpp b/include/boost/interprocess/sync/spin/wait.hpp new file mode 100644 index 0000000..1bf28f3 --- /dev/null +++ b/include/boost/interprocess/sync/spin/wait.hpp @@ -0,0 +1,186 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Peter Dimov 2008. +// (C) Copyright Ion Gaztanaga 2013. 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) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +//Parts of this file come from boost/smart_ptr/detail/yield_k.hpp +//Many thanks to Peter Dimov. + +#ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED +#define BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include + +//#define BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG +#include +#endif + +// 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 + +namespace boost{ +namespace interprocess{ +namespace ipcdetail { + +template +class num_core_holder +{ + public: + static unsigned int get() + { + if(!num_cores){ + return ipcdetail::get_num_cores(); + } + else{ + return num_cores; + } + } + + private: + static unsigned int num_cores; +}; + +template +unsigned int num_core_holder::num_cores = ipcdetail::get_num_cores(); + +} //namespace ipcdetail { + +class spin_wait +{ + public: + spin_wait() + : m_k(0u) + { + (void)m_nop_pause_limit; + (void)m_yield_only_counts; + (void)m_count_start; + } + + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + ~spin_wait() + { + if(m_k){ + std::cout << "final m_k: " << m_k + << " system tick(us): " << ipcdetail::get_system_tick_us() << std::endl; + } + } + #endif + + unsigned int count() const + { return m_k; } + + void yield() + { + //Lazy initialization of limits + if( !m_k){ + this->init_limits(); + } + //Nop tries + if( m_k < (m_nop_pause_limit >> 2) ){ + + } + //Pause tries if the processor supports it + #if defined(BOOST_INTERPROCESS_SMT_PAUSE) + else if( m_k < m_nop_pause_limit ){ + BOOST_INTERPROCESS_SMT_PAUSE + } + #endif + //Yield/Sleep strategy + else{ + //Lazy initialization of tick information + if(m_k == m_nop_pause_limit){ + this->init_tick_info(); + } + else if( this->yield_or_sleep() ){ + ipcdetail::thread_yield(); + } + else{ + ipcdetail::thread_sleep_tick(); + } + } + ++m_k; + } + + void reset() + { + m_k = 0u; + m_count_start = ipcdetail::get_current_system_highres_count(); + } + + private: + + void init_limits() + { + unsigned int num_cores = ipcdetail::num_core_holder<0>::get(); + m_nop_pause_limit = num_cores > 1u ? 32u : 0u; + } + + void init_tick_info() + { + m_yield_only_counts = ipcdetail::get_system_tick_in_highres_counts(); + m_count_start = ipcdetail::get_current_system_highres_count(); + } + + //Returns true if yield must be called, false is sleep must be called + bool yield_or_sleep() + { + if(ipcdetail::is_highres_count_zero(m_yield_only_counts)){ //If yield-only limit was reached then yield one in every two tries + return (m_k & 1u) != 0; + } + else{ //Try to see if we've reched yield-only time limit + const ipcdetail::OS_highres_count_t now = ipcdetail::get_current_system_highres_count(); + const ipcdetail::OS_highres_count_t elapsed = ipcdetail::system_highres_count_subtract(now, m_count_start); + if(!ipcdetail::system_highres_count_less(elapsed, m_yield_only_counts)){ + #ifdef BOOST_INTERPROCESS_SPIN_WAIT_DEBUG + std::cout << "elapsed!\n" + << " m_yield_only_counts: "; + ipcdetail::ostream_highres_count(std::cout, m_yield_only_counts) + << " system tick(us): " << ipcdetail::get_system_tick_us() << '\n' + << " m_k: " << m_k << " elapsed counts: "; + ipcdetail::ostream_highres_count(std::cout, elapsed) << std::endl; + #endif + //Yield-only time reached, now it's time to sleep + ipcdetail::zero_highres_count(m_yield_only_counts); + return false; + } + } + return true; //Otherwise yield + } + + unsigned int m_k; + unsigned int m_nop_pause_limit; + ipcdetail::OS_highres_count_t m_yield_only_counts; + ipcdetail::OS_highres_count_t m_count_start; +}; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // #ifndef BOOST_INTERPROCESS_SYNC_WAIT_HPP_INCLUDED diff --git a/test/bufferstream_test.cpp b/test/bufferstream_test.cpp index 58d9d05..7f82521 100644 --- a/test/bufferstream_test.cpp +++ b/test/bufferstream_test.cpp @@ -33,7 +33,7 @@ static int bufferstream_test() const int BufSize = 10001; //This will be zero-initialized static char buffer [BufSize]; - bufferstream bufstream;; + bufferstream bufstream; std::stringstream std_stringstream; std::string str1, str2, str3("testline:"); int number1, number2; diff --git a/test/robust_mutex_test.hpp b/test/robust_mutex_test.hpp index 3ec0cb5..09688c3 100644 --- a/test/robust_mutex_test.hpp +++ b/test/robust_mutex_test.hpp @@ -16,6 +16,7 @@ #include //std::system #include #include +#include #include "get_process_id_name.hpp" #include "mutex_test_template.hpp" #include @@ -66,9 +67,9 @@ int robust_mutex_test(int argc, char *argv[]) return 1; //Wait until child locks the mutexes and dies - unsigned k = 0; + spin_wait swait; while(!*go_ahead){ - ipcdetail::yield(k++); + swait.yield(); } std::cout << "... recovering mutex[0]" << std::endl; @@ -164,9 +165,9 @@ int robust_mutex_test(int argc, char *argv[]) } //Wait until child locks the 2nd mutex and dies - unsigned k = 0; + spin_wait swait; while(!*go_ahead2){ - ipcdetail::yield(k++); + swait.yield(); } //Done, now try to lock number 3 to see if robust