annotate libitm/beginend.cc @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2008-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2 Contributed by Richard Henderson <rth@redhat.com>.
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of the GNU Transactional Memory Library (libitm).
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 Libitm is free software; you can redistribute it and/or modify it
kono
parents:
diff changeset
7 under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
8 the Free Software Foundation; either version 3 of the License, or
kono
parents:
diff changeset
9 (at your option) any later version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
kono
parents:
diff changeset
13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
kono
parents:
diff changeset
14 more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
17 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
18 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
21 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
23 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
24
kono
parents:
diff changeset
25 #include "libitm_i.h"
kono
parents:
diff changeset
26 #include <pthread.h>
kono
parents:
diff changeset
27
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 using namespace GTM;
kono
parents:
diff changeset
30
kono
parents:
diff changeset
31 #if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP)
kono
parents:
diff changeset
32 extern __thread gtm_thread_tls _gtm_thr_tls;
kono
parents:
diff changeset
33 #endif
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 // Put this at the start of a cacheline so that serial_lock's writers and
kono
parents:
diff changeset
36 // htm_fastpath fields are on the same cacheline, so that HW transactions
kono
parents:
diff changeset
37 // only have to pay one cacheline capacity to monitor both.
kono
parents:
diff changeset
38 gtm_rwlock GTM::gtm_thread::serial_lock
kono
parents:
diff changeset
39 __attribute__((aligned(HW_CACHELINE_SIZE)));
kono
parents:
diff changeset
40 gtm_thread *GTM::gtm_thread::list_of_threads = 0;
kono
parents:
diff changeset
41 unsigned GTM::gtm_thread::number_of_threads = 0;
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 /* ??? Move elsewhere when we figure out library initialization. */
kono
parents:
diff changeset
44 uint64_t GTM::gtm_spin_count_var = 1000;
kono
parents:
diff changeset
45
kono
parents:
diff changeset
46 #ifdef HAVE_64BIT_SYNC_BUILTINS
kono
parents:
diff changeset
47 static atomic<_ITM_transactionId_t> global_tid;
kono
parents:
diff changeset
48 #else
kono
parents:
diff changeset
49 static _ITM_transactionId_t global_tid;
kono
parents:
diff changeset
50 static pthread_mutex_t global_tid_lock = PTHREAD_MUTEX_INITIALIZER;
kono
parents:
diff changeset
51 #endif
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53
kono
parents:
diff changeset
54 // Provides a on-thread-exit callback used to release per-thread data.
kono
parents:
diff changeset
55 static pthread_key_t thr_release_key;
kono
parents:
diff changeset
56 static pthread_once_t thr_release_once = PTHREAD_ONCE_INIT;
kono
parents:
diff changeset
57
kono
parents:
diff changeset
58 /* Allocate a transaction structure. */
kono
parents:
diff changeset
59 void *
kono
parents:
diff changeset
60 GTM::gtm_thread::operator new (size_t s)
kono
parents:
diff changeset
61 {
kono
parents:
diff changeset
62 void *tx;
kono
parents:
diff changeset
63
kono
parents:
diff changeset
64 assert(s == sizeof(gtm_thread));
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 tx = xmalloc (sizeof (gtm_thread), true);
kono
parents:
diff changeset
67 memset (tx, 0, sizeof (gtm_thread));
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 return tx;
kono
parents:
diff changeset
70 }
kono
parents:
diff changeset
71
kono
parents:
diff changeset
72 /* Free the given transaction. Raises an error if the transaction is still
kono
parents:
diff changeset
73 in use. */
kono
parents:
diff changeset
74 void
kono
parents:
diff changeset
75 GTM::gtm_thread::operator delete(void *tx)
kono
parents:
diff changeset
76 {
kono
parents:
diff changeset
77 free(tx);
kono
parents:
diff changeset
78 }
kono
parents:
diff changeset
79
kono
parents:
diff changeset
80 static void
kono
parents:
diff changeset
81 thread_exit_handler(void *)
kono
parents:
diff changeset
82 {
kono
parents:
diff changeset
83 gtm_thread *thr = gtm_thr();
kono
parents:
diff changeset
84 if (thr)
kono
parents:
diff changeset
85 delete thr;
kono
parents:
diff changeset
86 set_gtm_thr(0);
kono
parents:
diff changeset
87 }
kono
parents:
diff changeset
88
kono
parents:
diff changeset
89 static void
kono
parents:
diff changeset
90 thread_exit_init()
kono
parents:
diff changeset
91 {
kono
parents:
diff changeset
92 if (pthread_key_create(&thr_release_key, thread_exit_handler))
kono
parents:
diff changeset
93 GTM_fatal("Creating thread release TLS key failed.");
kono
parents:
diff changeset
94 }
kono
parents:
diff changeset
95
kono
parents:
diff changeset
96
kono
parents:
diff changeset
97 GTM::gtm_thread::~gtm_thread()
kono
parents:
diff changeset
98 {
kono
parents:
diff changeset
99 if (nesting > 0)
kono
parents:
diff changeset
100 GTM_fatal("Thread exit while a transaction is still active.");
kono
parents:
diff changeset
101
kono
parents:
diff changeset
102 // Deregister this transaction.
kono
parents:
diff changeset
103 serial_lock.write_lock ();
kono
parents:
diff changeset
104 gtm_thread **prev = &list_of_threads;
kono
parents:
diff changeset
105 for (; *prev; prev = &(*prev)->next_thread)
kono
parents:
diff changeset
106 {
kono
parents:
diff changeset
107 if (*prev == this)
kono
parents:
diff changeset
108 {
kono
parents:
diff changeset
109 *prev = (*prev)->next_thread;
kono
parents:
diff changeset
110 break;
kono
parents:
diff changeset
111 }
kono
parents:
diff changeset
112 }
kono
parents:
diff changeset
113 number_of_threads--;
kono
parents:
diff changeset
114 number_of_threads_changed(number_of_threads + 1, number_of_threads);
kono
parents:
diff changeset
115 serial_lock.write_unlock ();
kono
parents:
diff changeset
116 }
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 GTM::gtm_thread::gtm_thread ()
kono
parents:
diff changeset
119 {
kono
parents:
diff changeset
120 // This object's memory has been set to zero by operator new, so no need
kono
parents:
diff changeset
121 // to initialize any of the other primitive-type members that do not have
kono
parents:
diff changeset
122 // constructors.
kono
parents:
diff changeset
123 shared_state.store(-1, memory_order_relaxed);
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 // Register this transaction with the list of all threads' transactions.
kono
parents:
diff changeset
126 serial_lock.write_lock ();
kono
parents:
diff changeset
127 next_thread = list_of_threads;
kono
parents:
diff changeset
128 list_of_threads = this;
kono
parents:
diff changeset
129 number_of_threads++;
kono
parents:
diff changeset
130 number_of_threads_changed(number_of_threads - 1, number_of_threads);
kono
parents:
diff changeset
131 serial_lock.write_unlock ();
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 init_cpp_exceptions ();
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 if (pthread_once(&thr_release_once, thread_exit_init))
kono
parents:
diff changeset
136 GTM_fatal("Initializing thread release TLS key failed.");
kono
parents:
diff changeset
137 // Any non-null value is sufficient to trigger destruction of this
kono
parents:
diff changeset
138 // transaction when the current thread terminates.
kono
parents:
diff changeset
139 if (pthread_setspecific(thr_release_key, this))
kono
parents:
diff changeset
140 GTM_fatal("Setting thread release TLS key failed.");
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142
kono
parents:
diff changeset
143 static inline uint32_t
kono
parents:
diff changeset
144 choose_code_path(uint32_t prop, abi_dispatch *disp)
kono
parents:
diff changeset
145 {
kono
parents:
diff changeset
146 if ((prop & pr_uninstrumentedCode) && disp->can_run_uninstrumented_code())
kono
parents:
diff changeset
147 return a_runUninstrumentedCode;
kono
parents:
diff changeset
148 else
kono
parents:
diff changeset
149 return a_runInstrumentedCode;
kono
parents:
diff changeset
150 }
kono
parents:
diff changeset
151
kono
parents:
diff changeset
152 #ifdef TARGET_BEGIN_TRANSACTION_ATTRIBUTE
kono
parents:
diff changeset
153 /* This macro can be used to define target specific attributes for this
kono
parents:
diff changeset
154 function. For example, S/390 requires floating point to be disabled in
kono
parents:
diff changeset
155 begin_transaction. */
kono
parents:
diff changeset
156 TARGET_BEGIN_TRANSACTION_ATTRIBUTE
kono
parents:
diff changeset
157 #endif
kono
parents:
diff changeset
158 uint32_t
kono
parents:
diff changeset
159 GTM::gtm_thread::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
kono
parents:
diff changeset
160 {
kono
parents:
diff changeset
161 static const _ITM_transactionId_t tid_block_size = 1 << 16;
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 gtm_thread *tx;
kono
parents:
diff changeset
164 abi_dispatch *disp;
kono
parents:
diff changeset
165 uint32_t ret;
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 // ??? pr_undoLogCode is not properly defined in the ABI. Are barriers
kono
parents:
diff changeset
168 // omitted because they are not necessary (e.g., a transaction on thread-
kono
parents:
diff changeset
169 // local data) or because the compiler thinks that some kind of global
kono
parents:
diff changeset
170 // synchronization might perform better?
kono
parents:
diff changeset
171 if (unlikely(prop & pr_undoLogCode))
kono
parents:
diff changeset
172 GTM_fatal("pr_undoLogCode not supported");
kono
parents:
diff changeset
173
kono
parents:
diff changeset
174 #ifdef USE_HTM_FASTPATH
kono
parents:
diff changeset
175 // HTM fastpath. Only chosen in the absence of transaction_cancel to allow
kono
parents:
diff changeset
176 // using an uninstrumented code path.
kono
parents:
diff changeset
177 // The fastpath is enabled only by dispatch_htm's method group, which uses
kono
parents:
diff changeset
178 // serial-mode methods as fallback. Serial-mode transactions cannot execute
kono
parents:
diff changeset
179 // concurrently with HW transactions because the latter monitor the serial
kono
parents:
diff changeset
180 // lock's writer flag and thus abort if another thread is or becomes a
kono
parents:
diff changeset
181 // serial transaction. Therefore, if the fastpath is enabled, then a
kono
parents:
diff changeset
182 // transaction is not executing as a HW transaction iff the serial lock is
kono
parents:
diff changeset
183 // write-locked. Also, HW transactions monitor the fastpath control
kono
parents:
diff changeset
184 // variable, so that they will only execute if dispatch_htm is still the
kono
parents:
diff changeset
185 // current method group. This allows us to use htm_fastpath and the serial
kono
parents:
diff changeset
186 // lock's writers flag to reliable determine whether the current thread runs
kono
parents:
diff changeset
187 // a HW transaction, and thus we do not need to maintain this information in
kono
parents:
diff changeset
188 // per-thread state.
kono
parents:
diff changeset
189 // If an uninstrumented code path is not available, we can still run
kono
parents:
diff changeset
190 // instrumented code from a HW transaction because the HTM fastpath kicks
kono
parents:
diff changeset
191 // in early in both begin and commit, and the transaction is not canceled.
kono
parents:
diff changeset
192 // HW transactions might get requests to switch to serial-irrevocable mode,
kono
parents:
diff changeset
193 // but these can be ignored because the HTM provides all necessary
kono
parents:
diff changeset
194 // correctness guarantees. Transactions cannot detect whether they are
kono
parents:
diff changeset
195 // indeed in serial mode, and HW transactions should never need serial mode
kono
parents:
diff changeset
196 // for any internal changes (e.g., they never abort visibly to the STM code
kono
parents:
diff changeset
197 // and thus do not trigger the standard retry handling).
kono
parents:
diff changeset
198 #ifndef HTM_CUSTOM_FASTPATH
kono
parents:
diff changeset
199 if (likely(serial_lock.get_htm_fastpath() && (prop & pr_hasNoAbort)))
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 // Note that the snapshot of htm_fastpath that we take here could be
kono
parents:
diff changeset
202 // outdated, and a different method group than dispatch_htm may have
kono
parents:
diff changeset
203 // been chosen in the meantime. Therefore, take care not not touch
kono
parents:
diff changeset
204 // anything besides the serial lock, which is independent of method
kono
parents:
diff changeset
205 // groups.
kono
parents:
diff changeset
206 for (uint32_t t = serial_lock.get_htm_fastpath(); t; t--)
kono
parents:
diff changeset
207 {
kono
parents:
diff changeset
208 uint32_t ret = htm_begin();
kono
parents:
diff changeset
209 if (htm_begin_success(ret))
kono
parents:
diff changeset
210 {
kono
parents:
diff changeset
211 // We are executing a transaction now.
kono
parents:
diff changeset
212 // Monitor the writer flag in the serial-mode lock, and abort
kono
parents:
diff changeset
213 // if there is an active or waiting serial-mode transaction.
kono
parents:
diff changeset
214 // Also checks that htm_fastpath is still nonzero and thus
kono
parents:
diff changeset
215 // HW transactions are allowed to run.
kono
parents:
diff changeset
216 // Note that this can also happen due to an enclosing
kono
parents:
diff changeset
217 // serial-mode transaction; we handle this case below.
kono
parents:
diff changeset
218 if (unlikely(serial_lock.htm_fastpath_disabled()))
kono
parents:
diff changeset
219 htm_abort();
kono
parents:
diff changeset
220 else
kono
parents:
diff changeset
221 // We do not need to set a_saveLiveVariables because of HTM.
kono
parents:
diff changeset
222 return (prop & pr_uninstrumentedCode) ?
kono
parents:
diff changeset
223 a_runUninstrumentedCode : a_runInstrumentedCode;
kono
parents:
diff changeset
224 }
kono
parents:
diff changeset
225 // The transaction has aborted. Don't retry if it's unlikely that
kono
parents:
diff changeset
226 // retrying the transaction will be successful.
kono
parents:
diff changeset
227 if (!htm_abort_should_retry(ret))
kono
parents:
diff changeset
228 break;
kono
parents:
diff changeset
229 // Check whether the HTM fastpath has been disabled.
kono
parents:
diff changeset
230 if (!serial_lock.get_htm_fastpath())
kono
parents:
diff changeset
231 break;
kono
parents:
diff changeset
232 // Wait until any concurrent serial-mode transactions have finished.
kono
parents:
diff changeset
233 // This is an empty critical section, but won't be elided.
kono
parents:
diff changeset
234 if (serial_lock.htm_fastpath_disabled())
kono
parents:
diff changeset
235 {
kono
parents:
diff changeset
236 tx = gtm_thr();
kono
parents:
diff changeset
237 if (unlikely(tx == NULL))
kono
parents:
diff changeset
238 {
kono
parents:
diff changeset
239 // See below.
kono
parents:
diff changeset
240 tx = new gtm_thread();
kono
parents:
diff changeset
241 set_gtm_thr(tx);
kono
parents:
diff changeset
242 }
kono
parents:
diff changeset
243 // Check whether there is an enclosing serial-mode transaction;
kono
parents:
diff changeset
244 // if so, we just continue as a nested transaction and don't
kono
parents:
diff changeset
245 // try to use the HTM fastpath. This case can happen when an
kono
parents:
diff changeset
246 // outermost relaxed transaction calls unsafe code that starts
kono
parents:
diff changeset
247 // a transaction.
kono
parents:
diff changeset
248 if (tx->nesting > 0)
kono
parents:
diff changeset
249 break;
kono
parents:
diff changeset
250 // Another thread is running a serial-mode transaction. Wait.
kono
parents:
diff changeset
251 serial_lock.read_lock(tx);
kono
parents:
diff changeset
252 serial_lock.read_unlock(tx);
kono
parents:
diff changeset
253 // TODO We should probably reset the retry count t here, unless
kono
parents:
diff changeset
254 // we have retried so often that we should go serial to avoid
kono
parents:
diff changeset
255 // starvation.
kono
parents:
diff changeset
256 }
kono
parents:
diff changeset
257 }
kono
parents:
diff changeset
258 }
kono
parents:
diff changeset
259 #else
kono
parents:
diff changeset
260 // If we have a custom HTM fastpath in ITM_beginTransaction, we implement
kono
parents:
diff changeset
261 // just the retry policy here. We communicate with the custom fastpath
kono
parents:
diff changeset
262 // through additional property bits and return codes, and either transfer
kono
parents:
diff changeset
263 // control back to the custom fastpath or run the fallback mechanism. The
kono
parents:
diff changeset
264 // fastpath synchronization algorithm itself is the same.
kono
parents:
diff changeset
265 // pr_HTMRetryableAbort states that a HW transaction started by the custom
kono
parents:
diff changeset
266 // HTM fastpath aborted, and that we thus have to decide whether to retry
kono
parents:
diff changeset
267 // the fastpath (returning a_tryHTMFastPath) or just proceed with the
kono
parents:
diff changeset
268 // fallback method.
kono
parents:
diff changeset
269 if (likely(serial_lock.get_htm_fastpath() && (prop & pr_HTMRetryableAbort)))
kono
parents:
diff changeset
270 {
kono
parents:
diff changeset
271 tx = gtm_thr();
kono
parents:
diff changeset
272 if (unlikely(tx == NULL))
kono
parents:
diff changeset
273 {
kono
parents:
diff changeset
274 // See below.
kono
parents:
diff changeset
275 tx = new gtm_thread();
kono
parents:
diff changeset
276 set_gtm_thr(tx);
kono
parents:
diff changeset
277 }
kono
parents:
diff changeset
278 // If this is the first abort, reset the retry count. We abuse
kono
parents:
diff changeset
279 // restart_total for the retry count, which is fine because our only
kono
parents:
diff changeset
280 // other fallback will use serial transactions, which don't use
kono
parents:
diff changeset
281 // restart_total but will reset it when committing.
kono
parents:
diff changeset
282 if (!(prop & pr_HTMRetriedAfterAbort))
kono
parents:
diff changeset
283 tx->restart_total = gtm_thread::serial_lock.get_htm_fastpath();
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 if (--tx->restart_total > 0)
kono
parents:
diff changeset
286 {
kono
parents:
diff changeset
287 // Wait until any concurrent serial-mode transactions have finished.
kono
parents:
diff changeset
288 // Essentially the same code as above.
kono
parents:
diff changeset
289 if (!serial_lock.get_htm_fastpath())
kono
parents:
diff changeset
290 goto stop_custom_htm_fastpath;
kono
parents:
diff changeset
291 if (serial_lock.htm_fastpath_disabled())
kono
parents:
diff changeset
292 {
kono
parents:
diff changeset
293 if (tx->nesting > 0)
kono
parents:
diff changeset
294 goto stop_custom_htm_fastpath;
kono
parents:
diff changeset
295 serial_lock.read_lock(tx);
kono
parents:
diff changeset
296 serial_lock.read_unlock(tx);
kono
parents:
diff changeset
297 }
kono
parents:
diff changeset
298 // Let ITM_beginTransaction retry the custom HTM fastpath.
kono
parents:
diff changeset
299 return a_tryHTMFastPath;
kono
parents:
diff changeset
300 }
kono
parents:
diff changeset
301 }
kono
parents:
diff changeset
302 stop_custom_htm_fastpath:
kono
parents:
diff changeset
303 #endif
kono
parents:
diff changeset
304 #endif
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 tx = gtm_thr();
kono
parents:
diff changeset
307 if (unlikely(tx == NULL))
kono
parents:
diff changeset
308 {
kono
parents:
diff changeset
309 // Create the thread object. The constructor will also set up automatic
kono
parents:
diff changeset
310 // deletion on thread termination.
kono
parents:
diff changeset
311 tx = new gtm_thread();
kono
parents:
diff changeset
312 set_gtm_thr(tx);
kono
parents:
diff changeset
313 }
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 if (tx->nesting > 0)
kono
parents:
diff changeset
316 {
kono
parents:
diff changeset
317 // This is a nested transaction.
kono
parents:
diff changeset
318 // Check prop compatibility:
kono
parents:
diff changeset
319 // The ABI requires pr_hasNoFloatUpdate, pr_hasNoVectorUpdate,
kono
parents:
diff changeset
320 // pr_hasNoIrrevocable, pr_aWBarriersOmitted, pr_RaRBarriersOmitted, and
kono
parents:
diff changeset
321 // pr_hasNoSimpleReads to hold for the full dynamic scope of a
kono
parents:
diff changeset
322 // transaction. We could check that these are set for the nested
kono
parents:
diff changeset
323 // transaction if they are also set for the parent transaction, but the
kono
parents:
diff changeset
324 // ABI does not require these flags to be set if they could be set,
kono
parents:
diff changeset
325 // so the check could be too strict.
kono
parents:
diff changeset
326 // ??? For pr_readOnly, lexical or dynamic scope is unspecified.
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 if (prop & pr_hasNoAbort)
kono
parents:
diff changeset
329 {
kono
parents:
diff changeset
330 // We can use flat nesting, so elide this transaction.
kono
parents:
diff changeset
331 if (!(prop & pr_instrumentedCode))
kono
parents:
diff changeset
332 {
kono
parents:
diff changeset
333 if (!(tx->state & STATE_SERIAL) ||
kono
parents:
diff changeset
334 !(tx->state & STATE_IRREVOCABLE))
kono
parents:
diff changeset
335 tx->serialirr_mode();
kono
parents:
diff changeset
336 }
kono
parents:
diff changeset
337 // Increment nesting level after checking that we have a method that
kono
parents:
diff changeset
338 // allows us to continue.
kono
parents:
diff changeset
339 tx->nesting++;
kono
parents:
diff changeset
340 return choose_code_path(prop, abi_disp());
kono
parents:
diff changeset
341 }
kono
parents:
diff changeset
342
kono
parents:
diff changeset
343 // The transaction might abort, so use closed nesting if possible.
kono
parents:
diff changeset
344 // pr_hasNoAbort has lexical scope, so the compiler should really have
kono
parents:
diff changeset
345 // generated an instrumented code path.
kono
parents:
diff changeset
346 assert(prop & pr_instrumentedCode);
kono
parents:
diff changeset
347
kono
parents:
diff changeset
348 // Create a checkpoint of the current transaction.
kono
parents:
diff changeset
349 gtm_transaction_cp *cp = tx->parent_txns.push();
kono
parents:
diff changeset
350 cp->save(tx);
kono
parents:
diff changeset
351 new (&tx->alloc_actions) aa_tree<uintptr_t, gtm_alloc_action>();
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 // Check whether the current method actually supports closed nesting.
kono
parents:
diff changeset
354 // If we can switch to another one, do so.
kono
parents:
diff changeset
355 // If not, we assume that actual aborts are infrequent, and rather
kono
parents:
diff changeset
356 // restart in _ITM_abortTransaction when we really have to.
kono
parents:
diff changeset
357 disp = abi_disp();
kono
parents:
diff changeset
358 if (!disp->closed_nesting())
kono
parents:
diff changeset
359 {
kono
parents:
diff changeset
360 // ??? Should we elide the transaction if there is no alternative
kono
parents:
diff changeset
361 // method that supports closed nesting? If we do, we need to set
kono
parents:
diff changeset
362 // some flag to prevent _ITM_abortTransaction from aborting the
kono
parents:
diff changeset
363 // wrong transaction (i.e., some parent transaction).
kono
parents:
diff changeset
364 abi_dispatch *cn_disp = disp->closed_nesting_alternative();
kono
parents:
diff changeset
365 if (cn_disp)
kono
parents:
diff changeset
366 {
kono
parents:
diff changeset
367 disp = cn_disp;
kono
parents:
diff changeset
368 set_abi_disp(disp);
kono
parents:
diff changeset
369 }
kono
parents:
diff changeset
370 }
kono
parents:
diff changeset
371 }
kono
parents:
diff changeset
372 else
kono
parents:
diff changeset
373 {
kono
parents:
diff changeset
374 // Outermost transaction
kono
parents:
diff changeset
375 disp = tx->decide_begin_dispatch (prop);
kono
parents:
diff changeset
376 set_abi_disp (disp);
kono
parents:
diff changeset
377 }
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 // Initialization that is common for outermost and nested transactions.
kono
parents:
diff changeset
380 tx->prop = prop;
kono
parents:
diff changeset
381 tx->nesting++;
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 tx->jb = *jb;
kono
parents:
diff changeset
384
kono
parents:
diff changeset
385 // As long as we have not exhausted a previously allocated block of TIDs,
kono
parents:
diff changeset
386 // we can avoid an atomic operation on a shared cacheline.
kono
parents:
diff changeset
387 if (tx->local_tid & (tid_block_size - 1))
kono
parents:
diff changeset
388 tx->id = tx->local_tid++;
kono
parents:
diff changeset
389 else
kono
parents:
diff changeset
390 {
kono
parents:
diff changeset
391 #ifdef HAVE_64BIT_SYNC_BUILTINS
kono
parents:
diff changeset
392 // We don't really care which block of TIDs we get but only that we
kono
parents:
diff changeset
393 // acquire one atomically; therefore, relaxed memory order is
kono
parents:
diff changeset
394 // sufficient.
kono
parents:
diff changeset
395 tx->id = global_tid.fetch_add(tid_block_size, memory_order_relaxed);
kono
parents:
diff changeset
396 tx->local_tid = tx->id + 1;
kono
parents:
diff changeset
397 #else
kono
parents:
diff changeset
398 pthread_mutex_lock (&global_tid_lock);
kono
parents:
diff changeset
399 global_tid += tid_block_size;
kono
parents:
diff changeset
400 tx->id = global_tid;
kono
parents:
diff changeset
401 tx->local_tid = tx->id + 1;
kono
parents:
diff changeset
402 pthread_mutex_unlock (&global_tid_lock);
kono
parents:
diff changeset
403 #endif
kono
parents:
diff changeset
404 }
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 // Log the number of uncaught exceptions if we might have to roll back this
kono
parents:
diff changeset
407 // state.
kono
parents:
diff changeset
408 if (tx->cxa_uncaught_count_ptr != 0)
kono
parents:
diff changeset
409 tx->cxa_uncaught_count = *tx->cxa_uncaught_count_ptr;
kono
parents:
diff changeset
410
kono
parents:
diff changeset
411 // Run dispatch-specific restart code. Retry until we succeed.
kono
parents:
diff changeset
412 GTM::gtm_restart_reason rr;
kono
parents:
diff changeset
413 while ((rr = disp->begin_or_restart()) != NO_RESTART)
kono
parents:
diff changeset
414 {
kono
parents:
diff changeset
415 tx->decide_retry_strategy(rr);
kono
parents:
diff changeset
416 disp = abi_disp();
kono
parents:
diff changeset
417 }
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 // Determine the code path to run. Only irrevocable transactions cannot be
kono
parents:
diff changeset
420 // restarted, so all other transactions need to save live variables.
kono
parents:
diff changeset
421 ret = choose_code_path(prop, disp);
kono
parents:
diff changeset
422 if (!(tx->state & STATE_IRREVOCABLE))
kono
parents:
diff changeset
423 ret |= a_saveLiveVariables;
kono
parents:
diff changeset
424 return ret;
kono
parents:
diff changeset
425 }
kono
parents:
diff changeset
426
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 void
kono
parents:
diff changeset
429 GTM::gtm_transaction_cp::save(gtm_thread* tx)
kono
parents:
diff changeset
430 {
kono
parents:
diff changeset
431 // Save everything that we might have to restore on restarts or aborts.
kono
parents:
diff changeset
432 jb = tx->jb;
kono
parents:
diff changeset
433 undolog_size = tx->undolog.size();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
434
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
435 /* FIXME! Assignment of an aatree like alloc_actions is unsafe; if either
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
436 *this or *tx is destroyed, the other ends up pointing to a freed node. */
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
437 #pragma GCC diagnostic warning "-Wdeprecated-copy"
111
kono
parents:
diff changeset
438 alloc_actions = tx->alloc_actions;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
439
111
kono
parents:
diff changeset
440 user_actions_size = tx->user_actions.size();
kono
parents:
diff changeset
441 id = tx->id;
kono
parents:
diff changeset
442 prop = tx->prop;
kono
parents:
diff changeset
443 cxa_catch_count = tx->cxa_catch_count;
kono
parents:
diff changeset
444 cxa_uncaught_count = tx->cxa_uncaught_count;
kono
parents:
diff changeset
445 disp = abi_disp();
kono
parents:
diff changeset
446 nesting = tx->nesting;
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 void
kono
parents:
diff changeset
450 GTM::gtm_transaction_cp::commit(gtm_thread* tx)
kono
parents:
diff changeset
451 {
kono
parents:
diff changeset
452 // Restore state that is not persistent across commits. Exception handling,
kono
parents:
diff changeset
453 // information, nesting level, and any logs do not need to be restored on
kono
parents:
diff changeset
454 // commits of nested transactions. Allocation actions must be committed
kono
parents:
diff changeset
455 // before committing the snapshot.
kono
parents:
diff changeset
456 tx->jb = jb;
kono
parents:
diff changeset
457 tx->alloc_actions = alloc_actions;
kono
parents:
diff changeset
458 tx->id = id;
kono
parents:
diff changeset
459 tx->prop = prop;
kono
parents:
diff changeset
460 }
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 void
kono
parents:
diff changeset
464 GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool aborting)
kono
parents:
diff changeset
465 {
kono
parents:
diff changeset
466 // The undo log is special in that it used for both thread-local and shared
kono
parents:
diff changeset
467 // data. Because of the latter, we have to roll it back before any
kono
parents:
diff changeset
468 // dispatch-specific rollback (which handles synchronization with other
kono
parents:
diff changeset
469 // transactions).
kono
parents:
diff changeset
470 undolog.rollback (this, cp ? cp->undolog_size : 0);
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 // Perform dispatch-specific rollback.
kono
parents:
diff changeset
473 abi_disp()->rollback (cp);
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 // Roll back all actions that are supposed to happen around the transaction.
kono
parents:
diff changeset
476 rollback_user_actions (cp ? cp->user_actions_size : 0);
kono
parents:
diff changeset
477 commit_allocations (true, (cp ? &cp->alloc_actions : 0));
kono
parents:
diff changeset
478 revert_cpp_exceptions (cp);
kono
parents:
diff changeset
479
kono
parents:
diff changeset
480 if (cp)
kono
parents:
diff changeset
481 {
kono
parents:
diff changeset
482 // We do not yet handle restarts of nested transactions. To do that, we
kono
parents:
diff changeset
483 // would have to restore some state (jb, id, prop, nesting) not to the
kono
parents:
diff changeset
484 // checkpoint but to the transaction that was started from this
kono
parents:
diff changeset
485 // checkpoint (e.g., nesting = cp->nesting + 1);
kono
parents:
diff changeset
486 assert(aborting);
kono
parents:
diff changeset
487 // Roll back the rest of the state to the checkpoint.
kono
parents:
diff changeset
488 jb = cp->jb;
kono
parents:
diff changeset
489 id = cp->id;
kono
parents:
diff changeset
490 prop = cp->prop;
kono
parents:
diff changeset
491 if (cp->disp != abi_disp())
kono
parents:
diff changeset
492 set_abi_disp(cp->disp);
kono
parents:
diff changeset
493 alloc_actions = cp->alloc_actions;
kono
parents:
diff changeset
494 nesting = cp->nesting;
kono
parents:
diff changeset
495 }
kono
parents:
diff changeset
496 else
kono
parents:
diff changeset
497 {
kono
parents:
diff changeset
498 // Roll back to the outermost transaction.
kono
parents:
diff changeset
499 // Restore the jump buffer and transaction properties, which we will
kono
parents:
diff changeset
500 // need for the longjmp used to restart or abort the transaction.
kono
parents:
diff changeset
501 if (parent_txns.size() > 0)
kono
parents:
diff changeset
502 {
kono
parents:
diff changeset
503 jb = parent_txns[0].jb;
kono
parents:
diff changeset
504 id = parent_txns[0].id;
kono
parents:
diff changeset
505 prop = parent_txns[0].prop;
kono
parents:
diff changeset
506 }
kono
parents:
diff changeset
507 // Reset the transaction. Do not reset this->state, which is handled by
kono
parents:
diff changeset
508 // the callers. Note that if we are not aborting, we reset the
kono
parents:
diff changeset
509 // transaction to the point after having executed begin_transaction
kono
parents:
diff changeset
510 // (we will return from it), so the nesting level must be one, not zero.
kono
parents:
diff changeset
511 nesting = (aborting ? 0 : 1);
kono
parents:
diff changeset
512 parent_txns.clear();
kono
parents:
diff changeset
513 }
kono
parents:
diff changeset
514
kono
parents:
diff changeset
515 if (this->eh_in_flight)
kono
parents:
diff changeset
516 {
kono
parents:
diff changeset
517 _Unwind_DeleteException ((_Unwind_Exception *) this->eh_in_flight);
kono
parents:
diff changeset
518 this->eh_in_flight = NULL;
kono
parents:
diff changeset
519 }
kono
parents:
diff changeset
520 }
kono
parents:
diff changeset
521
kono
parents:
diff changeset
522 void ITM_REGPARM
kono
parents:
diff changeset
523 _ITM_abortTransaction (_ITM_abortReason reason)
kono
parents:
diff changeset
524 {
kono
parents:
diff changeset
525 gtm_thread *tx = gtm_thr();
kono
parents:
diff changeset
526
kono
parents:
diff changeset
527 assert (reason == userAbort || reason == (userAbort | outerAbort));
kono
parents:
diff changeset
528 assert ((tx->prop & pr_hasNoAbort) == 0);
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 if (tx->state & gtm_thread::STATE_IRREVOCABLE)
kono
parents:
diff changeset
531 abort ();
kono
parents:
diff changeset
532
kono
parents:
diff changeset
533 // Roll back to innermost transaction.
kono
parents:
diff changeset
534 if (tx->parent_txns.size() > 0 && !(reason & outerAbort))
kono
parents:
diff changeset
535 {
kono
parents:
diff changeset
536 // If the current method does not support closed nesting but we are
kono
parents:
diff changeset
537 // nested and must only roll back the innermost transaction, then
kono
parents:
diff changeset
538 // restart with a method that supports closed nesting.
kono
parents:
diff changeset
539 abi_dispatch *disp = abi_disp();
kono
parents:
diff changeset
540 if (!disp->closed_nesting())
kono
parents:
diff changeset
541 tx->restart(RESTART_CLOSED_NESTING);
kono
parents:
diff changeset
542
kono
parents:
diff changeset
543 // The innermost transaction is a closed nested transaction.
kono
parents:
diff changeset
544 gtm_transaction_cp *cp = tx->parent_txns.pop();
kono
parents:
diff changeset
545 uint32_t longjmp_prop = tx->prop;
kono
parents:
diff changeset
546 gtm_jmpbuf longjmp_jb = tx->jb;
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 tx->rollback (cp, true);
kono
parents:
diff changeset
549
kono
parents:
diff changeset
550 // Jump to nested transaction (use the saved jump buffer).
kono
parents:
diff changeset
551 GTM_longjmp (a_abortTransaction | a_restoreLiveVariables,
kono
parents:
diff changeset
552 &longjmp_jb, longjmp_prop);
kono
parents:
diff changeset
553 }
kono
parents:
diff changeset
554 else
kono
parents:
diff changeset
555 {
kono
parents:
diff changeset
556 // There is no nested transaction or an abort of the outermost
kono
parents:
diff changeset
557 // transaction was requested, so roll back to the outermost transaction.
kono
parents:
diff changeset
558 tx->rollback (0, true);
kono
parents:
diff changeset
559
kono
parents:
diff changeset
560 // Aborting an outermost transaction finishes execution of the whole
kono
parents:
diff changeset
561 // transaction. Therefore, reset transaction state.
kono
parents:
diff changeset
562 if (tx->state & gtm_thread::STATE_SERIAL)
kono
parents:
diff changeset
563 gtm_thread::serial_lock.write_unlock ();
kono
parents:
diff changeset
564 else
kono
parents:
diff changeset
565 gtm_thread::serial_lock.read_unlock (tx);
kono
parents:
diff changeset
566 tx->state = 0;
kono
parents:
diff changeset
567
kono
parents:
diff changeset
568 GTM_longjmp (a_abortTransaction | a_restoreLiveVariables,
kono
parents:
diff changeset
569 &tx->jb, tx->prop);
kono
parents:
diff changeset
570 }
kono
parents:
diff changeset
571 }
kono
parents:
diff changeset
572
kono
parents:
diff changeset
573 bool
kono
parents:
diff changeset
574 GTM::gtm_thread::trycommit ()
kono
parents:
diff changeset
575 {
kono
parents:
diff changeset
576 nesting--;
kono
parents:
diff changeset
577
kono
parents:
diff changeset
578 // Skip any real commit for elided transactions.
kono
parents:
diff changeset
579 if (nesting > 0 && (parent_txns.size() == 0 ||
kono
parents:
diff changeset
580 nesting > parent_txns[parent_txns.size() - 1].nesting))
kono
parents:
diff changeset
581 return true;
kono
parents:
diff changeset
582
kono
parents:
diff changeset
583 if (nesting > 0)
kono
parents:
diff changeset
584 {
kono
parents:
diff changeset
585 // Commit of a closed-nested transaction. Remove one checkpoint and add
kono
parents:
diff changeset
586 // any effects of this transaction to the parent transaction.
kono
parents:
diff changeset
587 gtm_transaction_cp *cp = parent_txns.pop();
kono
parents:
diff changeset
588 commit_allocations(false, &cp->alloc_actions);
kono
parents:
diff changeset
589 cp->commit(this);
kono
parents:
diff changeset
590 return true;
kono
parents:
diff changeset
591 }
kono
parents:
diff changeset
592
kono
parents:
diff changeset
593 // Commit of an outermost transaction.
kono
parents:
diff changeset
594 gtm_word priv_time = 0;
kono
parents:
diff changeset
595 if (abi_disp()->trycommit (priv_time))
kono
parents:
diff changeset
596 {
kono
parents:
diff changeset
597 // The transaction is now finished but we will still access some shared
kono
parents:
diff changeset
598 // data if we have to ensure privatization safety.
kono
parents:
diff changeset
599 bool do_read_unlock = false;
kono
parents:
diff changeset
600 if (state & gtm_thread::STATE_SERIAL)
kono
parents:
diff changeset
601 {
kono
parents:
diff changeset
602 gtm_thread::serial_lock.write_unlock ();
kono
parents:
diff changeset
603 // There are no other active transactions, so there's no need to
kono
parents:
diff changeset
604 // enforce privatization safety.
kono
parents:
diff changeset
605 priv_time = 0;
kono
parents:
diff changeset
606 }
kono
parents:
diff changeset
607 else
kono
parents:
diff changeset
608 {
kono
parents:
diff changeset
609 // If we have to ensure privatization safety, we must not yet
kono
parents:
diff changeset
610 // release the read lock and become inactive because (1) we still
kono
parents:
diff changeset
611 // have to go through the list of all transactions, which can be
kono
parents:
diff changeset
612 // modified by serial mode threads, and (2) we interpret each
kono
parents:
diff changeset
613 // transactions' shared_state in the context of what we believe to
kono
parents:
diff changeset
614 // be the current method group (and serial mode transactions can
kono
parents:
diff changeset
615 // change the method group). Therefore, if we have to ensure
kono
parents:
diff changeset
616 // privatization safety, delay becoming inactive but set a maximum
kono
parents:
diff changeset
617 // snapshot time (we have committed and thus have an empty snapshot,
kono
parents:
diff changeset
618 // so it will always be most recent). Use release MO so that this
kono
parents:
diff changeset
619 // synchronizes with other threads observing our snapshot time.
kono
parents:
diff changeset
620 if (priv_time)
kono
parents:
diff changeset
621 {
kono
parents:
diff changeset
622 do_read_unlock = true;
kono
parents:
diff changeset
623 shared_state.store((~(typeof gtm_thread::shared_state)0) - 1,
kono
parents:
diff changeset
624 memory_order_release);
kono
parents:
diff changeset
625 }
kono
parents:
diff changeset
626 else
kono
parents:
diff changeset
627 gtm_thread::serial_lock.read_unlock (this);
kono
parents:
diff changeset
628 }
kono
parents:
diff changeset
629 state = 0;
kono
parents:
diff changeset
630
kono
parents:
diff changeset
631 // We can commit the undo log after dispatch-specific commit and after
kono
parents:
diff changeset
632 // making the transaction inactive because we only have to reset
kono
parents:
diff changeset
633 // gtm_thread state.
kono
parents:
diff changeset
634 undolog.commit ();
kono
parents:
diff changeset
635 // Reset further transaction state.
kono
parents:
diff changeset
636 cxa_catch_count = 0;
kono
parents:
diff changeset
637 restart_total = 0;
kono
parents:
diff changeset
638
kono
parents:
diff changeset
639 // Ensure privatization safety, if necessary.
kono
parents:
diff changeset
640 if (priv_time)
kono
parents:
diff changeset
641 {
kono
parents:
diff changeset
642 // There must be a seq_cst fence between the following loads of the
kono
parents:
diff changeset
643 // other transactions' shared_state and the dispatch-specific stores
kono
parents:
diff changeset
644 // that signal updates by this transaction (e.g., lock
kono
parents:
diff changeset
645 // acquisitions). This ensures that if we read prior to other
kono
parents:
diff changeset
646 // reader transactions setting their shared_state to 0, then those
kono
parents:
diff changeset
647 // readers will observe our updates. We can reuse the seq_cst fence
kono
parents:
diff changeset
648 // in serial_lock.read_unlock() if we performed that; if not, we
kono
parents:
diff changeset
649 // issue the fence.
kono
parents:
diff changeset
650 if (do_read_unlock)
kono
parents:
diff changeset
651 atomic_thread_fence (memory_order_seq_cst);
kono
parents:
diff changeset
652 // TODO Don't just spin but also block using cond vars / futexes
kono
parents:
diff changeset
653 // here. Should probably be integrated with the serial lock code.
kono
parents:
diff changeset
654 for (gtm_thread *it = gtm_thread::list_of_threads; it != 0;
kono
parents:
diff changeset
655 it = it->next_thread)
kono
parents:
diff changeset
656 {
kono
parents:
diff changeset
657 if (it == this) continue;
kono
parents:
diff changeset
658 // We need to load other threads' shared_state using acquire
kono
parents:
diff changeset
659 // semantics (matching the release semantics of the respective
kono
parents:
diff changeset
660 // updates). This is necessary to ensure that the other
kono
parents:
diff changeset
661 // threads' memory accesses happen before our actions that
kono
parents:
diff changeset
662 // assume privatization safety.
kono
parents:
diff changeset
663 // TODO Are there any platform-specific optimizations (e.g.,
kono
parents:
diff changeset
664 // merging barriers)?
kono
parents:
diff changeset
665 while (it->shared_state.load(memory_order_acquire) < priv_time)
kono
parents:
diff changeset
666 cpu_relax();
kono
parents:
diff changeset
667 }
kono
parents:
diff changeset
668 }
kono
parents:
diff changeset
669
kono
parents:
diff changeset
670 // After ensuring privatization safety, we are now truly inactive and
kono
parents:
diff changeset
671 // thus can release the read lock. We will also execute potentially
kono
parents:
diff changeset
672 // privatizing actions (e.g., calling free()). User actions are first.
kono
parents:
diff changeset
673 if (do_read_unlock)
kono
parents:
diff changeset
674 gtm_thread::serial_lock.read_unlock (this);
kono
parents:
diff changeset
675 commit_user_actions ();
kono
parents:
diff changeset
676 commit_allocations (false, 0);
kono
parents:
diff changeset
677
kono
parents:
diff changeset
678 return true;
kono
parents:
diff changeset
679 }
kono
parents:
diff changeset
680 return false;
kono
parents:
diff changeset
681 }
kono
parents:
diff changeset
682
kono
parents:
diff changeset
683 void ITM_NORETURN
kono
parents:
diff changeset
684 GTM::gtm_thread::restart (gtm_restart_reason r, bool finish_serial_upgrade)
kono
parents:
diff changeset
685 {
kono
parents:
diff changeset
686 // Roll back to outermost transaction. Do not reset transaction state because
kono
parents:
diff changeset
687 // we will continue executing this transaction.
kono
parents:
diff changeset
688 rollback ();
kono
parents:
diff changeset
689
kono
parents:
diff changeset
690 // If we have to restart while an upgrade of the serial lock is happening,
kono
parents:
diff changeset
691 // we need to finish this here, after rollback (to ensure privatization
kono
parents:
diff changeset
692 // safety despite undo writes) and before deciding about the retry strategy
kono
parents:
diff changeset
693 // (which could switch to/from serial mode).
kono
parents:
diff changeset
694 if (finish_serial_upgrade)
kono
parents:
diff changeset
695 gtm_thread::serial_lock.write_upgrade_finish(this);
kono
parents:
diff changeset
696
kono
parents:
diff changeset
697 decide_retry_strategy (r);
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 // Run dispatch-specific restart code. Retry until we succeed.
kono
parents:
diff changeset
700 abi_dispatch* disp = abi_disp();
kono
parents:
diff changeset
701 GTM::gtm_restart_reason rr;
kono
parents:
diff changeset
702 while ((rr = disp->begin_or_restart()) != NO_RESTART)
kono
parents:
diff changeset
703 {
kono
parents:
diff changeset
704 decide_retry_strategy(rr);
kono
parents:
diff changeset
705 disp = abi_disp();
kono
parents:
diff changeset
706 }
kono
parents:
diff changeset
707
kono
parents:
diff changeset
708 GTM_longjmp (choose_code_path(prop, disp) | a_restoreLiveVariables,
kono
parents:
diff changeset
709 &jb, prop);
kono
parents:
diff changeset
710 }
kono
parents:
diff changeset
711
kono
parents:
diff changeset
712 void ITM_REGPARM
kono
parents:
diff changeset
713 _ITM_commitTransaction(void)
kono
parents:
diff changeset
714 {
kono
parents:
diff changeset
715 #if defined(USE_HTM_FASTPATH)
kono
parents:
diff changeset
716 // HTM fastpath. If we are not executing a HW transaction, then we will be
kono
parents:
diff changeset
717 // a serial-mode transaction. If we are, then there will be no other
kono
parents:
diff changeset
718 // concurrent serial-mode transaction.
kono
parents:
diff changeset
719 // See gtm_thread::begin_transaction.
kono
parents:
diff changeset
720 if (likely(!gtm_thread::serial_lock.htm_fastpath_disabled()))
kono
parents:
diff changeset
721 {
kono
parents:
diff changeset
722 htm_commit();
kono
parents:
diff changeset
723 return;
kono
parents:
diff changeset
724 }
kono
parents:
diff changeset
725 #endif
kono
parents:
diff changeset
726 gtm_thread *tx = gtm_thr();
kono
parents:
diff changeset
727 if (!tx->trycommit ())
kono
parents:
diff changeset
728 tx->restart (RESTART_VALIDATE_COMMIT);
kono
parents:
diff changeset
729 }
kono
parents:
diff changeset
730
kono
parents:
diff changeset
731 void ITM_REGPARM
kono
parents:
diff changeset
732 _ITM_commitTransactionEH(void *exc_ptr)
kono
parents:
diff changeset
733 {
kono
parents:
diff changeset
734 #if defined(USE_HTM_FASTPATH)
kono
parents:
diff changeset
735 // See _ITM_commitTransaction.
kono
parents:
diff changeset
736 if (likely(!gtm_thread::serial_lock.htm_fastpath_disabled()))
kono
parents:
diff changeset
737 {
kono
parents:
diff changeset
738 htm_commit();
kono
parents:
diff changeset
739 return;
kono
parents:
diff changeset
740 }
kono
parents:
diff changeset
741 #endif
kono
parents:
diff changeset
742 gtm_thread *tx = gtm_thr();
kono
parents:
diff changeset
743 if (!tx->trycommit ())
kono
parents:
diff changeset
744 {
kono
parents:
diff changeset
745 tx->eh_in_flight = exc_ptr;
kono
parents:
diff changeset
746 tx->restart (RESTART_VALIDATE_COMMIT);
kono
parents:
diff changeset
747 }
kono
parents:
diff changeset
748 }