diff --git a/include/boost/core/detail/sp_thread_pause.hpp b/include/boost/core/detail/sp_thread_pause.hpp new file mode 100644 index 0000000..4301488 --- /dev/null +++ b/include/boost/core/detail/sp_thread_pause.hpp @@ -0,0 +1,51 @@ +#ifndef BOOST_CORE_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED +#define BOOST_CORE_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/core/detail/sp_thread_pause.hpp +// +// inline void bost::core::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_CORE_SP_PAUSE _mm_pause(); + +#elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) ) + +#define BOOST_CORE_SP_PAUSE __asm__ __volatile__( "rep; nop" : : : "memory" ); + +#else + +#define BOOST_CORE_SP_PAUSE + +#endif + +namespace boost +{ +namespace core +{ + +inline void sp_thread_pause() +{ + BOOST_CORE_SP_PAUSE +} + +} // namespace core +} // namespace boost + +#undef BOOST_SP_PAUSE + +#endif // #ifndef BOOST_CORE_DETAIL_SP_THREAD_PAUSE_HPP_INCLUDED diff --git a/include/boost/core/detail/sp_thread_sleep.hpp b/include/boost/core/detail/sp_thread_sleep.hpp new file mode 100644 index 0000000..d18da23 --- /dev/null +++ b/include/boost/core/detail/sp_thread_sleep.hpp @@ -0,0 +1,104 @@ +#ifndef BOOST_CORE_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED +#define BOOST_CORE_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/core/detail/sp_thread_sleep.hpp +// +// inline void bost::core::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( __CYGWIN__ ) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using Sleep(1) in sp_thread_sleep") +#endif + +#include + +namespace boost +{ +namespace core +{ +namespace detail +{ + +inline void sp_thread_sleep() +{ + Sleep( 1 ); +} + +} // namespace detail + +using boost::core::detail::sp_thread_sleep; + +} // namespace core +} // 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 core +{ + +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 core +} // 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 core +{ + +inline void sp_thread_sleep() +{ + sp_thread_yield(); +} + +} // namespace core +} // namespace boost + +#endif + +#endif // #ifndef BOOST_CORE_DETAIL_SP_THREAD_SLEEP_HPP_INCLUDED diff --git a/include/boost/core/detail/sp_thread_yield.hpp b/include/boost/core/detail/sp_thread_yield.hpp new file mode 100644 index 0000000..c19e7e6 --- /dev/null +++ b/include/boost/core/detail/sp_thread_yield.hpp @@ -0,0 +1,100 @@ +#ifndef BOOST_CORE_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED +#define BOOST_CORE_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/core/detail/sp_thread_yield.hpp +// +// inline void bost::core::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( __CYGWIN__ ) + +#if defined(BOOST_SP_REPORT_IMPLEMENTATION) + BOOST_PRAGMA_MESSAGE("Using Sleep(0) in sp_thread_yield") +#endif + +#include + +namespace boost +{ +namespace core +{ +namespace detail +{ + +inline void sp_thread_yield() +{ + Sleep( 0 ); +} + +} // namespace detail + +using boost::core::detail::sp_thread_yield; + +} // namespace core +} // 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 core +{ + +inline void sp_thread_yield() +{ + sched_yield(); +} + +} // namespace core +} // 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 core +{ + +inline void sp_thread_yield() +{ + sp_thread_pause(); +} + +} // namespace core +} // namespace boost + +#endif + +#endif // #ifndef BOOST_CORE_DETAIL_SP_THREAD_YIELD_HPP_INCLUDED diff --git a/include/boost/core/detail/sp_win32_sleep.hpp b/include/boost/core/detail/sp_win32_sleep.hpp new file mode 100644 index 0000000..df51292 --- /dev/null +++ b/include/boost/core/detail/sp_win32_sleep.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_CORE_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED +#define BOOST_CORE_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/core/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 core +{ +namespace detail +{ + +#if !defined( BOOST_USE_WINDOWS_H ) + +#if defined(__clang__) && defined(__x86_64__) +// clang x64 warns that __stdcall is ignored +# define BOOST_CORE_SP_STDCALL +#else +# define BOOST_CORE_SP_STDCALL __stdcall +#endif + +#if defined(__LP64__) // Cygwin 64 + extern "C" __declspec(dllimport) void BOOST_CORE_SP_STDCALL Sleep( unsigned int ms ); +#else + extern "C" __declspec(dllimport) void BOOST_CORE_SP_STDCALL Sleep( unsigned long ms ); +#endif + +#undef BOOST_CORE_SP_STDCALL + +#endif // !defined( BOOST_USE_WINDOWS_H ) + +} // namespace detail +} // namespace core +} // namespace boost + +#endif // #ifndef BOOST_CORE_DETAIL_SP_WIN32_SLEEP_HPP_INCLUDED diff --git a/include/boost/core/yield_primitives.hpp b/include/boost/core/yield_primitives.hpp new file mode 100644 index 0000000..899453e --- /dev/null +++ b/include/boost/core/yield_primitives.hpp @@ -0,0 +1,12 @@ +#ifndef BOOST_CORE_YIELD_PRIMITIVES_HPP_INCLUDED +#define BOOST_CORE_YIELD_PRIMITIVES_HPP_INCLUDED + +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +#endif // #ifndef BOOST_CORE_YIELD_PRIMITIVES_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 5f79241..83d9d46 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -386,5 +386,10 @@ run serialization_construct_data_test.cpp : : : /boost//serialization/< run identity_test.cpp ; run identity_rvalue_test.cpp ; +run sp_thread_pause_test.cpp ; +run sp_thread_yield_test.cpp ; +run sp_thread_sleep_test.cpp ; +run yield_prim_windows_h_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/sp_thread_pause_test.cpp b/test/sp_thread_pause_test.cpp new file mode 100644 index 0000000..1bbd0c0 --- /dev/null +++ b/test/sp_thread_pause_test.cpp @@ -0,0 +1,15 @@ +// Test for sp_thread_pause +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +int main() +{ + for( int i = 0; i < 1048576; ++i ) + { + boost::core::sp_thread_pause(); + } +} diff --git a/test/sp_thread_sleep_test.cpp b/test/sp_thread_sleep_test.cpp new file mode 100644 index 0000000..2ee84ed --- /dev/null +++ b/test/sp_thread_sleep_test.cpp @@ -0,0 +1,15 @@ +// Test for sp_thread_sleep +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +int main() +{ + for( int i = 0; i < 1000; ++i ) + { + boost::core::sp_thread_sleep(); + } +} diff --git a/test/sp_thread_yield_test.cpp b/test/sp_thread_yield_test.cpp new file mode 100644 index 0000000..81d3f70 --- /dev/null +++ b/test/sp_thread_yield_test.cpp @@ -0,0 +1,15 @@ +// Test for sp_thread_yield +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include + +int main() +{ + for( int i = 0; i < 10000; ++i ) + { + boost::core::sp_thread_yield(); + } +} diff --git a/test/yield_prim_windows_h_test.cpp b/test/yield_prim_windows_h_test.cpp new file mode 100644 index 0000000..50f841f --- /dev/null +++ b/test/yield_prim_windows_h_test.cpp @@ -0,0 +1,18 @@ +// Test for sp_thread_yield +// +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include +#endif + +#include + +int main() +{ + boost::core::sp_thread_pause(); + boost::core::sp_thread_yield(); + boost::core::sp_thread_sleep(); +}