_x86_rtm_rw_mutex_impl.h
Go to the documentation of this file.
/*
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;
// writer-preference
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:
void __TBB_EXPORTED_METHOD internal_construct();
// 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);
// 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);
bool __TBB_EXPORTED_METHOD internal_upgrade( x86_rtm_rw_mutex::scoped_lock& );
bool __TBB_EXPORTED_METHOD internal_downgrade( x86_rtm_rw_mutex::scoped_lock& );
bool __TBB_EXPORTED_METHOD internal_try_acquire_writer( x86_rtm_rw_mutex::scoped_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;
}
public:
x86_rtm_rw_mutex() {
w_flag = false;
#if TBB_USE_THREADING_TOOLS
internal_construct();
#endif
}
#if TBB_USE_ASSERT
~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
// 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:
scoped_lock() : my_scoped_lock(), transaction_state(RTM_not_in_mutex) {
}
scoped_lock( x86_rtm_rw_mutex& m, bool write = true ) : my_scoped_lock(),
transaction_state(RTM_not_in_mutex) {
acquire(m, write);
}
~scoped_lock() {
if(transaction_state != RTM_not_in_mutex) release();
}
void acquire( x86_rtm_rw_mutex& m, bool write = true ) {
if( write ) m.internal_acquire_writer(*this);
else m.internal_acquire_reader(*this);
}
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);
}
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);
}
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);
}
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 */
__TBB_EXPORTED_METHOD
#define __TBB_EXPORTED_METHOD
Definition: tbb_stddef.h:98
__TBB_ASSERT
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
lock
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void * lock
Definition: ittnotify_static.h:121
tbb
The graph class.
Definition: serial/tbb/parallel_for.h:46
tbb::spin_rw_mutex
spin_rw_mutex_v3 spin_rw_mutex
Definition: spin_rw_mutex.h:33
tbb::release
@ release
Release.
Definition: atomic.h:59
tbb::acquire
@ acquire
Acquire.
Definition: atomic.h:57
internal
Definition: _flow_graph_async_msg_impl.h:24
tbb::internal::no_copy
Base class for types that should not be copied or assigned.
Definition: tbb_stddef.h:330

Copyright © 2005-2020 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.