spin_rw_mutex.cpp
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.
*/
#include "tbb/spin_rw_mutex.h"
#include "tbb/tbb_machine.h"
#include "tbb/atomic.h"
#include "itt_notify.h"
#if defined(_MSC_VER) && defined(_Wp64)
// Workaround for overzealous compiler warnings in /Wp64 mode
#pragma warning (disable: 4244)
#endif
namespace tbb {
template<typename T> // a template can work with private spin_rw_mutex::state_t
static inline T CAS(volatile T &addr, T newv, T oldv) {
// ICC (9.1 and 10.1 tried) unable to do implicit conversion
// from "volatile T*" to "volatile void*", so explicit cast added.
return tbb::internal::as_atomic(addr).compare_and_swap( newv, oldv );
}
bool spin_rw_mutex_v3::internal_acquire_writer()
{
ITT_NOTIFY(sync_prepare, this);
for( internal::atomic_backoff backoff;;backoff.pause() ){
state_t s = const_cast<volatile state_t&>(state); // ensure reloading
if( !(s & BUSY) ) { // no readers, no writers
if( CAS(state, WRITER, s)==s )
break; // successfully stored writer flag
backoff.reset(); // we could be very close to complete op.
} else if( !(s & WRITER_PENDING) ) { // no pending writers
__TBB_AtomicOR(&state, WRITER_PENDING);
}
}
ITT_NOTIFY(sync_acquired, this);
return false;
}
void spin_rw_mutex_v3::internal_release_writer()
{
ITT_NOTIFY(sync_releasing, this);
__TBB_AtomicAND( &state, READERS );
}
void spin_rw_mutex_v3::internal_acquire_reader()
{
ITT_NOTIFY(sync_prepare, this);
for( internal::atomic_backoff b;;b.pause() ){
state_t s = const_cast<volatile state_t&>(state); // ensure reloading
if( !(s & (WRITER|WRITER_PENDING)) ) { // no writer or write requests
state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
if( !( t&WRITER ))
break; // successfully stored increased number of readers
// writer got there first, undo the increment
__TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
}
}
ITT_NOTIFY(sync_acquired, this);
__TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
}
bool spin_rw_mutex_v3::internal_upgrade()
{
state_t s = state;
__TBB_ASSERT( s & READERS, "invalid state before upgrade: no readers " );
// check and set writer-pending flag
// required conditions: either no pending writers, or we are the only reader
// (with multiple readers and pending writer, another upgrade could have been requested)
while( (s & READERS)==ONE_READER || !(s & WRITER_PENDING) ) {
state_t old_s = s;
if( (s=CAS(state, s | WRITER | WRITER_PENDING, s))==old_s ) {
ITT_NOTIFY(sync_prepare, this);
internal::atomic_backoff backoff;
while( (state & READERS) != ONE_READER ) backoff.pause();
__TBB_ASSERT((state&(WRITER_PENDING|WRITER))==(WRITER_PENDING|WRITER),"invalid state when upgrading to writer");
// both new readers and writers are blocked at this time
__TBB_FetchAndAddW( &state, - (intptr_t)(ONE_READER+WRITER_PENDING));
ITT_NOTIFY(sync_acquired, this);
return true; // successfully upgraded
}
}
// slow reacquire
internal_release_reader();
return internal_acquire_writer(); // always returns false
}
void spin_rw_mutex_v3::internal_downgrade() {
ITT_NOTIFY(sync_releasing, this);
__TBB_FetchAndAddW( &state, (intptr_t)(ONE_READER-WRITER));
__TBB_ASSERT( state & READERS, "invalid state after downgrade: no readers" );
}
void spin_rw_mutex_v3::internal_release_reader()
{
__TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
ITT_NOTIFY(sync_releasing, this); // release reader
__TBB_FetchAndAddWrelease( &state,-(intptr_t)ONE_READER);
}
bool spin_rw_mutex_v3::internal_try_acquire_writer()
{
// for a writer: only possible to acquire if no active readers or writers
state_t s = state;
if( !(s & BUSY) ) // no readers, no writers; mask is 1..1101
if( CAS(state, WRITER, s)==s ) {
ITT_NOTIFY(sync_acquired, this);
return true; // successfully stored writer flag
}
return false;
}
bool spin_rw_mutex_v3::internal_try_acquire_reader()
{
// for a reader: acquire if no active or waiting writers
state_t s = state;
if( !(s & (WRITER|WRITER_PENDING)) ) { // no writers
state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
if( !( t&WRITER )) { // got the lock
ITT_NOTIFY(sync_acquired, this);
return true; // successfully stored increased number of readers
}
// writer got there first, undo the increment
__TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
}
return false;
}
void spin_rw_mutex_v3::internal_construct() {
ITT_SYNC_CREATE(this, _T("tbb::spin_rw_mutex"), _T(""));
}
} // namespace tbb
tbb::spin_rw_mutex_v3::internal_acquire_writer
bool __TBB_EXPORTED_METHOD internal_acquire_writer()
Internal acquire write lock.
Definition: spin_rw_mutex.cpp:37
__TBB_ASSERT
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
ITT_NOTIFY
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:112
tbb::internal::atomic_backoff
Class that implements exponential backoff.
Definition: tbb_machine.h:348
tbb::spin_rw_mutex_v3::WRITER
static const state_t WRITER
Definition: spin_rw_mutex.h:208
tbb
The graph class.
Definition: serial/tbb/parallel_for.h:46
tbb::spin_rw_mutex_v3::READERS
static const state_t READERS
Definition: spin_rw_mutex.h:210
tbb::spin_rw_mutex_v3::state_t
intptr_t state_t
Definition: spin_rw_mutex.h:207
spin_rw_mutex.h
tbb::spin_rw_mutex_v3::internal_construct
void __TBB_EXPORTED_METHOD internal_construct()
Definition: spin_rw_mutex.cpp:152
itt_notify.h
tbb::spin_rw_mutex_v3::internal_acquire_reader
void __TBB_EXPORTED_METHOD internal_acquire_reader()
Internal acquire read lock.
Definition: spin_rw_mutex.cpp:62
tbb::spin_rw_mutex_v3::internal_release_reader
void __TBB_EXPORTED_METHOD internal_release_reader()
Internal release read lock.
Definition: spin_rw_mutex.cpp:115
tbb::internal::atomic_backoff::pause
void pause()
Pause for a while.
Definition: tbb_machine.h:363
ITT_SYNC_CREATE
#define ITT_SYNC_CREATE(obj, type, name)
Definition: itt_notify.h:115
tbb::spin_rw_mutex_v3::internal_downgrade
void __TBB_EXPORTED_METHOD internal_downgrade()
Out of line code for downgrading a writer to a reader.
Definition: spin_rw_mutex.cpp:108
tbb::spin_rw_mutex_v3::WRITER_PENDING
static const state_t WRITER_PENDING
Definition: spin_rw_mutex.h:209
tbb::spin_rw_mutex_v3::internal_upgrade
bool __TBB_EXPORTED_METHOD internal_upgrade()
Internal upgrade reader to become a writer.
Definition: spin_rw_mutex.cpp:82
__TBB_AtomicAND
void __TBB_AtomicAND(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:891
atomic.h
tbb::CAS
static T CAS(volatile T &addr, T newv, T oldv)
Definition: spin_rw_mutex.cpp:30
_T
#define _T(string_literal)
Standard Windows style macro to markup the string literals.
Definition: itt_notify.h:59
s
void const char const char int ITT_FORMAT __itt_group_sync s
Definition: ittnotify_static.h:91
addr
void * addr
Definition: ittnotify_static.h:91
__TBB_AtomicOR
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:881
tbb_machine.h
tbb::spin_rw_mutex_v3::internal_try_acquire_writer
bool __TBB_EXPORTED_METHOD internal_try_acquire_writer()
Internal try_acquire write lock.
Definition: spin_rw_mutex.cpp:123
tbb::internal::as_atomic
atomic< T > & as_atomic(T &t)
Definition: atomic.h:572
tbb::spin_rw_mutex_v3::internal_try_acquire_reader
bool __TBB_EXPORTED_METHOD internal_try_acquire_reader()
Internal try_acquire read lock.
Definition: spin_rw_mutex.cpp:136
sync_releasing
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 sync_releasing
Definition: ittnotify_static.h:104
tbb::spin_rw_mutex_v3::ONE_READER
static const state_t ONE_READER
Definition: spin_rw_mutex.h:211
tbb::spin_rw_mutex_v3::internal_release_writer
void __TBB_EXPORTED_METHOD internal_release_writer()
Out of line code for releasing a write lock.
Definition: spin_rw_mutex.cpp:55
tbb::spin_rw_mutex_v3::BUSY
static const state_t BUSY
Definition: spin_rw_mutex.h:212
__TBB_FetchAndAddWrelease
#define __TBB_FetchAndAddWrelease(P, V)
Definition: tbb_machine.h:312
tbb::spin_rw_mutex_v3::state
state_t state
State of lock.
Definition: spin_rw_mutex.h:217

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.