Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
spin_rw_mutex.cpp
Go to the documentation of this file.
1/*
2 Copyright (c) 2005-2020 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#include "tbb/spin_rw_mutex.h"
18#include "tbb/tbb_machine.h"
19#include "tbb/atomic.h"
20#include "itt_notify.h"
21
22#if defined(_MSC_VER) && defined(_Wp64)
23 // Workaround for overzealous compiler warnings in /Wp64 mode
24 #pragma warning (disable: 4244)
25#endif
26
27namespace tbb {
28
29template<typename T> // a template can work with private spin_rw_mutex::state_t
30static inline T CAS(volatile T &addr, T newv, T oldv) {
31 // ICC (9.1 and 10.1 tried) unable to do implicit conversion
32 // from "volatile T*" to "volatile void*", so explicit cast added.
33 return tbb::internal::as_atomic(addr).compare_and_swap( newv, oldv );
34}
35
38{
39 ITT_NOTIFY(sync_prepare, this);
40 for( internal::atomic_backoff backoff;;backoff.pause() ){
41 state_t s = const_cast<volatile state_t&>(state); // ensure reloading
42 if( !(s & BUSY) ) { // no readers, no writers
43 if( CAS(state, WRITER, s)==s )
44 break; // successfully stored writer flag
45 backoff.reset(); // we could be very close to complete op.
46 } else if( !(s & WRITER_PENDING) ) { // no pending writers
48 }
49 }
50 ITT_NOTIFY(sync_acquired, this);
51 return false;
52}
53
56{
59}
60
63{
64 ITT_NOTIFY(sync_prepare, this);
65 for( internal::atomic_backoff b;;b.pause() ){
66 state_t s = const_cast<volatile state_t&>(state); // ensure reloading
67 if( !(s & (WRITER|WRITER_PENDING)) ) { // no writer or write requests
68 state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
69 if( !( t&WRITER ))
70 break; // successfully stored increased number of readers
71 // writer got there first, undo the increment
72 __TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
73 }
74 }
75
76 ITT_NOTIFY(sync_acquired, this);
77 __TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
78}
79
81
83{
84 state_t s = state;
85 __TBB_ASSERT( s & READERS, "invalid state before upgrade: no readers " );
86 // check and set writer-pending flag
87 // required conditions: either no pending writers, or we are the only reader
88 // (with multiple readers and pending writer, another upgrade could have been requested)
89 while( (s & READERS)==ONE_READER || !(s & WRITER_PENDING) ) {
90 state_t old_s = s;
91 if( (s=CAS(state, s | WRITER | WRITER_PENDING, s))==old_s ) {
92 ITT_NOTIFY(sync_prepare, this);
94 while( (state & READERS) != ONE_READER ) backoff.pause();
95 __TBB_ASSERT((state&(WRITER_PENDING|WRITER))==(WRITER_PENDING|WRITER),"invalid state when upgrading to writer");
96 // both new readers and writers are blocked at this time
97 __TBB_FetchAndAddW( &state, - (intptr_t)(ONE_READER+WRITER_PENDING));
98 ITT_NOTIFY(sync_acquired, this);
99 return true; // successfully upgraded
100 }
101 }
102 // slow reacquire
104 return internal_acquire_writer(); // always returns false
105}
106
110 __TBB_FetchAndAddW( &state, (intptr_t)(ONE_READER-WRITER));
111 __TBB_ASSERT( state & READERS, "invalid state after downgrade: no readers" );
112}
113
116{
117 __TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
118 ITT_NOTIFY(sync_releasing, this); // release reader
120}
121
124{
125 // for a writer: only possible to acquire if no active readers or writers
126 state_t s = state;
127 if( !(s & BUSY) ) // no readers, no writers; mask is 1..1101
128 if( CAS(state, WRITER, s)==s ) {
129 ITT_NOTIFY(sync_acquired, this);
130 return true; // successfully stored writer flag
131 }
132 return false;
133}
134
137{
138 // for a reader: acquire if no active or waiting writers
139 state_t s = state;
140 if( !(s & (WRITER|WRITER_PENDING)) ) { // no writers
141 state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
142 if( !( t&WRITER )) { // got the lock
143 ITT_NOTIFY(sync_acquired, this);
144 return true; // successfully stored increased number of readers
145 }
146 // writer got there first, undo the increment
147 __TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
148 }
149 return false;
150}
151
153 ITT_SYNC_CREATE(this, _T("tbb::spin_rw_mutex"), _T(""));
154}
155} // namespace tbb
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:878
void __TBB_AtomicAND(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:888
#define __TBB_FetchAndAddWrelease(P, V)
Definition: tbb_machine.h:309
#define _T(string_literal)
Standard Windows style macro to markup the string literals.
Definition: itt_notify.h:59
#define ITT_SYNC_CREATE(obj, type, name)
Definition: itt_notify.h:115
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:112
void const char const char int ITT_FORMAT __itt_group_sync s
void * addr
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
The graph class.
static T CAS(volatile T &addr, T newv, T oldv)
atomic< T > & as_atomic(T &t)
Definition: atomic.h:572
bool __TBB_EXPORTED_METHOD internal_acquire_writer()
Internal acquire write lock.
bool __TBB_EXPORTED_METHOD internal_try_acquire_writer()
Internal try_acquire write lock.
static const state_t WRITER_PENDING
static const state_t BUSY
static const state_t READERS
bool __TBB_EXPORTED_METHOD internal_try_acquire_reader()
Internal try_acquire read lock.
void __TBB_EXPORTED_METHOD internal_construct()
void __TBB_EXPORTED_METHOD internal_downgrade()
Out of line code for downgrading a writer to a reader.
state_t state
State of lock.
static const state_t WRITER
void __TBB_EXPORTED_METHOD internal_release_reader()
Internal release read lock.
bool __TBB_EXPORTED_METHOD internal_upgrade()
Internal upgrade reader to become a writer.
void __TBB_EXPORTED_METHOD internal_acquire_reader()
Internal acquire read lock.
void __TBB_EXPORTED_METHOD internal_release_writer()
Out of line code for releasing a write lock.
static const state_t ONE_READER
Class that implements exponential backoff.
Definition: tbb_machine.h:345
void pause()
Pause for a while.
Definition: tbb_machine.h:360

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.