Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:12:59

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #ifndef __TBB_spin_rw_mutex_H
0018 #define __TBB_spin_rw_mutex_H
0019 
0020 #include "tbb_stddef.h"
0021 #include "tbb_machine.h"
0022 #include "tbb_profiling.h"
0023 #include "internal/_mutex_padding.h"
0024 
0025 namespace tbb {
0026 
0027 #if __TBB_TSX_AVAILABLE
0028 namespace interface8 { namespace internal {
0029     class x86_rtm_rw_mutex;
0030 }}
0031 #endif
0032 
0033 class spin_rw_mutex_v3;
0034 typedef spin_rw_mutex_v3 spin_rw_mutex;
0035 
0036 //! Fast, unfair, spinning reader-writer lock with backoff and writer-preference
0037 /** @ingroup synchronization */
0038 class spin_rw_mutex_v3 : internal::mutex_copy_deprecated_and_disabled {
0039     //! @cond INTERNAL
0040 
0041     //! Internal acquire write lock.
0042     bool __TBB_EXPORTED_METHOD internal_acquire_writer();
0043 
0044     //! Out of line code for releasing a write lock.
0045     /** This code has debug checking and instrumentation for Intel(R) Thread Checker and Intel(R) Thread Profiler. */
0046     void __TBB_EXPORTED_METHOD internal_release_writer();
0047 
0048     //! Internal acquire read lock.
0049     void __TBB_EXPORTED_METHOD internal_acquire_reader();
0050 
0051     //! Internal upgrade reader to become a writer.
0052     bool __TBB_EXPORTED_METHOD internal_upgrade();
0053 
0054     //! Out of line code for downgrading a writer to a reader.
0055     /** This code has debug checking and instrumentation for Intel(R) Thread Checker and Intel(R) Thread Profiler. */
0056     void __TBB_EXPORTED_METHOD internal_downgrade();
0057 
0058     //! Internal release read lock.
0059     void __TBB_EXPORTED_METHOD internal_release_reader();
0060 
0061     //! Internal try_acquire write lock.
0062     bool __TBB_EXPORTED_METHOD internal_try_acquire_writer();
0063 
0064     //! Internal try_acquire read lock.
0065     bool __TBB_EXPORTED_METHOD internal_try_acquire_reader();
0066 
0067     //! @endcond
0068 public:
0069     //! Construct unacquired mutex.
0070     spin_rw_mutex_v3() : state(0) {
0071 #if TBB_USE_THREADING_TOOLS
0072         internal_construct();
0073 #endif
0074     }
0075 
0076 #if TBB_USE_ASSERT
0077     //! Destructor asserts if the mutex is acquired, i.e. state is zero.
0078     ~spin_rw_mutex_v3() {
0079         __TBB_ASSERT( !state, "destruction of an acquired mutex");
0080     };
0081 #endif /* TBB_USE_ASSERT */
0082 
0083     //! The scoped locking pattern
0084     /** It helps to avoid the common problem of forgetting to release lock.
0085         It also nicely provides the "node" for queuing locks. */
0086     class scoped_lock : internal::no_copy {
0087 #if __TBB_TSX_AVAILABLE
0088         friend class tbb::interface8::internal::x86_rtm_rw_mutex;
0089 #endif
0090     public:
0091         //! Construct lock that has not acquired a mutex.
0092         /** Equivalent to zero-initialization of *this. */
0093         scoped_lock() : mutex(NULL), is_writer(false) {}
0094 
0095         //! Acquire lock on given mutex.
0096         scoped_lock( spin_rw_mutex& m, bool write = true ) : mutex(NULL) {
0097             acquire(m, write);
0098         }
0099 
0100         //! Release lock (if lock is held).
0101         ~scoped_lock() {
0102             if( mutex ) release();
0103         }
0104 
0105         //! Acquire lock on given mutex.
0106         void acquire( spin_rw_mutex& m, bool write = true ) {
0107             __TBB_ASSERT( !mutex, "holding mutex already" );
0108             is_writer = write;
0109             mutex = &m;
0110             if( write ) mutex->internal_acquire_writer();
0111             else        mutex->internal_acquire_reader();
0112         }
0113 
0114         //! Upgrade reader to become a writer.
0115         /** Returns whether the upgrade happened without releasing and re-acquiring the lock */
0116         bool upgrade_to_writer() {
0117             __TBB_ASSERT( mutex, "mutex is not acquired" );
0118             if (is_writer) return true; // Already a writer
0119             is_writer = true;
0120             return mutex->internal_upgrade();
0121         }
0122 
0123         //! Release lock.
0124         void release() {
0125             __TBB_ASSERT( mutex, "mutex is not acquired" );
0126             spin_rw_mutex *m = mutex;
0127             mutex = NULL;
0128 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
0129             if( is_writer ) m->internal_release_writer();
0130             else            m->internal_release_reader();
0131 #else
0132             if( is_writer ) __TBB_AtomicAND( &m->state, READERS );
0133             else            __TBB_FetchAndAddWrelease( &m->state, -(intptr_t)ONE_READER);
0134 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
0135         }
0136 
0137         //! Downgrade writer to become a reader.
0138         bool downgrade_to_reader() {
0139             __TBB_ASSERT( mutex, "mutex is not acquired" );
0140             if (!is_writer) return true; // Already a reader
0141 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
0142             mutex->internal_downgrade();
0143 #else
0144             __TBB_FetchAndAddW( &mutex->state, ((intptr_t)ONE_READER-WRITER));
0145 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
0146             is_writer = false;
0147             return true;
0148         }
0149 
0150         //! Try acquire lock on given mutex.
0151         bool try_acquire( spin_rw_mutex& m, bool write = true ) {
0152             __TBB_ASSERT( !mutex, "holding mutex already" );
0153             bool result;
0154             is_writer = write;
0155             result = write? m.internal_try_acquire_writer()
0156                           : m.internal_try_acquire_reader();
0157             if( result )
0158                 mutex = &m;
0159             return result;
0160         }
0161 
0162     protected:
0163 
0164         //! The pointer to the current mutex that is held, or NULL if no mutex is held.
0165         spin_rw_mutex* mutex;
0166 
0167         //! If mutex!=NULL, then is_writer is true if holding a writer lock, false if holding a reader lock.
0168         /** Not defined if not holding a lock. */
0169         bool is_writer;
0170     };
0171 
0172     // Mutex traits
0173     static const bool is_rw_mutex = true;
0174     static const bool is_recursive_mutex = false;
0175     static const bool is_fair_mutex = false;
0176 
0177     // ISO C++0x compatibility methods
0178 
0179     //! Acquire writer lock
0180     void lock() {internal_acquire_writer();}
0181 
0182     //! Try acquiring writer lock (non-blocking)
0183     /** Return true if lock acquired; false otherwise. */
0184     bool try_lock() {return internal_try_acquire_writer();}
0185 
0186     //! Release lock
0187     void unlock() {
0188 #if TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT
0189         if( state&WRITER ) internal_release_writer();
0190         else               internal_release_reader();
0191 #else
0192         if( state&WRITER ) __TBB_AtomicAND( &state, READERS );
0193         else               __TBB_FetchAndAddWrelease( &state, -(intptr_t)ONE_READER);
0194 #endif /* TBB_USE_THREADING_TOOLS||TBB_USE_ASSERT */
0195     }
0196 
0197     // Methods for reader locks that resemble ISO C++0x compatibility methods.
0198 
0199     //! Acquire reader lock
0200     void lock_read() {internal_acquire_reader();}
0201 
0202     //! Try acquiring reader lock (non-blocking)
0203     /** Return true if reader lock acquired; false otherwise. */
0204     bool try_lock_read() {return internal_try_acquire_reader();}
0205 
0206 protected:
0207     typedef intptr_t state_t;
0208     static const state_t WRITER = 1;
0209     static const state_t WRITER_PENDING = 2;
0210     static const state_t READERS = ~(WRITER | WRITER_PENDING);
0211     static const state_t ONE_READER = 4;
0212     static const state_t BUSY = WRITER | READERS;
0213     //! State of lock
0214     /** Bit 0 = writer is holding lock
0215         Bit 1 = request by a writer to acquire lock (hint to readers to wait)
0216         Bit 2..N = number of readers holding lock */
0217     state_t state;
0218 
0219 private:
0220     void __TBB_EXPORTED_METHOD internal_construct();
0221 };
0222 
0223 __TBB_DEFINE_PROFILING_SET_NAME(spin_rw_mutex)
0224 
0225 } // namespace tbb
0226 
0227 #if __TBB_TSX_AVAILABLE
0228 #include "internal/_x86_rtm_rw_mutex_impl.h"
0229 #endif
0230 
0231 namespace tbb {
0232 namespace interface8 {
0233 //! A cross-platform spin reader/writer mutex with speculative lock acquisition.
0234 /** On platforms with proper HW support, this lock may speculatively execute
0235     its critical sections, using HW mechanisms to detect real data races and
0236     ensure atomicity of the critical sections. In particular, it uses
0237     Intel(R) Transactional Synchronization Extensions (Intel(R) TSX).
0238     Without such HW support, it behaves like a spin_rw_mutex.
0239     It should be used for locking short critical sections where the lock is
0240     contended but the data it protects are not.
0241     @ingroup synchronization */
0242 #if __TBB_TSX_AVAILABLE
0243 typedef interface7::internal::padded_mutex<tbb::interface8::internal::x86_rtm_rw_mutex,true> speculative_spin_rw_mutex;
0244 #else
0245 typedef interface7::internal::padded_mutex<tbb::spin_rw_mutex,true> speculative_spin_rw_mutex;
0246 #endif
0247 }  // namespace interface8
0248 
0249 using interface8::speculative_spin_rw_mutex;
0250 __TBB_DEFINE_PROFILING_SET_NAME(speculative_spin_rw_mutex)
0251 } // namespace tbb
0252 #endif /* __TBB_spin_rw_mutex_H */