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-2019 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 
18 
19 */
20 
21 #include "tbb/spin_rw_mutex.h"
22 #include "tbb/tbb_machine.h"
23 #include "tbb/atomic.h"
24 #include "itt_notify.h"
25 
26 #if defined(_MSC_VER) && defined(_Wp64)
27  // Workaround for overzealous compiler warnings in /Wp64 mode
28  #pragma warning (disable: 4244)
29 #endif
30 
31 namespace tbb {
32 
33 template<typename T> // a template can work with private spin_rw_mutex::state_t
34 static inline T CAS(volatile T &addr, T newv, T oldv) {
35  // ICC (9.1 and 10.1 tried) unable to do implicit conversion
36  // from "volatile T*" to "volatile void*", so explicit cast added.
37  return tbb::internal::as_atomic(addr).compare_and_swap( newv, oldv );
38 }
39 
42 {
43  ITT_NOTIFY(sync_prepare, this);
44  for( internal::atomic_backoff backoff;;backoff.pause() ){
45  state_t s = const_cast<volatile state_t&>(state); // ensure reloading
46  if( !(s & BUSY) ) { // no readers, no writers
47  if( CAS(state, WRITER, s)==s )
48  break; // successfully stored writer flag
49  backoff.reset(); // we could be very close to complete op.
50  } else if( !(s & WRITER_PENDING) ) { // no pending writers
52  }
53  }
54  ITT_NOTIFY(sync_acquired, this);
55  return false;
56 }
57 
60 {
63 }
64 
67 {
68  ITT_NOTIFY(sync_prepare, this);
69  for( internal::atomic_backoff b;;b.pause() ){
70  state_t s = const_cast<volatile state_t&>(state); // ensure reloading
71  if( !(s & (WRITER|WRITER_PENDING)) ) { // no writer or write requests
72  state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
73  if( !( t&WRITER ))
74  break; // successfully stored increased number of readers
75  // writer got there first, undo the increment
76  __TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
77  }
78  }
79 
80  ITT_NOTIFY(sync_acquired, this);
81  __TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
82 }
83 
85 
87 {
88  state_t s = state;
89  __TBB_ASSERT( s & READERS, "invalid state before upgrade: no readers " );
90  // check and set writer-pending flag
91  // required conditions: either no pending writers, or we are the only reader
92  // (with multiple readers and pending writer, another upgrade could have been requested)
93  while( (s & READERS)==ONE_READER || !(s & WRITER_PENDING) ) {
94  state_t old_s = s;
95  if( (s=CAS(state, s | WRITER | WRITER_PENDING, s))==old_s ) {
96  ITT_NOTIFY(sync_prepare, this);
97  internal::atomic_backoff backoff;
98  while( (state & READERS) != ONE_READER ) backoff.pause();
99  __TBB_ASSERT((state&(WRITER_PENDING|WRITER))==(WRITER_PENDING|WRITER),"invalid state when upgrading to writer");
100  // both new readers and writers are blocked at this time
101  __TBB_FetchAndAddW( &state, - (intptr_t)(ONE_READER+WRITER_PENDING));
102  ITT_NOTIFY(sync_acquired, this);
103  return true; // successfully upgraded
104  }
105  }
106  // slow reacquire
108  return internal_acquire_writer(); // always returns false
109 }
110 
113  ITT_NOTIFY(sync_releasing, this);
114  __TBB_FetchAndAddW( &state, (intptr_t)(ONE_READER-WRITER));
115  __TBB_ASSERT( state & READERS, "invalid state after downgrade: no readers" );
116 }
117 
120 {
121  __TBB_ASSERT( state & READERS, "invalid state of a read lock: no readers" );
122  ITT_NOTIFY(sync_releasing, this); // release reader
124 }
125 
128 {
129  // for a writer: only possible to acquire if no active readers or writers
130  state_t s = state;
131  if( !(s & BUSY) ) // no readers, no writers; mask is 1..1101
132  if( CAS(state, WRITER, s)==s ) {
133  ITT_NOTIFY(sync_acquired, this);
134  return true; // successfully stored writer flag
135  }
136  return false;
137 }
138 
141 {
142  // for a reader: acquire if no active or waiting writers
143  state_t s = state;
144  if( !(s & (WRITER|WRITER_PENDING)) ) { // no writers
145  state_t t = (state_t)__TBB_FetchAndAddW( &state, (intptr_t) ONE_READER );
146  if( !( t&WRITER )) { // got the lock
147  ITT_NOTIFY(sync_acquired, this);
148  return true; // successfully stored increased number of readers
149  }
150  // writer got there first, undo the increment
151  __TBB_FetchAndAddW( &state, -(intptr_t)ONE_READER );
152  }
153  return false;
154 }
155 
157  ITT_SYNC_CREATE(this, _T("tbb::spin_rw_mutex"), _T(""));
158 }
159 } // namespace tbb
void __TBB_EXPORTED_METHOD internal_acquire_reader()
Internal acquire read lock.
void __TBB_EXPORTED_METHOD internal_release_reader()
Internal release read lock.
static const state_t BUSY
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
bool __TBB_EXPORTED_METHOD internal_acquire_writer()
Internal acquire write lock.
#define ITT_SYNC_CREATE(obj, type, name)
Definition: itt_notify.h:123
void __TBB_EXPORTED_METHOD internal_construct()
bool __TBB_EXPORTED_METHOD internal_try_acquire_reader()
Internal try_acquire read lock.
#define __TBB_FetchAndAddWrelease(P, V)
Definition: tbb_machine.h:313
void __TBB_AtomicAND(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:892
void * addr
static T CAS(volatile T &addr, T newv, T oldv)
void __TBB_EXPORTED_METHOD internal_downgrade()
Out of line code for downgrading a writer to a reader.
static const state_t ONE_READER
static const state_t WRITER
The graph class.
#define _T(string_literal)
Standard Windows style macro to markup the string literals.
Definition: itt_notify.h:66
static const state_t WRITER_PENDING
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
state_t state
State of lock.
void __TBB_EXPORTED_METHOD internal_release_writer()
Out of line code for releasing a write lock.
#define ITT_NOTIFY(name, obj)
Definition: itt_notify.h:120
void const char const char int ITT_FORMAT __itt_group_sync s
bool __TBB_EXPORTED_METHOD internal_try_acquire_writer()
Internal try_acquire write lock.
atomic< T > & as_atomic(T &t)
Definition: atomic.h:547
bool __TBB_EXPORTED_METHOD internal_upgrade()
Internal upgrade reader to become a writer.
static const state_t READERS
void __TBB_AtomicOR(volatile void *operand, uintptr_t addend)
Definition: tbb_machine.h:882

Copyright © 2005-2019 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.