00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00053 #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_HPP_SPIN_MUTEX
00054 #define UNIXSTL_INCL_UNIXSTL_SYNCH_HPP_SPIN_MUTEX
00055
00056 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00057 # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SPIN_MUTEX_MAJOR 5
00058 # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SPIN_MUTEX_MINOR 0
00059 # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SPIN_MUTEX_REVISION 3
00060 # define UNIXSTL_VER_UNIXSTL_SYNCH_HPP_SPIN_MUTEX_EDIT 60
00061 #endif
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
00078 # include <unixstl/unixstl.h>
00079 #endif
00080 #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_UTIL_H_FEATURES
00081 # include <unixstl/synch/util/features.h>
00082 #endif
00083 #ifndef UNIXSTL_HAS_ATOMIC_INTEGER_OPERATIONS
00084 # error unixstl/synch/spin_mutex.hpp requires support for atomic integer operations. Consult unixstl/synch/util/features.h for details
00085 #endif
00086 #ifndef UNIXSTL_INCL_UNIXSTL_SYNCH_H_ATOMIC_FUNCTIONS
00087 # include <unixstl/synch/atomic_functions.h>
00088 #endif
00089 #ifndef STLSOFT_INCL_STLSOFT_SYNCH_HPP_CONCEPTS
00090 # include <stlsoft/synch/concepts.hpp>
00091 #endif
00092 #ifndef STLSOFT_INCL_STLSOFT_SYNCH_HPP_SPIN_POLICIES
00093 # include <stlsoft/synch/spin_policies.hpp>
00094 #endif
00095
00096 #ifndef STLSOFT_INCL_H_SCHED
00097 # define STLSOFT_INCL_H_SCHED
00098 # include <sched.h>
00099 #endif
00100
00101 #ifdef STLSOFT_UNITTEST
00102 # include <stlsoft/synch/lock_scope.hpp>
00103 #endif
00104
00105 #if defined(_DEBUG)
00106 # define STLSOFT_SPINMUTEX_COUNT_LOCKS
00107 #endif
00108
00109
00110
00111
00112
00113 #ifndef _UNIXSTL_NO_NAMESPACE
00114 # if defined(_STLSOFT_NO_NAMESPACE) || \
00115 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00116
00117 namespace unixstl
00118 {
00119 # else
00120
00121
00122 namespace stlsoft
00123 {
00124
00125 namespace unixstl_project
00126 {
00127
00128 # endif
00129 #endif
00130
00131
00132
00133
00134
00135
00144 template <ss_typename_param_k SP>
00145 class spin_mutex_base
00146 : public stlsoft_ns_qual(critical_section)< STLSOFT_CRITICAL_SECTION_ISNOT_RECURSIVE
00147 , STLSOFT_CRITICAL_SECTION_ISNOT_TRYABLE
00148 >
00149 {
00152 private:
00154 typedef SP spin_policy_class;
00155 public:
00157 typedef spin_mutex_base<SP> class_type;
00159 typedef unixstl_ns_qual(atomic_int_t) atomic_int_type;
00161 typedef us_sint32_t count_type;
00163 typedef us_bool_t bool_type;
00165
00168 public:
00169 #ifdef __SYNSOFT_DBS_COMPILER_SUPPORTS_PRAGMA_MESSAGE
00170 # pragma message(_sscomp_fileline_message("Create stlsoft/synch/spin_mutex_base.hpp, and factor out"))
00171 #endif
00172
00179 ss_explicit_k spin_mutex_base(atomic_int_type *p = NULL) stlsoft_throw_0()
00180 : m_spinCount((NULL != p) ? p : &m_internalCount)
00181 , m_internalCount(0)
00182 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00183 , m_cLocks(0)
00184 #endif // STLSOFT_SPINMUTEX_COUNT_LOCKS
00185 , m_spunCount(0)
00186 , m_bYieldOnSpin(spin_policy_class::value)
00187 {}
00193 spin_mutex_base(atomic_int_type *p, bool_type bYieldOnSpin) stlsoft_throw_0()
00194 : m_spinCount((NULL != p) ? p : &m_internalCount)
00195 , m_internalCount(0)
00196 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00197 , m_cLocks(0)
00198 #endif
00199 , m_spunCount(0)
00200 , m_bYieldOnSpin(bYieldOnSpin)
00201 {}
00203 ~spin_mutex_base() stlsoft_throw_0()
00204 {
00205 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00206 UNIXSTL_ASSERT(0 == m_cLocks);
00207 #endif // STLSOFT_SPINMUTEX_COUNT_LOCKS
00208 }
00210
00213 public:
00215 void lock() stlsoft_throw_0()
00216 {
00217 #ifdef UNIXSTL_SPINMUTEX_CHECK_INIT
00218
00219
00220
00221
00222 if(NULL == m_spinCount)
00223 {
00224 m_spinCount = &m_internalCount;
00225 }
00226 #endif
00227
00228 UNIXSTL_MESSAGE_ASSERT("A global instance of spin_mutex has skipped dynamic initialisation. You must #define UNIXSTL_SPINMUTEX_CHECK_INIT if your compilation causes dynamic initialisation to be skipped.", NULL != m_spinCount);
00229
00230 #if defined(UNIXSTL_OS_IS_LINUX) && \
00231 !defined(UNIXSTL_ARCH_IS_INTEL)
00232 for(m_spunCount = 1; 0 != ::atomic_inc_and_test(m_spinCount); ++m_spunCount)
00233 #elif defined(UNIXSTL_OS_IS_MACOSX)
00234 for(m_spunCount = 1; !::OSAtomicCompareAndSwap32Barrier(0, 1, m_spinCount); ++m_spunCount)
00235 #elif defined(UNIXSTL_HAS_ATOMIC_WRITE)
00236 for(m_spunCount = 1; 0 != atomic_write(m_spinCount, 1); ++m_spunCount)
00237 #else
00238 # error Your platform does not support atomic_write(), or has provides it in a manner unknown to the authors of UNIXSTL. If you know of the correct implementation, please send a patch.
00239 #endif
00240 {
00241 if(m_bYieldOnSpin)
00242 {
00243 ::sched_yield();
00244 }
00245 }
00246
00247 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00248 UNIXSTL_ASSERT(0 != ++m_cLocks);
00249 #endif // STLSOFT_SPINMUTEX_COUNT_LOCKS
00250 }
00252 void unlock() stlsoft_throw_0()
00253 {
00254 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00255 UNIXSTL_ASSERT(m_cLocks-- != 0);
00256 #endif // STLSOFT_SPINMUTEX_COUNT_LOCKS
00257
00258 m_spunCount = 0;
00259
00260 #if defined(UNIXSTL_OS_IS_LINUX) && \
00261 !defined(UNIXSTL_ARCH_IS_INTEL)
00262 ::atomic_dec(m_spinCount);
00263 #elif defined(UNIXSTL_OS_IS_MACOSX)
00264 ::OSAtomicDecrement32Barrier(m_spinCount);
00265 #else
00266 atomic_write(m_spinCount, 0);
00267 #endif
00268 }
00270
00273 public:
00285 count_type spun_count() const
00286 {
00287 return m_spunCount;
00288 }
00290
00293 private:
00294 atomic_int_type *m_spinCount;
00295 atomic_int_type m_internalCount;
00296 #ifdef STLSOFT_SPINMUTEX_COUNT_LOCKS
00297 count_type m_cLocks;
00298 #endif // STLSOFT_SPINMUTEX_COUNT_LOCKS
00299 count_type m_spunCount;
00300 const bool_type m_bYieldOnSpin;
00302
00305 private:
00306 spin_mutex_base(class_type const& rhs);
00307 class_type& operator =(class_type const& rhs);
00309 };
00310
00311 typedef spin_mutex_base<stlsoft_ns_qual(spin_yield)> spin_mutex_yield;
00312 typedef spin_mutex_base<stlsoft_ns_qual(spin_no_yield)> spin_mutex_no_yield;
00313
00314 #ifdef STLSOFT_OLD_SPIN_MUTEX_BEHAVIOUR
00315 typedef spin_mutex_no_yield spin_mutex;
00316 #else
00317 typedef spin_mutex_yield spin_mutex;
00318 #endif
00319
00320
00321
00322
00323
00324 #ifndef _UNIXSTL_NO_NAMESPACE
00325 # if defined(_STLSOFT_NO_NAMESPACE) || \
00326 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00327 }
00328 # else
00329 }
00330 # endif
00331 #endif
00332
00339 template <ss_typename_param_k SP>
00340 inline void lock_instance(unixstl_ns_qual(spin_mutex_base)<SP> &mx)
00341 {
00342 mx.lock();
00343 }
00344
00351 template <ss_typename_param_k SP>
00352 inline void unlock_instance(unixstl_ns_qual(spin_mutex_base)<SP> &mx)
00353 {
00354 mx.unlock();
00355 }
00356
00357
00358 #ifndef _UNIXSTL_NO_NAMESPACE
00359 # if defined(_STLSOFT_NO_NAMESPACE) || \
00360 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00361 namespace unixstl
00362 {
00363 # else
00364 namespace unixstl_project
00365 {
00366 # if defined(STLSOFT_COMPILER_IS_BORLAND)
00367 using ::stlsoft::lock_instance;
00368 using ::stlsoft::unlock_instance;
00369 # endif
00370 # endif
00371 #endif
00372
00373
00374
00375
00376
00377
00382 struct spin_mutex_lock_traits
00383 {
00384 public:
00386 typedef spin_mutex lock_type;
00387 typedef spin_mutex_lock_traits class_type;
00388
00389
00390 public:
00392 static void lock(spin_mutex &c)
00393 {
00394 lock_instance(c);
00395 }
00396
00398 static void unlock(spin_mutex &c)
00399 {
00400 unlock_instance(c);
00401 }
00402 };
00403
00405
00406
00407 #ifdef STLSOFT_UNITTEST
00408 # include "./unittest/spin_mutex_unittest_.h"
00409 #endif
00410
00411
00412
00413 #ifndef _UNIXSTL_NO_NAMESPACE
00414 # if defined(_STLSOFT_NO_NAMESPACE) || \
00415 defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00416 }
00417 # else
00418 }
00419 }
00420 # endif
00421 #endif
00422
00423
00424
00425 #endif
00426
00427