Home ⌂Doc Index ◂Up ▴
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 
27 namespace tbb {
28 
29 template<typename T> // a template can work with private spin_rw_mutex::state_t
30 static 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 
109  ITT_NOTIFY(sync_releasing, this);
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
bool __TBB_EXPORTED_METHOD internal_try_acquire_reader()
Internal try_acquire read lock.
void __TBB_EXPORTED_METHOD internal_release_reader()
Internal release read lock.
bool __TBB_EXPORTED_METHOD internal_try_acquire_writer()
Internal try_acquire write lock.
bool __TBB_EXPORTED_METHOD internal_acquire_writer()
Internal acquire write lock.
static T CAS(volatile T &addr, T newv, T oldv)
void pause()
Pause for a while.
Definition: tbb_machine.h:360
static const state_t ONE_READER
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:878
void * addr
void __TBB_AtomicAND(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:888
state_t state
State of lock.
static const state_t BUSY
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
static const state_t WRITER_PENDING
#define _T(string_literal)
Standard Windows style macro to markup the string literals.
Definition: itt_notify.h:59
void __TBB_EXPORTED_METHOD internal_construct()
static const state_t WRITER
Class that implements exponential backoff.
Definition: tbb_machine.h:345
static const state_t READERS
void const char const char int ITT_FORMAT __itt_group_sync s
#define ITT_SYNC_CREATE(obj, type, name)
Definition: itt_notify.h:115
#define __TBB_FetchAndAddWrelease(P, V)
Definition: tbb_machine.h:309
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
void __TBB_EXPORTED_METHOD internal_acquire_reader()
Internal acquire read lock.
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:112
void __TBB_EXPORTED_METHOD internal_release_writer()
Out of line code for releasing a write lock.
atomic< T > & as_atomic(T &t)
Definition: atomic.h:572
bool __TBB_EXPORTED_METHOD internal_upgrade()
Internal upgrade reader to become a writer.
The graph class.
void __TBB_EXPORTED_METHOD internal_downgrade()
Out of line code for downgrading a writer to a reader.

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.