OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libitm/] [beginend.cc] - Blame information for rev 801

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 737 jeremybenn
/* Copyright (C) 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
2
   Contributed by Richard Henderson <rth@redhat.com>.
3
 
4
   This file is part of the GNU Transactional Memory Library (libitm).
5
 
6
   Libitm is free software; you can redistribute it and/or modify it
7
   under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
 
11
   Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14
   more details.
15
 
16
   Under Section 7 of GPL version 3, you are granted additional
17
   permissions described in the GCC Runtime Library Exception, version
18
   3.1, as published by the Free Software Foundation.
19
 
20
   You should have received a copy of the GNU General Public License and
21
   a copy of the GCC Runtime Library Exception along with this program;
22
   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23
   <http://www.gnu.org/licenses/>.  */
24
 
25
#include "libitm_i.h"
26
#include <pthread.h>
27
 
28
 
29
using namespace GTM;
30
 
31
#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP)
32
extern __thread gtm_thread_tls _gtm_thr_tls;
33
#endif
34
 
35
gtm_rwlock GTM::gtm_thread::serial_lock;
36
gtm_thread *GTM::gtm_thread::list_of_threads = 0;
37
unsigned GTM::gtm_thread::number_of_threads = 0;
38
 
39
gtm_stmlock GTM::gtm_stmlock_array[LOCK_ARRAY_SIZE];
40
atomic<gtm_version> GTM::gtm_clock;
41
 
42
/* ??? Move elsewhere when we figure out library initialization.  */
43
uint64_t GTM::gtm_spin_count_var = 1000;
44
 
45
#ifdef HAVE_64BIT_SYNC_BUILTINS
46
static atomic<_ITM_transactionId_t> global_tid;
47
#else
48
static _ITM_transactionId_t global_tid;
49
static pthread_mutex_t global_tid_lock = PTHREAD_MUTEX_INITIALIZER;
50
#endif
51
 
52
 
53
// Provides a on-thread-exit callback used to release per-thread data.
54
static pthread_key_t thr_release_key;
55
static pthread_once_t thr_release_once = PTHREAD_ONCE_INIT;
56
 
57
 
58
/* Allocate a transaction structure.  */
59
void *
60
GTM::gtm_thread::operator new (size_t s)
61
{
62
  void *tx;
63
 
64
  assert(s == sizeof(gtm_thread));
65
 
66
  tx = xmalloc (sizeof (gtm_thread), true);
67
  memset (tx, 0, sizeof (gtm_thread));
68
 
69
  return tx;
70
}
71
 
72
/* Free the given transaction. Raises an error if the transaction is still
73
   in use.  */
74
void
75
GTM::gtm_thread::operator delete(void *tx)
76
{
77
  free(tx);
78
}
79
 
80
static void
81
thread_exit_handler(void *)
82
{
83
  gtm_thread *thr = gtm_thr();
84
  if (thr)
85
    delete thr;
86
  set_gtm_thr(0);
87
}
88
 
89
static void
90
thread_exit_init()
91
{
92
  if (pthread_key_create(&thr_release_key, thread_exit_handler))
93
    GTM_fatal("Creating thread release TLS key failed.");
94
}
95
 
96
 
97
GTM::gtm_thread::~gtm_thread()
98
{
99
  if (nesting > 0)
100
    GTM_fatal("Thread exit while a transaction is still active.");
101
 
102
  // Deregister this transaction.
103
  serial_lock.write_lock ();
104
  gtm_thread **prev = &list_of_threads;
105
  for (; *prev; prev = &(*prev)->next_thread)
106
    {
107
      if (*prev == this)
108
        {
109
          *prev = (*prev)->next_thread;
110
          break;
111
        }
112
    }
113
  number_of_threads--;
114
  number_of_threads_changed(number_of_threads + 1, number_of_threads);
115
  serial_lock.write_unlock ();
116
}
117
 
118
GTM::gtm_thread::gtm_thread ()
119
{
120
  // This object's memory has been set to zero by operator new, so no need
121
  // to initialize any of the other primitive-type members that do not have
122
  // constructors.
123
  shared_state.store(-1, memory_order_relaxed);
124
 
125
  // Register this transaction with the list of all threads' transactions.
126
  serial_lock.write_lock ();
127
  next_thread = list_of_threads;
128
  list_of_threads = this;
129
  number_of_threads++;
130
  number_of_threads_changed(number_of_threads - 1, number_of_threads);
131
  serial_lock.write_unlock ();
132
 
133
  if (pthread_once(&thr_release_once, thread_exit_init))
134
    GTM_fatal("Initializing thread release TLS key failed.");
135
  // Any non-null value is sufficient to trigger destruction of this
136
  // transaction when the current thread terminates.
137
  if (pthread_setspecific(thr_release_key, this))
138
    GTM_fatal("Setting thread release TLS key failed.");
139
}
140
 
141
static inline uint32_t
142
choose_code_path(uint32_t prop, abi_dispatch *disp)
143
{
144
  if ((prop & pr_uninstrumentedCode) && disp->can_run_uninstrumented_code())
145
    return a_runUninstrumentedCode;
146
  else
147
    return a_runInstrumentedCode;
148
}
149
 
150
uint32_t
151
GTM::gtm_thread::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb)
152
{
153
  static const _ITM_transactionId_t tid_block_size = 1 << 16;
154
 
155
  gtm_thread *tx;
156
  abi_dispatch *disp;
157
  uint32_t ret;
158
 
159
  // ??? pr_undoLogCode is not properly defined in the ABI. Are barriers
160
  // omitted because they are not necessary (e.g., a transaction on thread-
161
  // local data) or because the compiler thinks that some kind of global
162
  // synchronization might perform better?
163
  if (unlikely(prop & pr_undoLogCode))
164
    GTM_fatal("pr_undoLogCode not supported");
165
 
166
  tx = gtm_thr();
167
  if (unlikely(tx == NULL))
168
    {
169
      // Create the thread object. The constructor will also set up automatic
170
      // deletion on thread termination.
171
      tx = new gtm_thread();
172
      set_gtm_thr(tx);
173
    }
174
 
175
  if (tx->nesting > 0)
176
    {
177
      // This is a nested transaction.
178
      // Check prop compatibility:
179
      // The ABI requires pr_hasNoFloatUpdate, pr_hasNoVectorUpdate,
180
      // pr_hasNoIrrevocable, pr_aWBarriersOmitted, pr_RaRBarriersOmitted, and
181
      // pr_hasNoSimpleReads to hold for the full dynamic scope of a
182
      // transaction. We could check that these are set for the nested
183
      // transaction if they are also set for the parent transaction, but the
184
      // ABI does not require these flags to be set if they could be set,
185
      // so the check could be too strict.
186
      // ??? For pr_readOnly, lexical or dynamic scope is unspecified.
187
 
188
      if (prop & pr_hasNoAbort)
189
        {
190
          // We can use flat nesting, so elide this transaction.
191
          if (!(prop & pr_instrumentedCode))
192
            {
193
              if (!(tx->state & STATE_SERIAL) ||
194
                  !(tx->state & STATE_IRREVOCABLE))
195
                tx->serialirr_mode();
196
            }
197
          // Increment nesting level after checking that we have a method that
198
          // allows us to continue.
199
          tx->nesting++;
200
          return choose_code_path(prop, abi_disp());
201
        }
202
 
203
      // The transaction might abort, so use closed nesting if possible.
204
      // pr_hasNoAbort has lexical scope, so the compiler should really have
205
      // generated an instrumented code path.
206
      assert(prop & pr_instrumentedCode);
207
 
208
      // Create a checkpoint of the current transaction.
209
      gtm_transaction_cp *cp = tx->parent_txns.push();
210
      cp->save(tx);
211
      new (&tx->alloc_actions) aa_tree<uintptr_t, gtm_alloc_action>();
212
 
213
      // Check whether the current method actually supports closed nesting.
214
      // If we can switch to another one, do so.
215
      // If not, we assume that actual aborts are infrequent, and rather
216
      // restart in _ITM_abortTransaction when we really have to.
217
      disp = abi_disp();
218
      if (!disp->closed_nesting())
219
        {
220
          // ??? Should we elide the transaction if there is no alternative
221
          // method that supports closed nesting? If we do, we need to set
222
          // some flag to prevent _ITM_abortTransaction from aborting the
223
          // wrong transaction (i.e., some parent transaction).
224
          abi_dispatch *cn_disp = disp->closed_nesting_alternative();
225
          if (cn_disp)
226
            {
227
              disp = cn_disp;
228
              set_abi_disp(disp);
229
            }
230
        }
231
    }
232
  else
233
    {
234
      // Outermost transaction
235
      disp = tx->decide_begin_dispatch (prop);
236
      set_abi_disp (disp);
237
    }
238
 
239
  // Initialization that is common for outermost and nested transactions.
240
  tx->prop = prop;
241
  tx->nesting++;
242
 
243
  tx->jb = *jb;
244
 
245
  // As long as we have not exhausted a previously allocated block of TIDs,
246
  // we can avoid an atomic operation on a shared cacheline.
247
  if (tx->local_tid & (tid_block_size - 1))
248
    tx->id = tx->local_tid++;
249
  else
250
    {
251
#ifdef HAVE_64BIT_SYNC_BUILTINS
252
      // We don't really care which block of TIDs we get but only that we
253
      // acquire one atomically; therefore, relaxed memory order is
254
      // sufficient.
255
      tx->id = global_tid.fetch_add(tid_block_size, memory_order_relaxed);
256
      tx->local_tid = tx->id + 1;
257
#else
258
      pthread_mutex_lock (&global_tid_lock);
259
      global_tid += tid_block_size;
260
      tx->id = global_tid;
261
      tx->local_tid = tx->id + 1;
262
      pthread_mutex_unlock (&global_tid_lock);
263
#endif
264
    }
265
 
266
  // Run dispatch-specific restart code. Retry until we succeed.
267
  GTM::gtm_restart_reason rr;
268
  while ((rr = disp->begin_or_restart()) != NO_RESTART)
269
    {
270
      tx->decide_retry_strategy(rr);
271
      disp = abi_disp();
272
    }
273
 
274
  // Determine the code path to run. Only irrevocable transactions cannot be
275
  // restarted, so all other transactions need to save live variables.
276
  ret = choose_code_path(prop, disp);
277
  if (!(tx->state & STATE_IRREVOCABLE))
278
    ret |= a_saveLiveVariables;
279
  return ret;
280
}
281
 
282
 
283
void
284
GTM::gtm_transaction_cp::save(gtm_thread* tx)
285
{
286
  // Save everything that we might have to restore on restarts or aborts.
287
  jb = tx->jb;
288
  undolog_size = tx->undolog.size();
289
  memcpy(&alloc_actions, &tx->alloc_actions, sizeof(alloc_actions));
290
  user_actions_size = tx->user_actions.size();
291
  id = tx->id;
292
  prop = tx->prop;
293
  cxa_catch_count = tx->cxa_catch_count;
294
  cxa_unthrown = tx->cxa_unthrown;
295
  disp = abi_disp();
296
  nesting = tx->nesting;
297
}
298
 
299
void
300
GTM::gtm_transaction_cp::commit(gtm_thread* tx)
301
{
302
  // Restore state that is not persistent across commits. Exception handling,
303
  // information, nesting level, and any logs do not need to be restored on
304
  // commits of nested transactions. Allocation actions must be committed
305
  // before committing the snapshot.
306
  tx->jb = jb;
307
  memcpy(&tx->alloc_actions, &alloc_actions, sizeof(alloc_actions));
308
  tx->id = id;
309
  tx->prop = prop;
310
}
311
 
312
 
313
void
314
GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool aborting)
315
{
316
  // The undo log is special in that it used for both thread-local and shared
317
  // data. Because of the latter, we have to roll it back before any
318
  // dispatch-specific rollback (which handles synchronization with other
319
  // transactions).
320
  undolog.rollback (this, cp ? cp->undolog_size : 0);
321
 
322
  // Perform dispatch-specific rollback.
323
  abi_disp()->rollback (cp);
324
 
325
  // Roll back all actions that are supposed to happen around the transaction.
326
  rollback_user_actions (cp ? cp->user_actions_size : 0);
327
  commit_allocations (true, (cp ? &cp->alloc_actions : 0));
328
  revert_cpp_exceptions (cp);
329
 
330
  if (cp)
331
    {
332
      // We do not yet handle restarts of nested transactions. To do that, we
333
      // would have to restore some state (jb, id, prop, nesting) not to the
334
      // checkpoint but to the transaction that was started from this
335
      // checkpoint (e.g., nesting = cp->nesting + 1);
336
      assert(aborting);
337
      // Roll back the rest of the state to the checkpoint.
338
      jb = cp->jb;
339
      id = cp->id;
340
      prop = cp->prop;
341
      if (cp->disp != abi_disp())
342
        set_abi_disp(cp->disp);
343
      memcpy(&alloc_actions, &cp->alloc_actions, sizeof(alloc_actions));
344
      nesting = cp->nesting;
345
    }
346
  else
347
    {
348
      // Roll back to the outermost transaction.
349
      // Restore the jump buffer and transaction properties, which we will
350
      // need for the longjmp used to restart or abort the transaction.
351
      if (parent_txns.size() > 0)
352
        {
353
          jb = parent_txns[0].jb;
354
          id = parent_txns[0].id;
355
          prop = parent_txns[0].prop;
356
        }
357
      // Reset the transaction. Do not reset this->state, which is handled by
358
      // the callers. Note that if we are not aborting, we reset the
359
      // transaction to the point after having executed begin_transaction
360
      // (we will return from it), so the nesting level must be one, not zero.
361
      nesting = (aborting ? 0 : 1);
362
      parent_txns.clear();
363
    }
364
 
365
  if (this->eh_in_flight)
366
    {
367
      _Unwind_DeleteException ((_Unwind_Exception *) this->eh_in_flight);
368
      this->eh_in_flight = NULL;
369
    }
370
}
371
 
372
void ITM_REGPARM
373
_ITM_abortTransaction (_ITM_abortReason reason)
374
{
375
  gtm_thread *tx = gtm_thr();
376
 
377
  assert (reason == userAbort || reason == (userAbort | outerAbort));
378
  assert ((tx->prop & pr_hasNoAbort) == 0);
379
 
380
  if (tx->state & gtm_thread::STATE_IRREVOCABLE)
381
    abort ();
382
 
383
  // Roll back to innermost transaction.
384
  if (tx->parent_txns.size() > 0 && !(reason & outerAbort))
385
    {
386
      // If the current method does not support closed nesting but we are
387
      // nested and must only roll back the innermost transaction, then
388
      // restart with a method that supports closed nesting.
389
      abi_dispatch *disp = abi_disp();
390
      if (!disp->closed_nesting())
391
        tx->restart(RESTART_CLOSED_NESTING);
392
 
393
      // The innermost transaction is a closed nested transaction.
394
      gtm_transaction_cp *cp = tx->parent_txns.pop();
395
      uint32_t longjmp_prop = tx->prop;
396
      gtm_jmpbuf longjmp_jb = tx->jb;
397
 
398
      tx->rollback (cp, true);
399
 
400
      // Jump to nested transaction (use the saved jump buffer).
401
      GTM_longjmp (a_abortTransaction | a_restoreLiveVariables,
402
                   &longjmp_jb, longjmp_prop);
403
    }
404
  else
405
    {
406
      // There is no nested transaction or an abort of the outermost
407
      // transaction was requested, so roll back to the outermost transaction.
408
      tx->rollback (0, true);
409
 
410
      // Aborting an outermost transaction finishes execution of the whole
411
      // transaction. Therefore, reset transaction state.
412
      if (tx->state & gtm_thread::STATE_SERIAL)
413
        gtm_thread::serial_lock.write_unlock ();
414
      else
415
        gtm_thread::serial_lock.read_unlock (tx);
416
      tx->state = 0;
417
 
418
      GTM_longjmp (a_abortTransaction | a_restoreLiveVariables,
419
                   &tx->jb, tx->prop);
420
    }
421
}
422
 
423
bool
424
GTM::gtm_thread::trycommit ()
425
{
426
  nesting--;
427
 
428
  // Skip any real commit for elided transactions.
429
  if (nesting > 0 && (parent_txns.size() == 0 ||
430
      nesting > parent_txns[parent_txns.size() - 1].nesting))
431
    return true;
432
 
433
  if (nesting > 0)
434
    {
435
      // Commit of a closed-nested transaction. Remove one checkpoint and add
436
      // any effects of this transaction to the parent transaction.
437
      gtm_transaction_cp *cp = parent_txns.pop();
438
      commit_allocations(false, &cp->alloc_actions);
439
      cp->commit(this);
440
      return true;
441
    }
442
 
443
  // Commit of an outermost transaction.
444
  gtm_word priv_time = 0;
445
  if (abi_disp()->trycommit (priv_time))
446
    {
447
      // The transaction is now inactive. Everything that we still have to do
448
      // will not synchronize with other transactions anymore.
449
      if (state & gtm_thread::STATE_SERIAL)
450
        {
451
          gtm_thread::serial_lock.write_unlock ();
452
          // There are no other active transactions, so there's no need to
453
          // enforce privatization safety.
454
          priv_time = 0;
455
        }
456
      else
457
        gtm_thread::serial_lock.read_unlock (this);
458
      state = 0;
459
 
460
      // We can commit the undo log after dispatch-specific commit and after
461
      // making the transaction inactive because we only have to reset
462
      // gtm_thread state.
463
      undolog.commit ();
464
      // Reset further transaction state.
465
      cxa_catch_count = 0;
466
      cxa_unthrown = NULL;
467
      restart_total = 0;
468
 
469
      // Ensure privatization safety, if necessary.
470
      if (priv_time)
471
        {
472
          // There must be a seq_cst fence between the following loads of the
473
          // other transactions' shared_state and the dispatch-specific stores
474
          // that signal updates by this transaction (e.g., lock
475
          // acquisitions).  This ensures that if we read prior to other
476
          // reader transactions setting their shared_state to 0, then those
477
          // readers will observe our updates.  We can reuse the seq_cst fence
478
          // in serial_lock.read_unlock() however, so we don't need another
479
          // one here.
480
          // TODO Don't just spin but also block using cond vars / futexes
481
          // here. Should probably be integrated with the serial lock code.
482
          for (gtm_thread *it = gtm_thread::list_of_threads; it != 0;
483
              it = it->next_thread)
484
            {
485
              if (it == this) continue;
486
              // We need to load other threads' shared_state using acquire
487
              // semantics (matching the release semantics of the respective
488
              // updates).  This is necessary to ensure that the other
489
              // threads' memory accesses happen before our actions that
490
              // assume privatization safety.
491
              // TODO Are there any platform-specific optimizations (e.g.,
492
              // merging barriers)?
493
              while (it->shared_state.load(memory_order_acquire) < priv_time)
494
                cpu_relax();
495
            }
496
        }
497
 
498
      // After ensuring privatization safety, we execute potentially
499
      // privatizing actions (e.g., calling free()). User actions are first.
500
      commit_user_actions ();
501
      commit_allocations (false, 0);
502
 
503
      return true;
504
    }
505
  return false;
506
}
507
 
508
void ITM_NORETURN
509
GTM::gtm_thread::restart (gtm_restart_reason r, bool finish_serial_upgrade)
510
{
511
  // Roll back to outermost transaction. Do not reset transaction state because
512
  // we will continue executing this transaction.
513
  rollback ();
514
 
515
  // If we have to restart while an upgrade of the serial lock is happening,
516
  // we need to finish this here, after rollback (to ensure privatization
517
  // safety despite undo writes) and before deciding about the retry strategy
518
  // (which could switch to/from serial mode).
519
  if (finish_serial_upgrade)
520
    gtm_thread::serial_lock.write_upgrade_finish(this);
521
 
522
  decide_retry_strategy (r);
523
 
524
  // Run dispatch-specific restart code. Retry until we succeed.
525
  abi_dispatch* disp = abi_disp();
526
  GTM::gtm_restart_reason rr;
527
  while ((rr = disp->begin_or_restart()) != NO_RESTART)
528
    {
529
      decide_retry_strategy(rr);
530
      disp = abi_disp();
531
    }
532
 
533
  GTM_longjmp (choose_code_path(prop, disp) | a_restoreLiveVariables,
534
               &jb, prop);
535
}
536
 
537
void ITM_REGPARM
538
_ITM_commitTransaction(void)
539
{
540
  gtm_thread *tx = gtm_thr();
541
  if (!tx->trycommit ())
542
    tx->restart (RESTART_VALIDATE_COMMIT);
543
}
544
 
545
void ITM_REGPARM
546
_ITM_commitTransactionEH(void *exc_ptr)
547
{
548
  gtm_thread *tx = gtm_thr();
549
  if (!tx->trycommit ())
550
    {
551
      tx->eh_in_flight = exc_ptr;
552
      tx->restart (RESTART_VALIDATE_COMMIT);
553
    }
554
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.