diff --git a/include/boost/detail/spinlock.hpp b/include/boost/detail/spinlock.hpp new file mode 100644 index 0000000..605fccb --- /dev/null +++ b/include/boost/detail/spinlock.hpp @@ -0,0 +1,43 @@ +#ifndef BOOST_DETAIL_SPINLOCK_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// boost/detail/spinlock.hpp +// +// Copyright (c) 2008 Peter Dimov +// +// 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) +// +// struct spinlock +// { +// void lock(); +// bool try_lock(); +// void unlock(); +// +// class scoped_lock; +// }; +// +// #define BOOST_DETAIL_SPINLOCK_INIT +// + +#include + +#if defined(__GNUC__) && ( __GNUC__ * 100 + __GNUC_MINOR__ >= 401 ) +# include +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Unrecognized threading platform +#endif + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_pt.hpp b/include/boost/detail/spinlock_pt.hpp new file mode 100644 index 0000000..dfb2d6f --- /dev/null +++ b/include/boost/detail/spinlock_pt.hpp @@ -0,0 +1,79 @@ +#ifndef BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + pthread_mutex_t v_; + +public: + + bool try_lock() + { + return pthread_mutex_trylock( &v_ ) == 0; + } + + void lock() + { + pthread_mutex_lock( &v_ ); + } + + void unlock() + { + pthread_mutex_unlock( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT { PTHREAD_MUTEX_INITIALIZER } + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_PT_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_sync.hpp b/include/boost/detail/spinlock_sync.hpp new file mode 100644 index 0000000..d602365 --- /dev/null +++ b/include/boost/detail/spinlock_sync.hpp @@ -0,0 +1,83 @@ +#ifndef BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + int v_; + +public: + + bool try_lock() + { + int r = __sync_lock_test_and_set( &v_, 1 ); + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { + __sync_lock_release( &v_ ); + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_SYNC_HPP_INCLUDED diff --git a/include/boost/detail/spinlock_w32.hpp b/include/boost/detail/spinlock_w32.hpp new file mode 100644 index 0000000..5d0b824 --- /dev/null +++ b/include/boost/detail/spinlock_w32.hpp @@ -0,0 +1,98 @@ +#ifndef BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED +#define BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// Copyright (c) 2008 Peter Dimov +// +// 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 + +#if defined( _MSC_VER ) && _MSC_VER >= 1310 + extern "C" void _ReadWriteBarrier(); +# pragma intrinsic( _ReadWriteBarrier ) +#endif + +namespace boost +{ + +namespace detail +{ + +class spinlock +{ +public: + + long v_; + +public: + + bool try_lock() + { + long r = BOOST_INTERLOCKED_EXCHANGE( &v_, 1 ); + +#if defined( _MSC_VER ) && _MSC_VER >= 1310 + _ReadWriteBarrier(); +#endif + + return r == 0; + } + + void lock() + { + for( unsigned k = 0; !try_lock(); ++k ) + { + boost::detail::yield( k ); + } + } + + void unlock() + { +#if defined( _MSC_VER ) && _MSC_VER >= 1310 + _ReadWriteBarrier(); +#endif + + *const_cast< long volatile* >( &v_ ) = 0; + } + +public: + + class scoped_lock + { + private: + + spinlock & sp_; + + scoped_lock( scoped_lock const & ); + scoped_lock & operator=( scoped_lock const & ); + + public: + + explicit scoped_lock( spinlock & sp ): sp_( sp ) + { + sp.lock(); + } + + ~scoped_lock() + { + sp_.unlock(); + } + }; +}; + +} // namespace detail +} // namespace boost + +#define BOOST_DETAIL_SPINLOCK_INIT {0} + +#endif // #ifndef BOOST_DETAIL_SPINLOCK_W32_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 13109da..d3b92a3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -38,5 +38,6 @@ import testing ; [ run esft_regtest.cpp ] [ run esft_constructor_test.cpp ] [ run yield_k_test.cpp ] + [ run spinlock_test.cpp ] ; } diff --git a/test/spinlock_test.cpp b/test/spinlock_test.cpp new file mode 100644 index 0000000..faec048 --- /dev/null +++ b/test/spinlock_test.cpp @@ -0,0 +1,46 @@ +// +// spinlock_test.cpp +// +// Copyright 2008 Peter Dimov +// +// 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 + +// Sanity check only + +static boost::detail::spinlock sp = BOOST_DETAIL_SPINLOCK_INIT; +static boost::detail::spinlock sp2 = BOOST_DETAIL_SPINLOCK_INIT; + +int main() +{ + BOOST_TEST( sp.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( sp2.try_lock() ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + sp.lock(); + BOOST_TEST( !sp.try_lock() ); + sp2.lock(); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + sp.unlock(); + sp2.unlock(); + + { + boost::detail::spinlock::scoped_lock lock( sp ); + BOOST_TEST( !sp.try_lock() ); + boost::detail::spinlock::scoped_lock lock2( sp2 ); + BOOST_TEST( !sp.try_lock() ); + BOOST_TEST( !sp2.try_lock() ); + } + + return boost::report_errors(); +}