| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- /*
- Copyright (c) 2005-2020 Intel Corporation
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- #ifndef __TBB__x86_rtm_rw_mutex_impl_H
- #define __TBB__x86_rtm_rw_mutex_impl_H
- #ifndef __TBB_spin_rw_mutex_H
- #error Do not #include this internal file directly; use public TBB headers instead.
- #endif
- #if __TBB_TSX_AVAILABLE
- #include "../tbb_stddef.h"
- #include "../tbb_machine.h"
- #include "../tbb_profiling.h"
- #include "../spin_rw_mutex.h"
- namespace tbb {
- namespace interface8 {
- namespace internal {
- enum RTM_type {
- RTM_not_in_mutex,
- RTM_transacting_reader,
- RTM_transacting_writer,
- RTM_real_reader,
- RTM_real_writer
- };
- static const unsigned long speculation_granularity = 64;
- //! Fast, unfair, spinning speculation-enabled reader-writer lock with backoff and
- // writer-preference
- /** @ingroup synchronization */
- class x86_rtm_rw_mutex: private spin_rw_mutex {
- #if __TBB_USE_X86_RTM_RW_MUTEX || __TBB_GCC_VERSION < 40000
- // bug in gcc 3.x.x causes syntax error in spite of the friend declaration below.
- // Make the scoped_lock public in that case.
- public:
- #else
- private:
- #endif
- friend class interface7::internal::padded_mutex<x86_rtm_rw_mutex,true>;
- class scoped_lock; // should be private
- friend class scoped_lock;
- private:
- //! @cond INTERNAL
- //! Internal construct unacquired mutex.
- void __TBB_EXPORTED_METHOD internal_construct();
- //! Internal acquire write lock.
- // only_speculate == true if we're doing a try_lock, else false.
- void __TBB_EXPORTED_METHOD internal_acquire_writer(x86_rtm_rw_mutex::scoped_lock&, bool only_speculate=false);
- //! Internal acquire read lock.
- // only_speculate == true if we're doing a try_lock, else false.
- void __TBB_EXPORTED_METHOD internal_acquire_reader(x86_rtm_rw_mutex::scoped_lock&, bool only_speculate=false);
- //! Internal upgrade reader to become a writer.
- bool __TBB_EXPORTED_METHOD internal_upgrade( x86_rtm_rw_mutex::scoped_lock& );
- //! Out of line code for downgrading a writer to a reader.
- bool __TBB_EXPORTED_METHOD internal_downgrade( x86_rtm_rw_mutex::scoped_lock& );
- //! Internal try_acquire write lock.
- bool __TBB_EXPORTED_METHOD internal_try_acquire_writer( x86_rtm_rw_mutex::scoped_lock& );
- //! Internal release lock.
- void __TBB_EXPORTED_METHOD internal_release( x86_rtm_rw_mutex::scoped_lock& );
- static x86_rtm_rw_mutex* internal_get_mutex( const spin_rw_mutex::scoped_lock& lock )
- {
- return static_cast<x86_rtm_rw_mutex*>( lock.mutex );
- }
- static void internal_set_mutex( spin_rw_mutex::scoped_lock& lock, spin_rw_mutex* mtx )
- {
- lock.mutex = mtx;
- }
- //! @endcond
- public:
- //! Construct unacquired mutex.
- x86_rtm_rw_mutex() {
- w_flag = false;
- #if TBB_USE_THREADING_TOOLS
- internal_construct();
- #endif
- }
- #if TBB_USE_ASSERT
- //! Empty destructor.
- ~x86_rtm_rw_mutex() {}
- #endif /* TBB_USE_ASSERT */
- // Mutex traits
- static const bool is_rw_mutex = true;
- static const bool is_recursive_mutex = false;
- static const bool is_fair_mutex = false;
- #if __TBB_USE_X86_RTM_RW_MUTEX || __TBB_GCC_VERSION < 40000
- #else
- // by default we will not provide the scoped_lock interface. The user
- // should use the padded version of the mutex. scoped_lock is used in
- // padded_mutex template.
- private:
- #endif
- //! The scoped locking pattern
- /** It helps to avoid the common problem of forgetting to release lock.
- It also nicely provides the "node" for queuing locks. */
- // Speculation-enabled scoped lock for spin_rw_mutex
- // The idea is to be able to reuse the acquire/release methods of spin_rw_mutex
- // and its scoped lock wherever possible. The only way to use a speculative lock is to use
- // a scoped_lock. (because transaction_state must be local)
- class scoped_lock : tbb::internal::no_copy {
- friend class x86_rtm_rw_mutex;
- spin_rw_mutex::scoped_lock my_scoped_lock;
- RTM_type transaction_state;
- public:
- //! Construct lock that has not acquired a mutex.
- /** Equivalent to zero-initialization of *this. */
- scoped_lock() : my_scoped_lock(), transaction_state(RTM_not_in_mutex) {
- }
- //! Acquire lock on given mutex.
- scoped_lock( x86_rtm_rw_mutex& m, bool write = true ) : my_scoped_lock(),
- transaction_state(RTM_not_in_mutex) {
- acquire(m, write);
- }
- //! Release lock (if lock is held).
- ~scoped_lock() {
- if(transaction_state != RTM_not_in_mutex) release();
- }
- //! Acquire lock on given mutex.
- void acquire( x86_rtm_rw_mutex& m, bool write = true ) {
- if( write ) m.internal_acquire_writer(*this);
- else m.internal_acquire_reader(*this);
- }
- //! Release lock
- void release() {
- x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
- __TBB_ASSERT( mutex, "lock is not acquired" );
- __TBB_ASSERT( transaction_state!=RTM_not_in_mutex, "lock is not acquired" );
- return mutex->internal_release(*this);
- }
- //! Upgrade reader to become a writer.
- /** Returns whether the upgrade happened without releasing and re-acquiring the lock */
- bool upgrade_to_writer() {
- x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
- __TBB_ASSERT( mutex, "lock is not acquired" );
- if (transaction_state == RTM_transacting_writer || transaction_state == RTM_real_writer)
- return true; // Already a writer
- return mutex->internal_upgrade(*this);
- }
- //! Downgrade writer to become a reader.
- /** Returns whether the downgrade happened without releasing and re-acquiring the lock */
- bool downgrade_to_reader() {
- x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
- __TBB_ASSERT( mutex, "lock is not acquired" );
- if (transaction_state == RTM_transacting_reader || transaction_state == RTM_real_reader)
- return true; // Already a reader
- return mutex->internal_downgrade(*this);
- }
- //! Attempt to acquire mutex.
- /** returns true if successful. */
- bool try_acquire( x86_rtm_rw_mutex& m, bool write = true ) {
- #if TBB_USE_ASSERT
- x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
- __TBB_ASSERT( !mutex, "lock is already acquired" );
- #endif
- // have to assign m to our mutex.
- // cannot set the mutex, because try_acquire in spin_rw_mutex depends on it being NULL.
- if(write) return m.internal_try_acquire_writer(*this);
- // speculatively acquire the lock. If this fails, do try_acquire on the spin_rw_mutex.
- m.internal_acquire_reader(*this, /*only_speculate=*/true);
- if(transaction_state == RTM_transacting_reader) return true;
- if( my_scoped_lock.try_acquire(m, false)) {
- transaction_state = RTM_real_reader;
- return true;
- }
- return false;
- }
- }; // class x86_rtm_rw_mutex::scoped_lock
- // ISO C++0x compatibility methods not provided because we cannot maintain
- // state about whether a thread is in a transaction.
- private:
- char pad[speculation_granularity-sizeof(spin_rw_mutex)]; // padding
- // If true, writer holds the spin_rw_mutex.
- tbb::atomic<bool> w_flag; // want this on a separate cache line
- }; // x86_rtm_rw_mutex
- } // namespace internal
- } // namespace interface8
- } // namespace tbb
- #endif /* __TBB_TSX_AVAILABLE */
- #endif /* __TBB__x86_rtm_rw_mutex_impl_H */
|