BRE12
_x86_rtm_rw_mutex_impl.h
1 /*
2  Copyright 2005-2016 Intel Corporation. All Rights Reserved.
3 
4  This file is part of Threading Building Blocks. Threading Building Blocks is free software;
5  you can redistribute it and/or modify it under the terms of the GNU General Public License
6  version 2 as published by the Free Software Foundation. Threading Building Blocks is
7  distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9  See the GNU General Public License for more details. You should have received a copy of
10  the GNU General Public License along with Threading Building Blocks; if not, write to the
11  Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12 
13  As a special exception, you may use this file as part of a free software library without
14  restriction. Specifically, if other files instantiate templates or use macros or inline
15  functions from this file, or you compile this file and link it with other files to produce
16  an executable, this file does not by itself cause the resulting executable to be covered
17  by the GNU General Public License. This exception does not however invalidate any other
18  reasons why the executable file might be covered by the GNU General Public License.
19 */
20 
21 #ifndef __TBB__x86_rtm_rw_mutex_impl_H
22 #define __TBB__x86_rtm_rw_mutex_impl_H
23 
24 #ifndef __TBB_spin_rw_mutex_H
25 #error Do not #include this internal file directly; use public TBB headers instead.
26 #endif
27 
28 #if __TBB_TSX_AVAILABLE
29 
30 #include "../tbb_stddef.h"
31 #include "../tbb_machine.h"
32 #include "../tbb_profiling.h"
33 #include "../spin_rw_mutex.h"
34 
35 namespace tbb {
36 namespace interface8 {
37 namespace internal {
38 
39 enum RTM_type {
40  RTM_not_in_mutex,
41  RTM_transacting_reader,
42  RTM_transacting_writer,
43  RTM_real_reader,
44  RTM_real_writer
45 };
46 
47 static const unsigned long speculation_granularity = 64;
48 
50 // writer-preference
52 class x86_rtm_rw_mutex: private spin_rw_mutex {
53 #if __TBB_USE_X86_RTM_RW_MUTEX || __TBB_GCC_VERSION < 40000
54 // bug in gcc 3.x.x causes syntax error in spite of the friend declaration below.
55 // Make the scoped_lock public in that case.
56 public:
57 #else
58 private:
59 #endif
60  friend class interface7::internal::padded_mutex<x86_rtm_rw_mutex,true>;
61  class scoped_lock; // should be private
62  friend class scoped_lock;
63 private:
65 
67  void __TBB_EXPORTED_METHOD internal_construct();
68 
70  // only_speculate == true if we're doing a try_lock, else false.
71  void __TBB_EXPORTED_METHOD internal_acquire_writer(x86_rtm_rw_mutex::scoped_lock&, bool only_speculate=false);
72 
74  // only_speculate == true if we're doing a try_lock, else false.
75  void __TBB_EXPORTED_METHOD internal_acquire_reader(x86_rtm_rw_mutex::scoped_lock&, bool only_speculate=false);
76 
78  bool __TBB_EXPORTED_METHOD internal_upgrade( x86_rtm_rw_mutex::scoped_lock& );
79 
81  bool __TBB_EXPORTED_METHOD internal_downgrade( x86_rtm_rw_mutex::scoped_lock& );
82 
84  bool __TBB_EXPORTED_METHOD internal_try_acquire_writer( x86_rtm_rw_mutex::scoped_lock& );
85 
87  void __TBB_EXPORTED_METHOD internal_release( x86_rtm_rw_mutex::scoped_lock& );
88 
89  static x86_rtm_rw_mutex* internal_get_mutex( const spin_rw_mutex::scoped_lock& lock )
90  {
91  return static_cast<x86_rtm_rw_mutex*>( lock.internal_get_mutex() );
92  }
93  static void internal_set_mutex( spin_rw_mutex::scoped_lock& lock, spin_rw_mutex* mtx )
94  {
95  lock.internal_set_mutex( mtx );
96  }
98 public:
100  x86_rtm_rw_mutex() {
101  w_flag = false;
102 #if TBB_USE_THREADING_TOOLS
103  internal_construct();
104 #endif
105  }
106 
107 #if TBB_USE_ASSERT
108  ~x86_rtm_rw_mutex() {}
110 #endif /* TBB_USE_ASSERT */
111 
112  // Mutex traits
113  static const bool is_rw_mutex = true;
114  static const bool is_recursive_mutex = false;
115  static const bool is_fair_mutex = false;
116 
117 #if __TBB_USE_X86_RTM_RW_MUTEX || __TBB_GCC_VERSION < 40000
118 #else
119  // by default we will not provide the scoped_lock interface. The user
120  // should use the padded version of the mutex. scoped_lock is used in
121  // padded_mutex template.
122 private:
123 #endif
124 
127  // Speculation-enabled scoped lock for spin_rw_mutex
128  // The idea is to be able to reuse the acquire/release methods of spin_rw_mutex
129  // and its scoped lock wherever possible. The only way to use a speculative lock is to use
130  // a scoped_lock. (because transaction_state must be local)
131 
132  class scoped_lock : tbb::internal::no_copy {
133  friend class x86_rtm_rw_mutex;
134  spin_rw_mutex::scoped_lock my_scoped_lock;
135 
136  RTM_type transaction_state;
137 
138  public:
140 
141  scoped_lock() : my_scoped_lock(), transaction_state(RTM_not_in_mutex) {
142  }
143 
145  scoped_lock( x86_rtm_rw_mutex& m, bool write = true ) : my_scoped_lock(),
146  transaction_state(RTM_not_in_mutex) {
147  acquire(m, write);
148  }
149 
151  ~scoped_lock() {
152  if(transaction_state != RTM_not_in_mutex) release();
153  }
154 
156  void acquire( x86_rtm_rw_mutex& m, bool write = true ) {
157  if( write ) m.internal_acquire_writer(*this);
158  else m.internal_acquire_reader(*this);
159  }
160 
162  void release() {
163  x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
164  __TBB_ASSERT( mutex, "lock is not acquired" );
165  __TBB_ASSERT( transaction_state!=RTM_not_in_mutex, "lock is not acquired" );
166  return mutex->internal_release(*this);
167  }
168 
170 
171  bool upgrade_to_writer() {
172  x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
173  __TBB_ASSERT( mutex, "lock is not acquired" );
174  __TBB_ASSERT( transaction_state==RTM_transacting_reader || transaction_state==RTM_real_reader, "Invalid state for upgrade" );
175  return mutex->internal_upgrade(*this);
176  }
177 
179 
180  bool downgrade_to_reader() {
181  x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
182  __TBB_ASSERT( mutex, "lock is not acquired" );
183  __TBB_ASSERT( transaction_state==RTM_transacting_writer || transaction_state==RTM_real_writer, "Invalid state for downgrade" );
184  return mutex->internal_downgrade(*this);
185  }
186 
188 
189  bool try_acquire( x86_rtm_rw_mutex& m, bool write = true ) {
190 #if TBB_USE_ASSERT
191  x86_rtm_rw_mutex* mutex = x86_rtm_rw_mutex::internal_get_mutex(my_scoped_lock);
192  __TBB_ASSERT( !mutex, "lock is already acquired" );
193 #endif
194  // have to assign m to our mutex.
195  // cannot set the mutex, because try_acquire in spin_rw_mutex depends on it being NULL.
196  if(write) return m.internal_try_acquire_writer(*this);
197  // speculatively acquire the lock. If this fails, do try_acquire on the spin_rw_mutex.
198  m.internal_acquire_reader(*this, /*only_speculate=*/true);
199  if(transaction_state == RTM_transacting_reader) return true;
200  if( my_scoped_lock.try_acquire(m, false)) {
201  transaction_state = RTM_real_reader;
202  return true;
203  }
204  return false;
205  }
206 
207  }; // class x86_rtm_rw_mutex::scoped_lock
208 
209  // ISO C++0x compatibility methods not provided because we cannot maintain
210  // state about whether a thread is in a transaction.
211 
212 private:
213  char pad[speculation_granularity-sizeof(spin_rw_mutex)]; // padding
214 
215  // If true, writer holds the spin_rw_mutex.
216  tbb::atomic<bool> w_flag; // want this on a separate cache line
217 
218 }; // x86_rtm_rw_mutex
219 
220 } // namespace internal
221 } // namespace interface8
222 } // namespace tbb
223 
224 #endif /* __TBB_TSX_AVAILABLE */
225 #endif /* __TBB__x86_rtm_rw_mutex_impl_H */
Acquire.
Definition: atomic.h:47
Definition: _flow_graph_async_msg_impl.h:32
Release.
Definition: atomic.h:49
The namespace tbb contains all components of the library.
Definition: parallel_for.h:44