diff --git a/include/boost/smart_ptr/detail/sp_thread_pause.hpp b/include/boost/smart_ptr/detail/sp_thread_pause.hpp new file mode 100644 index 0000000..2cddd90 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_thread_pause.hpp @@ -0,0 +1,51 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/smart_ptr/detail/sp_thread_pause.hpp +// +// inline void bost::detail::sp_thread_pause(); +// +// Emits a "pause" instruction. +// +// Copyright 2008, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0 +// https://www.boost.org/LICENSE_1_0.txt + +#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) && !defined(__c2__) + +extern "C" void _mm_pause(); + +#define BOOST_SP_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_SP_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#else + +#define BOOST_SP_PAUSE + +#endif + +namespace boost +{ +namespace detail +{ + +inline void sp_thread_pause() +{ + BOOST_SP_PAUSE +} + +} // namespace detail +} // namespace boost + +#undef BOOST_SP_PAUSE + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_thread_sleep.hpp b/include/boost/smart_ptr/detail/sp_thread_sleep.hpp new file mode 100644 index 0000000..ff1d168 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_thread_sleep.hpp @@ -0,0 +1,104 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/smart_ptr/detail/sp_thread_sleep.hpp +// +// inline void bost::detail::sp_thread_sleep(); +// +// Cease execution for a while to yield to other threads, +// as if by calling nanosleep() with an appropriate interval. +// +// Copyright 2008, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0 +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined( __CYGWIN__ ) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using Sleep(1) in sp_thread_sleep") +#endif + +#include + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_sleep() +{ + Sleep( 1 ); +} + +} // namespace detail + +} // namespace boost + +#elif defined(BOOST_HAS_NANOSLEEP) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using nanosleep() in sp_thread_sleep") +#endif + +#include + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_sleep() +{ + // 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 detail + +} // namespace boost + +#else + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using sp_thread_yield() in sp_thread_sleep") +#endif + +#include + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_sleep() +{ + sp_thread_yield(); +} + +} // namespace detail + +} // namespace boost + +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_thread_yield.hpp b/include/boost/smart_ptr/detail/sp_thread_yield.hpp new file mode 100644 index 0000000..9a221cc --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_thread_yield.hpp @@ -0,0 +1,100 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/smart_ptr/detail/sp_thread_yield.hpp +// +// inline void bost::detail::sp_thread_yield(); +// +// Gives up the remainder of the time slice, +// as if by calling sched_yield(). +// +// Copyright 2008, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0 +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include + +#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined( __CYGWIN__ ) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using Sleep(0) in sp_thread_yield") +#endif + +#include + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_yield() +{ + Sleep( 0 ); +} + +} // namespace detail + +} // namespace boost + +#elif defined(BOOST_HAS_SCHED_YIELD) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using sched_yield() in sp_thread_yield") +#endif + +#ifndef _AIX +# include +#else + // AIX's sched.h defines ::var which sometimes conflicts with Lambda's var + extern "C" int sched_yield(void); +#endif + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_yield() +{ + sched_yield(); +} + +} // namespace detail + +} // namespace boost + +#else + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using sp_thread_pause() in sp_thread_yield") +#endif + +#include + +namespace boost +{ + +namespace detail +{ + +inline void sp_thread_yield() +{ + sp_thread_pause(); +} + +} // namespace detail + +} // namespace boost + +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_win32_sleep.hpp b/include/boost/smart_ptr/detail/sp_win32_sleep.hpp new file mode 100644 index 0000000..139a569 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_win32_sleep.hpp @@ -0,0 +1,49 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/smart_ptr/detail/sp_win32_sleep.hpp +// +// Declares the Win32 Sleep() function. +// +// Copyright 2008, 2020 Peter Dimov +// Distributed under the Boost Software License, Version 1.0 +// https://www.boost.org/LICENSE_1_0.txt + +#if defined( BOOST_USE_WINDOWS_H ) +# include +#endif + +namespace boost +{ +namespace detail +{ + +#if !defined( BOOST_USE_WINDOWS_H ) + +#if defined(__clang__) && defined(__x86_64__) +// clang x64 warns that __stdcall is ignored +# define BOOST_SP_STDCALL +#else +# define BOOST_SP_STDCALL __stdcall +#endif + +#if defined(__LP64__) // Cygwin 64 + extern "C" __declspec(dllimport) void BOOST_SP_STDCALL Sleep( unsigned int ms ); +#else + extern "C" __declspec(dllimport) void BOOST_SP_STDCALL Sleep( unsigned long ms ); +#endif + +#undef BOOST_SP_STDCALL + +#endif // !defined( BOOST_USE_WINDOWS_H ) + +} // namespace detail +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/yield_k.hpp b/include/boost/smart_ptr/detail/yield_k.hpp index 8f52a58..d9a1b46 100644 --- a/include/boost/smart_ptr/detail/yield_k.hpp +++ b/include/boost/smart_ptr/detail/yield_k.hpp @@ -7,50 +7,21 @@ # pragma once #endif +// boost/smart_ptr/detail/yield_k.hpp // -// yield_k.hpp +// Copyright 2008, 2020 Peter Dimov // -// Copyright (c) 2008 Peter Dimov +// inline void boost::detail::yield( unsigned k ); // -// 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 +// Typical use: +// for( unsigned k = 0; !try_lock(); ++k ) yield( k ); // +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +#include +#include #include -#include - -// BOOST_SMT_PAUSE - -#if defined(_MSC_VER) && _MSC_VER >= 1310 && ( defined(_M_IX86) || defined(_M_X64) ) && !defined(__c2__) - -extern "C" void _mm_pause(); - -#define BOOST_SMT_PAUSE _mm_pause(); - -#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) - -#define BOOST_SMT_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); - -#else - -#define BOOST_SMT_PAUSE - -#endif - -// - -#if defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) || defined( __CYGWIN__ ) - -#if defined( BOOST_USE_WINDOWS_H ) -# include -#endif namespace boost { @@ -58,133 +29,14 @@ namespace boost namespace detail { -#if !defined( BOOST_USE_WINDOWS_H ) - -#if defined(__clang__) && defined(__x86_64__) -// clang x64 warns that __stdcall is ignored -# define BOOST_SP_STDCALL -#else -# define BOOST_SP_STDCALL __stdcall -#endif - -#if defined(__LP64__) // Cygwin 64 - extern "C" __declspec(dllimport) void BOOST_SP_STDCALL Sleep( unsigned int ms ); -#else - extern "C" __declspec(dllimport) void BOOST_SP_STDCALL Sleep( unsigned long ms ); -#endif - -#undef BOOST_SP_STDCALL - -#endif // !defined( BOOST_USE_WINDOWS_H ) - -#if defined(BOOST_SP_REPORT_IMPLEMENTATION) - BOOST_PRAGMA_MESSAGE("Using Win32 yield_k") -#endif - -inline void sp_thread_yield() +inline void yield( unsigned k ) { - Sleep( 0 ); -} + // Experiments on Windows and Fedora 32 show that a single pause, + // followed by an immediate sp_thread_sleep(), is best. -inline void sp_thread_sleep() -{ - Sleep( 1 ); -} - -} // namespace detail - -} // namespace boost - -#elif defined( BOOST_HAS_PTHREADS ) - -#ifndef _AIX -#include -#else - // AIX's sched.h defines ::var which sometimes conflicts with Lambda's var - extern "C" int sched_yield(void); -#endif - -#include - -namespace boost -{ - -namespace detail -{ - -#if defined(BOOST_SP_REPORT_IMPLEMENTATION) - BOOST_PRAGMA_MESSAGE("Using POSIX yield_k") -#endif - -inline void sp_thread_yield() -{ - sched_yield(); -} - -inline void sp_thread_sleep() -{ - // 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 detail - -} // namespace boost - -#else - -#if defined(BOOST_SP_REPORT_IMPLEMENTATION) - BOOST_PRAGMA_MESSAGE("Using empty yield_k") -#endif - -namespace boost -{ - -namespace detail -{ - -inline void sp_thread_yield() -{ - BOOST_SMT_PAUSE -} - -inline void sp_thread_sleep() -{ - BOOST_SMT_PAUSE -} - -} // namespace detail - -} // namespace boost - -#endif - -namespace boost -{ - -namespace detail -{ - -inline void yield( unsigned k ) BOOST_NOEXCEPT -{ - // Experiments show that a simple sp_thread_sleep() here is best; - // leave a few pause instructions out of mostly superstition. - // (These are verified to not degrade performance.) - // - // There seems to be no benefit from calling sp_thread_yield() - // at any time. - - if( k < 8 ) + if( k == 0 ) { - BOOST_SMT_PAUSE + sp_thread_pause(); } else {