Index: libitm/ChangeLog =================================================================== --- libitm/ChangeLog (.../trunk) (revision 0) +++ libitm/ChangeLog (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,851 @@ +2011-10-29 Torvald Riegel + + * beginend.cc (GTM::gtm_thread::rollback): Add aborting flag and + handle aborts. + (_ITM_abortTransaction): Handle aborts of outer transactions. + * libitm_i.h: Same. + * eh_cpp.cc (GTM::gtm_thread::revert_cpp_exceptions): Fix assertion. + * libitm.texi: Document aborts of outer transactions. + * testsuite/libitm.c/cancel.c: New file. + +2011-10-19 Torvald Riegel + + * testsuite/*: Change __transaction to __transaction_atomic or + __transaction_relaxed. + +2011-10-19 Torvald Riegel + + * config/linux/x86/tls.h (abi_disp): Make TLS slot read volatile. + (gtm_thr): Same. + +2011-10-19 Torvald Riegel + + * libitm_i.h: Add gl_wt dispatch. + * retry.cc (parse_default_method): Same. + * method-gl.cc: New file. + * Makefile.am: Use method-gl.cc. + * Makefile.in: Rebuild. + +2011-10-19 Torvald Riegel + + * beginend.cc (GTM::gtm_thread::trycommit): Ensure privatization + safety if requested by a TM method. + * dispatch.h (GTM::abi_dispatch::trycommit): Add parameter for + privatization safety. + * method-serial.cc: Same. + +2011-10-19 Torvald Riegel + + * libitm_i.h: Renamed gtm_local_undo to gtm_undolog_entry. + (GTM::gtm_thread): Renamed local_undo to undolog. Renamed + undolog-related member functions from *_local to *_undolog. + * local.cc (gtm_thread::commit_undolog): Same. + * beginend.cc (GTM::gtm_thread::trycommit): Same. + (GTM::gtm_thread::rollback): Roll back undolog before + dispatch-specific rollback. + +2011-10-19 Torvald Riegel + + * retry.cc (GTM::gtm_thread::decide_retry_strategy): Handle + re-initialization of the current method group. + * libitm_i.h (GTM::gtm_restart_reason): Add restart reason for this. + +2011-10-19 Torvald Riegel + + * alloc.cc (commit_allocations_2): Do not free transaction-local + memory when committing a nested transaction. + +2011-10-19 Torvald Riegel + + * method-serial.cc (GTM::gtm_thread::serialirr_mode): Fixed: Use + serial-irrevocable dispatch, not serial. + +2011-10-19 Torvald Riegel + + * libitm_i.h (GTM::gtm_restart_reason): Re-arrange and clean up + declarations. + * dispatch.h (GTM::abi_dispatch::begin_or_restart): New. + * method-serial.cc: Implement begin_or_restart(). + * beginend.cc (GTM::gtm_thread::begin_transaction): Call + dispatch-specific begin_or_restart(). + (GTM::gtm_thread::restart): Same. + +2011-08-23 Torvald Riegel + + * retry.cc (GTM::gtm_thread::decide_retry_strategy): Cleanup. Fix + restarting without switching to serial mode. + (GTM::gtm_thread::decide_begin_dispatch): Let the caller set the + transaction state. Choose closed-nesting alternative if available. + (GTM::gtm_thread::set_default_dispatch): New. + (parse_default_method): New. + (GTM::gtm_thread::number_of_threads_changed): New. + * method-serial.cc (GTM::serial_mg): New method group class. + (GTM::serialirr_dispatch): Belongs to serial_mg. Remove reinit and + fini. + (GTM::serial_dispatch): Same. + (GTM::serialirr_onwrite_dispatch): Same. + (GTM::gtm_thread::serialirr_mode): Remove calls to fini. + * beginend.cc (GTM::gtm_thread::~gtm_thread): Maintain number of + registered threads. + (GTM::gtm_thread::gtm_thread): Same. + (_ITM_abortTransaction): Remove calls to abi_dispatch::fini(). + (GTM::gtm_thread::trycommit): Same. Reset number of restarts. + (GTM::gtm_thread::begin_transaction): Let decide_begin_dispatch() + choose dispatch but set state according to dispatch here. + * dispatch.h (GTM::abi_dispatch::fini): Move to method group. + (GTM::method_group): New class. + (GTM::abi_dispatch): Add comments. Maintain pointer to method_group. + * libitm_i.h (GTM::gtm_thread): Add declarations for new members. + * libitm.texi: Document TM methods, method groups, method life cycle. + Rename method sets to method groups. + +2011-08-23 Torvald Riegel + + * config/x86/tls.h: Moved to ... + * config/linux/x86/tls.h: ... here. + +2011-08-23 Torvald Riegel + + * config/x86/tls.h: Use __x86_64__ instead of __LP64__. + Add X32 support. + * config/x86/sjlj.S: Same. + +2011-08-19 Torvald Riegel + + * config/linux/rwlock.h: New file. + * config/linux/rwlock.c: New file. + * configure.ac: Reenable futex support (undo SVN rev 157758). + * Makefile.am: Same. + * configure.tgt: Same. + * config/linux/alpha/futex_bits.h: Same. + * config/linux/futex.h: Same. Return number of woken processes. + * config/linux/futex.cc: Same. + (futex_wait): Remove spinning. + * config/linux/x86/futex_bits.h: Same. Set futex timeout to zero. + Use __x86_64__ instead of __LP64__. + * aclocal.m4: Include generic futex checks. + * configure: Rebuild. + * Makefile.in: Rebuild. + * testsuite/Makefile.in: Rebuild. + * beginend.cc: Include pthread.h. + * config/posix/cachepage.cc: Same. + +2011-08-12 Torvald Riegel + + * config/x86/tls.h (gtm_tx, set_gtm_tx, setup_gtm_thr): Removed. + (abi_disp, set_abi_disp): Move to tx's TLS slot. + (set_gtm_thr): New. + * config/generic/tls.h (gtm_tx, set_gtm_tx, setup_gtm_thr): Removed. + (set_gtm_thr): New. + (GTM::gtm_thread::thread_num): Removed. + (GTM::gtm_thread): Renamed to GTM::gtm_thread_tls. + * libitm_i.h (GTM::gtm_transaction): Renamed to GTM::gtm_thread. More + tx-to-thread renaming. + * beginend.cc: Adapted to tx-to-thread renaming. + (GTM::gtm_thread::~gtm_thread): Extracted from thread_exit_handler(). + (GTM::gtm_thread::gtm_thread): Extracted from begin_transaction(). + * query.cc (_ITM_getTransactionId, _ITM_inTransaction): Renamed + gtm_transaction to gtm_thread. + (_ITM_getThreadnum): Removed. Not supported anymore. + * testsuite/libitm.c/notx.c (main): Removed _ITM_getThreadnum call. + * libitm.texi: Documented that _ITM_getThreadnum is not supported. + * useraction.cc: Renamed gtm_transaction to gtm_thread. Adapted to + gtm_tx-to-gtm_thr renaming if necessary. + * eh_cpp.cc: Same. + * local.cc: Same. + * retry.cc: Same. + * clone.cc: Same. + * alloc.cc: Same. + * alloc_c.cc: Same. + * alloc_cpp.cc: Same. + * method-serial.cc: Same. + * config/generic/tls.cc: Same. + * config/posix/rwlock.h (gtm_rwlock): Same. + * config/posix/rwlock.cc: Same. Adapted to more tx-to-thread renaming. + +2011-08-12 Torvald Riegel + + * config/posix/rwlock.cc (gtm_rwlock::read_lock): Changed locking + implementation. + (gtm_rwlock::read_unlock): Same. + (gtm_rwlock::write_lock_generic): New. Generalized from ... + (gtm_rwlock::write_lock, gtm_rwlock::write_upgrade): ... these. + * libitm_i.h (GTM::gtm_transaction): Added shared_state. + * config/posix/rwlock.h (GTM::gtm_rwlock): Removed a_reader and + w_upgrade. Replaced by per-transaction flags (in shared_state). + Added c_confirmed_writers. + (GTM::gtm_rwlock::read_lock, GTM::gtm_rwlock::read_unlock, + GTM::gtm_rwlock::write_upgrade): Add tx parameter. + * retry.cc (GTM::gtm_transaction::decide_retry_strategy): Same. + * method-serial.cc (GTM::gtm_transaction::serialirr_mode): Same. + * beginend.cc (GTM::gtm_transaction::begin_transaction, + _ITM_abortTransaction, GTM::gtm_transaction::trycommit): Same. + * libitm.texi: Document locking conventions and implementations in + libitm. + +2011-08-12 Torvald Riegel + + * libitm_i.h (next_tx): Add list of all threads' transaction. + * beginend.cc (GTM::gtm_transaction::begin_transaction): Register + transaction with list of transactions and ... + (thread_exit_handler): ... deregister here. + * config/alpha/target.h: Add HW_CACHELINE_SIZE setting. + * config/x86/target.h: Same. + +2011-08-12 Torvald Riegel + + * testsuite/libitm.c++/static_ctor.C: New file. + +2011-08-12 Torvald Riegel + + * testsuite/libitm.c/reentrant.c: New file. + +2011-08-12 Torvald Riegel + + * config/generic/tls.h: Remove the free list for transactions and ... + * beginend.cc (GTM::gtm_transaction::operator new): ... allocate ... + (GTM::gtm_transaction::operator delete): ... and release here. + (thread_exit_handler): New. Delete tx when thread terminates. + (thread_exit_init): New. + (GTM::gtm_transaction::begin_transaction): Set up on-exit handler. + * testsuite/libitm.c/txrelease.c: New file. + +2011-08-12 Torvald Riegel + + * query.cc (_ITM_getThreadnum): Set up gtm_thread if necessary. + * testsuite/libitm.c/notx.c: New file. + +2011-08-12 Torvald Riegel + + * config/generic/tls.h (gtm_thread): Move local_tid from here ... + * libitm_i.h (local_tid): ... to here. + * beginend.cc (GTM::gtm_transaction::begin_transaction): Same. + (GTM::gtm_transaction::operator new): Set up gtm_thread if necessary. + +2011-08-12 Torvald Riegel + + * retry.cc (GTM::gtm_transaction::decide_begin_dispatch): Use + serialirr_onwrite_dispatch as new default for now. + * method-serial.cc (serialirr_onwrite_dispatch): New. + (GTM::dispatch_serialirr_onwrite): New. + * libitm_i.h: Same. + +2011-08-12 Torvald Riegel + + * beginend.cc (GTM::gtm_transaction::rollback): Roll back tx id as well. + * query.cc (_ITM_getTransactionId): There is no active transaction if + the current nesting level is zero. + +2011-07-28 Torvald Riegel + + * beginend.cc (GTM::gtm_transaction::rollback): Fix nesting level + rollback. + +2011-07-28 Torvald Riegel + + * retry.cc (GTM::gtm_transaction::decide_begin_dispatch): Get + transaction properties from the caller instead of from the + transaction object. + * libitm_i.h: Same. + * beginend.cc (GTM::gtm_transaction::begin_transaction): Same. + +2011-07-28 Torvald Riegel + + * local.cc (gtm_transaction::rollback_local): Support closed nesting. + * eh_cpp.cc (GTM::gtm_transaction::revert_cpp_exceptions): Same. + * dispatch.h: Same. + * method-serial.cc: Same. + * beginend.cc (GTM::gtm_transaction::begin_transaction): Change to + flat nesting as default, and closed nesting on demand. + (GTM::gtm_transaction::rollback): Same. + (_ITM_abortTransaction): Same. + (GTM::gtm_transaction::restart): Same. + (GTM::gtm_transaction::trycommit): Same. + (GTM::gtm_transaction::trycommit_and_finalize): Removed. + (choose_code_path): New. + (GTM::gtm_transaction_cp::save): New. + (GTM::gtm_transaction_cp::commit): New. + * query.cc (_ITM_inTransaction): Support flat nesting. + * libitm_i.h (GTM::gtm_transaction_cp): New helper struct for nesting. + (GTM::gtm_transaction): Support flat and closed nesting. + * alloc.cc (commit_allocations_2): New. + (commit_cb_data): New helper struct. + (GTM::gtm_transaction::commit_allocations): Handle nested + commits/rollbacks. + * libitm.texi: Update user action section, add description of nesting. + +2011-07-28 Torvald Riegel + + * libitm_i.h: Add closed nesting as restart reason. + * retry.cc (GTM::gtm_transaction::decide_retry_strategy): Same. + +2011-07-28 Torvald Riegel + + * useraction.cc: Use vector instead of list to store actions. + Also support partial rollbacks for closed nesting. + * libitm_i.h (GTM::gtm_transaction::user_action): Same. + * beginend.cc: Same. + +2011-07-28 Torvald Riegel + + * dispatch.h (GTM::abi_dispatch): Add can_run_uninstrumented_code and + closed_nesting flags, as well as a closed nesting alternative. + * method-serial.cc: Same. + (serial_dispatch): Renamed to serialirr_dispatch. + (GTM::dispatch_serialirr): Same. + (serial_dispatch_ul): Renamed to serial_dispatch. + (GTM::dispatch_serial): Same. + +2011-07-28 Torvald Riegel + + * libitm.h (_ITM_codeProperties): Change pr_hasElse to the ABI's value. + +2011-07-28 Torvald Riegel + + * aatree.h (aa_tree::remove): New. + (aa_tree::operator new): Add placement new. + +2011-07-02 Torvald Riegel + + * containers.h: New file. + * util.cc (xmalloc, xrealloc): Accept cacheline-alloc flag. + * libitm_i.h (xmalloc, xrealloc): Moved declarations from here ... + * common.h: ... to here. + (local_undo): Use GTM::vector for gtm_transaction::local_undo. + * local.cc: Same. + +2011-06-30 Torvald Riegel + + * libitm_i.h (STATE_ABORTING): Remove. + * beginend.cc (_ITM_abortTransaction): Same. + (GTM::gtm_transaction::trycommit_and_finalize): Same. + * libitm.h (_ITM_registerThrownObject, _ITM_tryCommitTransaction): Remove. + (_ITM_rollbackTransaction): Remove. + * beginend.cc: Same. + * libitm.map: Same. + * libitm.texi: Document these ABI changes. + +2011-06-30 Torvald Riegel + + * libitm.texi: New file. + * Makefile.am: Add libitm.texi. + * Makefile.in: Rebuild. + +2011-06-30 Torvald Riegel + + * libitm_i.h: Move parts to common.h and dispatch.h. + * common.h: New file. + * dispatch.h: New file, new dispatch class. + Rename GTM::abi_dispatch::lock_type to ls_modifier. + RenameGTM::abi_dispatch::NOLOCK to NONTXNAL. + * beginend.cc (GTM::gtm_transaction::begin_transaction): Delegate mode + decision to retry.cc. + * retry.cc (GTM::gtm_transaction::decide_retry_strategy): Use serial mode + only. + (GTM::gtm_transaction::decide_begin_dispatch): Same. + * method-serial.cc: Adapt to new dispatch. Add serial mode with undo + logging. + * barrier.cc: Use new barriers definitions. + (abi_dispatch::memmove_overlap_check): New. + * config/x86/x86_sse.cc: Same. + * config/x86/x86_avx.cc: Same. + * Makefile.am: Don't build readonly and wbetl methods, memset.cc and + memcpy.cc. + * Makefile.in: Rebuild. + * method-readonly.cc: Remove. + * method-wbetl.cc: Rename GTM::abi_dispatch::lock_type to ls_modifier. + Rename GTM::abi_dispatch::NOLOCK to NONTXNAL. + +2011-06-30 Torvald Riegel + + * alloc_c.cc (_ITM_dropReferences): Don't support it anymore. + * testsuite/libitm.c++/dropref.C: _ITM_dropReferences is expected to fail. + * testsuite/libitm.c/dropref-2.c: Same. + * testsuite/libitm.c/dropref.c: Same. + +2011-06-30 Torvald Riegel + + * config/generic/tls.h (gtm_disp): Rename to abi_disp. + * config/generic/tls.h (set_gtm_disp): Rename to set_abi_disp. + * libitm_i.h: Rename gtm_dispatch to abi_dispatch. + * alloc_c.cc: Same. + * barrier.tpl: Same. + * beginend.c: Same. + * config/generic/tls.h: Same. + * config/x86/tls.h: Same. + * libitm_i.h: Same. + * memcpy.cc: Same. + * memset.cc: Same. + * method-readonly.cc: Same. + * method-serial.cc: Same. + * method-wbetl.cc: Same. + * retry.cc: Same. + +2011-03-03 Richard Henderson + + * config/posix/rwlock.cc (write_upgrade): Add missing case. + From Patrik Marlier . + +2011-02-03 Richard Henderson + + * acinclude.m4 (LIBITM_CHECK_SIZE_T_MANGLING): New. + * configure.ac: Use it. + * configure, config.h.in: Rebuild. + * alloc_cpp.cc (_ZnwX): Use MANGLE_SIZE_T in constructing the name. + (_ZnaX, _ZnwXRKSt9nothrow_t, _ZnaXRKSt9nothrow_t, _ZGTtnwX, + _ZGTtnaX, _ZGTtnwXRKSt9nothrow_t, _ZGTtnaXRKSt9nothrow_t): Likewise. + * libitm.map: Use wildcards to match size_t mangling. + +2010-12-14 Richard Henderson + + * beginend.cc (GTM::gtm_transaction::begin_transaction): Allocate + blocks of TIDs per thread. + * config/generic/tls.h (struct gtm_thread): Add local_tid member. + (setup_gtm_thr): Return the thread structure. + * config/x86/tls.h (setup_gtm_thr): Likewise. + +2010-12-14 Richard Henderson + + * clone.cc (table_lock): Remove. + (find_clone): Don't take it. + (ExcludeTransaction): New helper class. + (_ITM_registerTMCloneTable): Use it. + (_ITM_deregisterTMCloneTable): Likewise. + +2010-12-14 Richard Henderson + + * config/x86/tls.h: New file. + +2010-07-15 Richard Henderson + + * Makefile.am (AM_CXXFLAGS): Add -funwind-tables. + * Makefile.in: Rebuild. + +2010-07-13 Aldy Hernandez + + * method-wbetl.cc (trydropreference): Fix source line. + +2010-07-13 Aldy Hernandez + + * libitm.h: Add comment. + * libitm_i.h (begin_transaction): Add ITM_REGPARM. + +2010-07-07 Aldy Hernandez + + * configure.ac: Call LIBITM_CHECK_64BIT_SYNC_BUILTINS. + * beginend.cc (begin_transaction): If 64-bit sync builtins are not + available, use pthread mutexes. + * acinclude.m4 (LIBITM_CHECK_64BIT_SYNC_BUILTINS): New. + * config.h.in: Regenerate. + * configure: Regenerate. + +2010-07-06 Aldy Hernandez + + * libitm.h (ITM_PURE): Define. + Declare _ITM_malloc, _ITM_calloc, and _ITM_free. + +2010-06-28 Aldy Hernandez + + * method-wbetl.cc (class wbetl_dispatch): Add trydropreference. + (validate): Add comment. + (trydropreference): New. + * method-readonly.cc (class readonly_dispatch): Add + trydropreference. + * alloc_c.cc (_ITM_dropReferences): Remove const attribute. + Call trydropreference(). + * libitm.h (_ITM_dropReferences): Remove const attribute. + * method-serial.cc (class serial_dispatch): Add trydropreference. + * libitm_i.h (struct gtm_dispatch): Add trydropreference. + +2010-06-28 Aldy Hernandez + + * memcpy.cc (do_memcpy): Comment. + +2010-06-25 Aldy Hernandez + + * barrier.tpl: Add comments throughout. + +2010-06-24 Aldy Hernandez + + * method-wbetl.cc (struct w_entry): Add comments. + (trycommit): Same. + (rollback): Same. + +2010-06-24 Aldy Hernandez + + * alloc_c.cc (_ITM_dropReferences): New. + * libitm.map (_ITM_dropReferences): Add. + * libitm.h (_ITM_dropReferences): Add transaction_pure attribute. + * libitm_i.h (struct gtm_transaction): Declare + drop_references_allocations and drop_references_local. + * local.cc (rollback_local): Ignore memory when applicable. + (drop_references_local): New. + +2010-06-23 Richard Henderson + + * barrier.tpl, beginend.cc, clone.cc, tls.h, memcpy.cc, + memset.cc, method-serial.cc: Revert the 2010-06-16 change. + * config/x86/target.h (struct gtm_jmpbuf): Change CFA type to void*. + * config/alpha/target.h: Likewise. + * config/generic/tls.cc (gtm_mask_stack): Use it. + +2010-06-23 Richard Henderson + + * config/posix/cachepage.cc (gtm_cacheline_page::operator new): Use + a mutex instead of trying a lock-free compare-and-swap on the list. + (gtm_cacheline_page::operator delete): Likewise. + +2010-06-16 Richard Henderson + + * method-wbetl.cc (wbetl_dispatch::trycommit): Discard changes + that overlap the libitm stack. + * barrier.tpl: Mark incoming stack. + * beginend.cc (_ITM_rollbackTransaction, _ITM_abortTransaction, + _ITM_commitTransaction, _ITM_commitTransactionEH): Likewise. + * clone.cc (_ITM_getTMCloneOrIrrevocable): Likewise. + * memcpy.cc, memset.cc: Likewise. + * method-serial.cc (_ITM_changeTransactionMode): Likewise. + * config/generic/tls.h (gtm_thread): Add stack_top member. + (gtm_stack_top, set_gtm_stack_top, struct gtm_stack_marker): New. + * libitm_i.h (gtm_mask_stack): Declare. + * config/generic/tls.cc: New file. + * Makefile.am (libitm_la_SOURCES): Add it. + (AM_CXXFLAGS): Turn off exceptions. + * Makefile.in: Rebuild. + +2010-06-16 Richard Henderson + + * alloc.cc (struct gtm_alloc_action): Move definition ... + * libitm_i.h: ... here. + (class gtm_transaction): Declare new and delete. + * beginend.cc (alloc_tx): Reformulate as operator new. + (free_tx): Reformulate as operator delete. + * config/generic/tls.h (gtm_thread): Change free_tx member to void *. + +2010-06-11 Richard Henderson + + * clone.cc (clone_entry_compare): Fix typo. + From Patrik Marlier . + +2010-05-13 Richard Henderson + + * alloc_c.cc (_ITM_malloc, _ITM_calloc, _ITM_free): Wrap functions + in extern "C". + +2010-05-07 Aldy Hernandez + + * libitm_i.h (struct gtm_transaction): Remove + get_allocation_size. + (record_allocation): Remove size parameter. + * libitm.map (_ITM_realloc): Remove. + * alloc_c.cc (_ITM_realloc): Remove. + (_ITM_malloc): Remove size argument to record_allocation. + (_ITM_calloc): Same. + * alloc_cpp.cc (_ZGTtnwm): Same. + (_ZGTtnwmRKSt9nothrow_t): Same. + (_ZGTtnam): Same. + (_ZGTtnamRKSt9nothrow_t): Same. + * alloc.cc (struct gtm_alloc_action): Remove size. + (get_allocation_size): Remove. + (commit_allocations): Add comment. + (record_allocation): Remove size parameter. + (forget_allocation): Remove set of size. + +2010-04-19 Aldy Hernandez + + * Makefile.am (abi_version): New. + (AM_CXXFLAGS): Pass abi_version. + * Makefile.in: Regenerate. + * config/x86/unaligned.h: Remove always_inline kludge for vectors. + +2010-04-06 Aldy Hernandez + + * clone.cc (_ITM_getTMCloneOrIrrevocable): Rename from + _ITM_getTMCloneOrIrrevokable. + * libitm.h (_ITM_getTMCloneOrIrrevocable): Same. + * libitm.map (_ITM_getTMCloneOrIrrevocable): Same. + +2010-03-26 Aldy Hernandez + + * configure.ac: Remove Linux futex support. + * configure.tgt (config_path): Same. + * Makefile.am: Same. + * config/linux: Remove entire directory. + * configure: Rebuild. + * Makefile.in: Rebuild. + * testsuite/Makefile.in: Rebuild. + +2010-03-09 Aldy Hernandez + + * retry.cc (decide_retry_strategy): Set state to STATE_SERIAL when + switching to serial mode. + * beginend.cc (trycommit_and_finalize): Unlock serial_lock. + +2010-03-03 Aldy Hernandez + + * configure.tgt: Add emacs -*- tags. + * barrier.tpl: Same. + +2010-02-23 Aldy Hernandez + + * Makefile.am: Rename serial.cc to method-serial.cc. + * Makefile.in: Regenerate with automake 1.11.1. + * testsuite/Makefile.in: Same. + * aclocal.m4: Regenerate with aclocal 1.11.1. + * method-serial.cc: Rename from serial.cc. + * libitm_i.h (struct gtm_transaction): Update comment on + serialirr_mode. + +2010-02-22 Aldy Hernandez + + * libitm_i.h (GTM_longjmp): Add ITM_REGPARM. + * config/linux/rwlock.h (class gtm_rwlock): Add comments. + +2010-02-11 Aldy Hernandez + + * configure: Rebuild. + +2009-11-12 Richard Henderson + + * Rewrite everything in C++. + +2009-11-03 Richard Henderson + + * config/x86/x86_sse.c, config/x86/x86_avx.c: New files. + * Makefile.am (libitm_la_SOURCES): Add them. + * configure.ac (ARCH_X86): New conditional. + * Makefile.in, configure: Rebuild. + * configure.tgt: Set up ARCH; do cflags setup at the same time. + Move futex setup into "other system configury" case. + * local.c (rollback_local): Merge into ... + (GTM_rollback_local): ... here. + (GTM_LB): Rename from GTM_alloc_local; do the memcpy here. + (_ITM_LB): Define as an alias to GTM_LB. + +2009-11-03 Richard Henderson + + * method-readonly.c: New file. + * Makefile.am (libitm_la_SOURCES): Add it. + * Makefile.in: Rebuild. + * beginend.c (gtm_stmlock_array, gtm_clock): New. + (GTM_begin_transaction): Use dispatch_readonly for read-only txn. + * libitm_i.h (gtm_stmlock, gtm_version): Move from method-wbetl.c. + (GTM_VERSION_MAX, GTM_VERSION_INVALID, gtm_stmlock_owned_p, + gtm_stmlock_set_owned, gtm_stmlock_get_addr, + gtm_stmlock_get_version, gtm_stmlock_set_version, LOCK_ARRAY_SIZE, + gtm_stmlock_array, gtm_get_stmlock, gtm_clock, RESTART_NOT_READONLY, + gtm_get_clock, gtm_inc_clock): New. + * method-wbetl.c (gtm_version, gtm_stmlock, OWNED_MASK, VERSION_MAX, + LOCK_GET_OWNED, LOCK_SET_ADDR, LOCK_GET_ADDR, LOCK_GET_TIMESTAMP, + LOCK_SET_TIMESTAMP, LOCK_ARRAY_SIZE, LOCK_MASK, LOCK_IDX, GET_LOCK, + locks, gclock, CLOCK, GET_CLOCK, FETCH_AND_INC_CLOCK): Remove and + replace uses with new libitm_i.h symbols. + (dispatch_wbetl): Rename from wbetl_dispatch. + * retry.c (GTM_decide_retry_strategy): If RESTART_NOT_READONLY, move + away from dispatch_readonly; abort if the beginTransaction call + asserted that the transaction was readonly. + +2009-11-03 Richard Henderson + + * memset.c: New file. + * Makefile.am (libitm_la_SOURCES): Add it. + * Makefile.in: Rebuild. + * testsuite/libitm.c/memset-1.c: New. + +2009-11-03 Richard Henderson + + * dispatch.c: Remove file. + * useraction.c (struct gtm_user_action): Move from libitm.h. + * serial.c (GTM_null_read_lock, GTM_null_write_lock): New. + (serial_memset, serial_memmove, serial_memcpy): Remove. + (serial_W*, serial_R*): Remove. + (serial_dispatch): Update to match. + * configure.ac: Move Werror down below configure checks. Don't + check for sys/loadavg.h, do check for malloc.h. Don't check for + getloadavg and clock_gettime; do check for memalign, posix_memalign. + Use GCC_AC_FUNC_MMAP_BLACKLIST + * libitm.h: Split out all internal items to... + * libitm_i.h: ... here. New file. + * copymask.c: New file. + * local.c (struct gtm_local_undo): Move from libitm.h. + (GTM_alloc_local): Rename from alloc_local; export. + * memcpy.c: New file. + * alloc_c.c (_ITM_realloc): Use _ITM_memcpyRnWt directly. + * config/posix/page.c: New file. + * config/posix/target_tls.h: Remove file. + * barrier.c: New file. + * Makefile.am (libitm_la_SOURCES): Add barrier.c, memcpy.c, + copymask.c, page.c. + * alloc.c (struct gtm_alloc_action): Move from libitm.h. + * method-wbetl.c: Rewrite for new cacheline methods. + * Makefile.in, configure, testsuite/Makefile.in, config.h.in: Rebuild. + + * config/alpha/sjlj.S: Fix typo. + * config/alpha/target_i.h: Copy functions from alpha/target.h. + * config/alpha/copymask.c: New file. + * config/alpha/target.h (CACHELINE_SIZE): New. + (STRICT_ALIGNMENT, PAGE_SIZE, FIXED_PAGE_SIZE): New. + + * config/x86/target_i.h: Copy functions from x86/target.h. + * config/x86/copymask.c: New file. + * config/x86/target.h (_ITM_ALL_TARGET_TYPES): Remove. + (CACHELINE_SIZE, STRICT_ALIGNMENT): New. + (PAGE_SIZE, FIXED_PAGE_SIZE): New. + * config/x86/target_tls.h: Move contents to target_i.h. + + * testsuite/libitm.c/clone-1.c: Include libitm.h. + * testsuite/libitm.c/memcpy-1.c: New. + +2009-10-22 Richard Henderson + + * Makefile.am (CCAS, CCASFLAGS, LTCCASCOMPILE): Remove. + (AM_CCASFLAGS): New. + * configure.ac: Add AM_PROG_AS. Use m4_rename_force for + saving/restoring _AC_ARG_VAR_PRECIOUS. + * Makefile.in, aclocal.m4, config.h.in, configure, + testsuite/Makefile.in: Rebuild with automake 1.11; autoconf 2.64. + +2009-10-22 Richard Henderson + + * testsuite/*: Update for new compiler syntax. + +2009-10-21 Richard Henderson + + * libitm.h (_ITM_abortReason): Add outerAbort. + +2009-08-03 Richard Henderson + + * libitm.map (_ITM_commitTransactionEH, _ITM_cxa_allocate_exception, + _ITM_cxa_begin_catch, _ITM_cxa_end_catch, _ITM_cxa_throw): Export. + * method-wbetl.c (struct w_entry): Remove mask. + (wbetl_write, wbetl_load): Return pointer to word containing the data; + adjust all callers. + +2009-07-22 Richard Henderson + + * eh_cpp.c: New file. + * Makefile.am (libitm_la_SOURCES): Add it. + * Makefile.in: Rebuild. + * beginend.c (GTM_rollback_transaction): Undo exception state. + (GTM_trycommit_transaction): Mark inline. + (GTM_trycommit_and_finalize_transaction): Split out from ... + (_ITM_commitTransaction): ... here. + (_ITM_commitTransactionEH): New function. + * libitm.h (struct gtm_transaction): Add cxa_catch_count, + cxa_unthrown, eh_in_flight; reorder. + + * testsuite/libitm.c++/c++.exp: New. + * testsuite/libitm.c++/eh-1.C: New. + + * aatree.c (aa_free): Remove REGPARM. + * aatree.h: Remove all REGPARM. + +2009-07-18 Richard Henderson + + * aatree.c, aatree.h, alloc.c, alloc_c.c, alloc_cpp.c: New files. + * Makefile.am (libitm_la_SOURCES): Add them. + * Makefile.in: Rebuild. + * beginend.c (GTM_rollback_transaction): Use GTM_commit_allocations. + (GTM_trycommit_transaction): Likewise. + * libitm.h: Include aatree.h + (struct gtm_alloc_action): New. + (struct gtm_transaction): Add alloc_actions. + (GTM_record_allocation, GTM_forget_allocation): Declare. + (GTM_get_allocation_size, GTM_commit_allocations): Declare. + * libitm.map (_ITM_malloc, _ITM_calloc, _ITM_realloc, _ITM_free, + _ZGTtnwm, _ZGTtnam, _ZGTtdlPv, _ZGTtdaPv, _ZGTtnwmRKSt9nothrow_t, + _ZGTtnamRKSt9nothrow_t, _ZGTtdlPvRKSt9nothrow_t, + _ZGTtdaPvRKSt9nothrow_t): Export. + +2009-07-18 Richard Henderson + + * target_tls.h: Move ... + * config/posix/target_tls.h: ... here. + +2009-07-07 Richard Henderson + + * config/x86/target.h (atomic_write_barrier): Use sfence if available. + +2009-07-07 Richard Henderson + + * Update to GPL3. + +2009-07-07 Richard Henderson + + * libitm.h (struct gtm_transaction): Widen id to _ITM_transactionId_t. + * beginend.c (global_tid): Widen to _ITM_transactionId_t. + + * configure.tgt: Don't use -ftls-model for x86 linux. + * libitm.h: Include target.h after standard includes. + (_gtm_thr): Rename from gtm_thr. + (setup_gtm_thr, gtm_thr, gtm_tx, set_gtm_tx): New. + (gtm_disp, set_gtm_disp): New. + * beginend.c, dispatch.c, local.c, method-wbetl.c, query.c, + retry.c, serial.c, useraction.c: Use accessor functions throughout. + * config/alpha/target_tls.h, config/x86/target_tls.h: New files. + +2009-07-07 Richard Henderson + + * config/linux/rwlock.c (EZ): New define. Use it throughout. + +2009-07-06 Richard Henderson + + * libitm.h (_ITM_SRCLOCATION_DECL_1, _ITM_SRCLOCATION_DECL_2): Remove. + (_ITM_SRCLOCATION_DEFN_1, _ITM_SRCLOCATION_DEFN_2): Remove. + (_ITM_beginTransaction): Take variadic arguments. + (_ITM_registerThrownObject): Declare. + * beginend.c, serial.c: Update. + * libitm.map: Add _ITM_registerThrownObject. + +2009-01-28 Richard Henderson + + * Makefile.am (libitm_la_SOURCES): Add clone.c. + * Makefile.in: Rebuild. + * beginend.c (_ITM_abortTransaction): Abort if irrevokable. + (GTM_restart_transaction): Fix uninstrumented code check. + * retry.c (GTM_decide_retry_strategy): Add serial check. + * serial.c (GTM_serialmode): Add irrevokable variable. Don't + automatically go irrevokable when in serial mode. + * clone.c: New file. + * libitm.h, libitm.map: Update. + +2009-01-27 Richard Henderson + + * Makefile.am (LTCCASCOMPILE): Define. + (libitm_la_SOURCES): Add methid-wbetl.c. + * testsuite/Makefile.am: New + * configure.ac: Add testsuite/Makefile. + * Makefile.in, testsuite/Makefile.in, configure: Regenerate. + * beginend.c (GTM_begin_transaction): Install wbetl_dispatch. + (_ITM_abortTransaction): Finalize implementation method; pass + transaction properties to longjmp. + (GTM_restart_transaction): Split out from ... + (_ITM_commitTransaction): ... here. + * config/linux/x86/futex_bits.h (cpu_relax, atomic_write_barrier): + Move to config/x86/target.h. + * config/linux/alpha/futex_bits.h: New. + * config/x86/sjlj.S (GTM_longjmp): Fix 64-bit input register. + * config/x86/target.h: Disable target types for 32-bit. + * config/alpha/sjlj.S, config/alpha/target.h: New. + * libitm.h (struct gtm_dispatch): Add init, fini. + (enum restart_reason): New. + (struct gtm_transaction): Add method and restarts. + * retry.c (GTM_decide_retry_strategy): Implement. + * serial.c (serial_init, serial_fini): New. + (GTM_serialmode): Finialize outgoing method. + * method-wbetl.c: New. + +2008-12-09 Richard Henderson + + * config/x86/target.h (_ITM_ALL_TARGET_TYPES, _ITM_TYPE_ATTR): New. + * configure.tgt (i386-*, x86_64-*): Don't force SSE. + * dispatch.c (_ITM_##R##T, _ITM_##W##T): Use _ITM_TYPE_ATTR. + * libitm.h (_ITM_ALL_TARGET_TYPES, _ITM_TYPE_ATTR): Provide default. + (_ITM_TYPE_M64, _ITM_TYPE_M128, _ITM_TYPE_M256): Move to x86 header. + (_ITM_ALL_TYPES): Use _ITM_ALL_TARGET_TYPES. + * local.c (_ITM_L##T): Use _ITM_TYPE_ATTR. + * serial.c (serial_R##T, serial_W##T): Likewise. + +2008-11-21 Richard Henderson + + * Initial commit. Index: libitm/method-wbetl.cc =================================================================== --- libitm/method-wbetl.cc (.../trunk) (revision 0) +++ libitm/method-wbetl.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,628 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace { + +using namespace GTM; + +class wbetl_dispatch : public abi_dispatch +{ + private: + static const size_t RW_SET_SIZE = 4096; + + struct r_entry + { + gtm_version version; + gtm_stmlock *lock; + }; + + r_entry *m_rset_entries; + size_t m_rset_nb_entries; + size_t m_rset_size; + + struct w_entry + { + /* There's a hashtable where the locks are held, so multiple + cachelines can hash to a given bucket. This link points to the + possible next cacheline that also hashes to this bucket. */ + struct w_entry *next; + + /* Every entry in this bucket (accessed by NEXT) has the same LOCK + address below. */ + gtm_stmlock *lock; + + gtm_cacheline *addr; + gtm_cacheline *value; + gtm_version version; + }; + + w_entry *m_wset_entries; + size_t m_wset_nb_entries; + size_t m_wset_size; + bool m_wset_reallocate; + + gtm_version m_start; + gtm_version m_end; + + gtm_cacheline_page *m_cache_page; + unsigned m_n_cache_page; + + private: + bool local_w_entry_p (w_entry *w); + bool has_read (gtm_stmlock *lock); + bool validate(); + bool extend(); + + gtm_cacheline *do_write_lock(gtm_cacheline *); + gtm_cacheline *do_after_write_lock(gtm_cacheline *); + const gtm_cacheline *do_read_lock(const gtm_cacheline *, bool); + + public: + wbetl_dispatch(); + + virtual const gtm_cacheline *read_lock(const gtm_cacheline *, ls_modifier); + virtual mask_pair write_lock(gtm_cacheline *, ls_modifier); + + virtual bool trycommit(); + virtual void rollback(); + virtual void reinit(); + virtual void fini(); + virtual bool trydropreference (void *, size_t); +}; + +/* Check if W is one of our write locks. */ + +inline bool +wbetl_dispatch::local_w_entry_p (w_entry *w) +{ + return (m_wset_entries <= w && w < m_wset_entries + m_wset_nb_entries); +} + +/* Check if stripe has been read previously. */ + +inline bool +wbetl_dispatch::has_read (gtm_stmlock *lock) +{ + // ??? Consider using an AA tree to lookup the r_set entries. + size_t n = m_rset_nb_entries; + for (size_t i = 0; i < n; ++i) + if (m_rset_entries[i].lock == lock) + return true; + + return false; +} + +/* Validate read set, i.e. check if all read addresses are still valid now. */ + +bool +wbetl_dispatch::validate () +{ + __sync_synchronize (); + + size_t n = m_rset_nb_entries; + for (size_t i = 0; i < n; ++i) + { + r_entry *r = &m_rset_entries[i]; + gtm_stmlock l = *r->lock; + + if (gtm_stmlock_owned_p (l)) + { + w_entry *w = (w_entry *) gtm_stmlock_get_addr (l); + + // If someone has locked us, it better be by someone in the + // current thread. + if (!local_w_entry_p (w)) + return false; + } + else if (gtm_stmlock_get_version (l) != r->version) + return false; + } + + return true; +} + +/* Extend the snapshot range. */ + +bool +wbetl_dispatch::extend () +{ + gtm_version now = gtm_get_clock (); + + if (validate ()) + { + m_end = now; + return true; + } + return false; +} + +/* Acquire a write lock on ADDR. */ + +gtm_cacheline * +wbetl_dispatch::do_write_lock(gtm_cacheline *addr) +{ + gtm_stmlock *lock; + gtm_stmlock l, l2; + gtm_version version; + w_entry *w, *prev = NULL; + + lock = gtm_get_stmlock (addr); + l = *lock; + + restart_no_load: + if (gtm_stmlock_owned_p (l)) + { + w = (w_entry *) gtm_stmlock_get_addr (l); + + /* Did we previously write the same address? */ + if (local_w_entry_p (w)) + { + prev = w; + while (1) + { + if (addr == prev->addr) + return prev->value; + if (prev->next == NULL) + break; + prev = prev->next; + } + + /* Get version from previous entry write set. */ + version = prev->version; + + /* If there's not enough entries, we must reallocate the array, + which invalidates all pointers to write set entries, which + means we have to restart the transaction. */ + if (m_wset_nb_entries == m_wset_size) + { + m_wset_size *= 2; + m_wset_reallocate = true; + gtm_tx()->restart (RESTART_REALLOCATE); + } + + w = &m_wset_entries[m_wset_nb_entries]; + goto do_write; + } + + gtm_tx()->restart (RESTART_LOCKED_WRITE); + } + else + { + version = gtm_stmlock_get_version (l); + + /* We might have read an older version previously. */ + if (version > m_end) + { + if (has_read (lock)) + gtm_tx()->restart (RESTART_VALIDATE_WRITE); + } + + /* Extend write set, aborting to reallocate write set entries. */ + if (m_wset_nb_entries == m_wset_size) + { + m_wset_size *= 2; + m_wset_reallocate = true; + gtm_tx()->restart (RESTART_REALLOCATE); + } + + /* Acquire the lock. */ + w = &m_wset_entries[m_wset_nb_entries]; + l2 = gtm_stmlock_set_owned (w); + l = __sync_val_compare_and_swap (lock, l, l2); + if (l != l2) + goto restart_no_load; + } + + do_write: + m_wset_nb_entries++; + if (prev != NULL) + prev->next = w; + w->next = 0; + w->lock = lock; + w->addr = addr; + w->version = version; + + gtm_cacheline_page *page = m_cache_page; + unsigned index = m_n_cache_page; + + if (page == NULL || index == gtm_cacheline_page::LINES) + { + gtm_cacheline_page *npage = new gtm_cacheline_page; + npage->prev = page; + m_cache_page = page = npage; + m_n_cache_page = 1; + index = 0; + } + else + m_n_cache_page = index + 1; + + gtm_cacheline *line = &page->lines[index]; + w->value = line; + page->masks[index] = 0; + *line = *addr; + + return line; +} + +gtm_cacheline * +wbetl_dispatch::do_after_write_lock (gtm_cacheline *addr) +{ + gtm_stmlock *lock; + gtm_stmlock l; + w_entry *w; + + lock = gtm_get_stmlock (addr); + l = *lock; + assert (gtm_stmlock_owned_p (l)); + + w = (w_entry *) gtm_stmlock_get_addr (l); + assert (local_w_entry_p (w)); + + while (1) + { + if (addr == w->addr) + return w->value; + w = w->next; + } +} + +/* Acquire a read lock on ADDR. */ + +const gtm_cacheline * +wbetl_dispatch::do_read_lock (const gtm_cacheline *addr, bool after_read) +{ + gtm_stmlock *lock; + gtm_stmlock l, l2; + gtm_version version; + w_entry *w; + + lock = gtm_get_stmlock (addr); + l = *lock; + + restart_no_load: + if (gtm_stmlock_owned_p (l)) + { + w = (w_entry *) gtm_stmlock_get_addr (l); + + /* Did we previously write the same address? */ + if (local_w_entry_p (w)) + { + while (1) + { + if (addr == w->addr) + return w->value; + if (w->next == NULL) + return addr; + w = w->next; + } + } + + gtm_tx()->restart (RESTART_LOCKED_READ); + } + + version = gtm_stmlock_get_version (l); + + /* If version is no longer valid, re-validate the read set. */ + if (version > m_end) + { + if (!extend ()) + gtm_tx()->restart (RESTART_VALIDATE_READ); + + if (!after_read) + { + // Verify that the version has not yet been overwritten. The read + // value has not yet been added to read set and may not have been + // checked during the extend. + // + // ??? This only makes sense if we're actually reading the value + // and returning it now -- which I believe the original TinySTM + // did. This doesn't make a whole lot of sense when we're + // manipulating cachelines as we are now. Do we need some other + // form of lock verification here, or is the validate call in + // trycommit sufficient? + + __sync_synchronize (); + l2 = *lock; + if (l != l2) + { + l = l2; + goto restart_no_load; + } + } + } + + if (!after_read) + { + r_entry *r; + + /* Add the address and version to the read set. */ + if (m_rset_nb_entries == m_rset_size) + { + m_rset_size *= 2; + + m_rset_entries = (r_entry *) + xrealloc (m_rset_entries, m_rset_size * sizeof(r_entry)); + } + r = &m_rset_entries[m_rset_nb_entries++]; + r->version = version; + r->lock = lock; + } + + return addr; +} + +const gtm_cacheline * +wbetl_dispatch::read_lock (const gtm_cacheline *addr, ls_modifier ltype) +{ + switch (ltype) + { + case NONTXNAL: + return addr; + case R: + return do_read_lock (addr, false); + case RaR: + return do_read_lock (addr, true); + case RaW: + return do_after_write_lock (const_cast(addr)); + case RfW: + return do_write_lock (const_cast(addr)); + default: + abort (); + } +} + +abi_dispatch::mask_pair +wbetl_dispatch::write_lock (gtm_cacheline *addr, ls_modifier ltype) +{ + gtm_cacheline *line; + + switch (ltype) + { + case NONTXNAL: + return mask_pair (addr, &mask_sink); + case W: + case WaR: + line = do_write_lock (addr); + break; + case WaW: + line = do_after_write_lock (addr); + break; + default: + abort (); + } + + return mask_pair (line, gtm_cacheline_page::mask_for_page_line (line)); +} + +/* Commit the transaction. */ + +bool +wbetl_dispatch::trycommit () +{ + const size_t n = m_wset_nb_entries; + if (n != 0) + { + /* Get commit timestamp. */ + gtm_version t = gtm_inc_clock (); + + /* Validate only if a concurrent transaction has started since. */ + if (m_start != t - 1 && !validate ()) + return false; + + /* Install new versions. */ + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + gtm_cacheline_mask mask + = *gtm_cacheline_page::mask_for_page_line (w->value); + + /* Filter out any updates that overlap the libitm stack. */ + mask = gtm_mask_stack (w->addr, mask); + + gtm_cacheline::copy_mask (w->addr, w->value, mask); + } + + /* Only emit barrier after all cachelines are copied. */ + gtm_cacheline::copy_mask_wb (); + + /* Drop locks. */ + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + + /* Every link along the chain has the same lock, but only + bother dropping the lock once per bucket (at the end). */ + if (w->next == NULL) + *w->lock = gtm_stmlock_set_version (t); + } + } + + __sync_synchronize (); + return true; +} + +void +wbetl_dispatch::rollback () +{ + /* Drop locks. */ + const size_t n = m_wset_nb_entries; + for (size_t i = 0; i < n; ++i) + { + w_entry *w = &m_wset_entries[i]; + + /* Every link along the chain has the same lock, but only + bother dropping the lock once per bucket (at the end). */ + if (w->next == NULL) + *w->lock = gtm_stmlock_set_version (w->version); + } + + __sync_synchronize (); +} + +void +wbetl_dispatch::reinit () +{ + gtm_cacheline_page *page; + + m_rset_nb_entries = 0; + m_wset_nb_entries = 0; + + if (m_wset_reallocate) + { + m_wset_reallocate = 0; + m_wset_entries = (w_entry *) + xrealloc (m_wset_entries, m_wset_size * sizeof(w_entry)); + } + + page = m_cache_page; + if (page) + { + /* Release all but one of the pages of cachelines. */ + gtm_cacheline_page *prev = page->prev; + if (prev) + { + page->prev = 0; + delete prev; + } + + /* Start the next cacheline allocation from the beginning. */ + m_n_cache_page = 0; + } + + m_start = m_end = gtm_get_clock (); +} + +void +wbetl_dispatch::fini () +{ + delete m_cache_page; + free (m_rset_entries); + free (m_wset_entries); + delete this; +} + +/* Attempt to drop any internal references to PTR. Return TRUE if successful. + + This is an adaptation of the transactional memcpy function. + + What we do here is flush out the current transactional content of + PTR to real memory, and remove the write mask bits associated with + it so future commits will ignore this piece of memory. */ + +bool +wbetl_dispatch::trydropreference (void *ptr, size_t size) +{ + if (size == 0) + return true; + + if (!validate ()) + return false; + + uintptr_t isrc = (uintptr_t)ptr; + // The position in the source cacheline where *PTR starts. + uintptr_t sofs = isrc & (CACHELINE_SIZE - 1); + gtm_cacheline *src + = reinterpret_cast(isrc & -CACHELINE_SIZE); + unsigned char *dst = (unsigned char *)ptr; + abi_dispatch::mask_pair pair; + + // If we're trying to drop a reference, we should already have a + // write lock on it. If we don't have one, there's no work to do. + if (!gtm_stmlock_owned_p (*gtm_get_stmlock (src))) + return true; + + // We copy the data in three stages: + + // (a) Copy stray bytes at the beginning that are smaller than a + // cacheline. + if (sofs != 0) + { + size_t sleft = CACHELINE_SIZE - sofs; + size_t min = (size <= sleft ? size : sleft); + + // WaW will give us the current locked entry. + pair = this->write_lock (src, WaW); + + // *jedi mind wave*...these aren't the droids you're looking for. + *pair.mask &= ~((((gtm_cacheline_mask)1 << min) - 1) << sofs); + + memcpy (dst, &pair.line->b[sofs], min); + dst += min; + src++; + size -= min; + } + + // (b) Copy subsequent cacheline sized chunks. + while (size >= CACHELINE_SIZE) + { + pair = this->write_lock(src, WaW); + *pair.mask = 0; + memcpy (dst, pair.line, CACHELINE_SIZE); + dst += CACHELINE_SIZE; + src++; + size -= CACHELINE_SIZE; + } + + // (c) Copy anything left over. + if (size != 0) + { + pair = this->write_lock(src, WaW); + *pair.mask &= ~(((gtm_cacheline_mask)1 << size) - 1); + memcpy (dst, pair.line, size); + } + + // No need to drop locks, since we're going to abort the transaction + // anyhow. + + return true; +} + + +wbetl_dispatch::wbetl_dispatch () + : abi_dispatch (false, false) +{ + m_rset_entries = (r_entry *) xmalloc (RW_SET_SIZE * sizeof(r_entry)); + m_rset_nb_entries = 0; + m_rset_size = RW_SET_SIZE; + + m_wset_entries = (w_entry *) xmalloc (RW_SET_SIZE * sizeof(w_entry)); + m_wset_nb_entries = 0; + m_wset_size = RW_SET_SIZE; + m_wset_reallocate = false; + + m_start = m_end = gtm_get_clock (); + + m_cache_page = 0; + m_n_cache_page = 0; +} + +} // anon namespace + +abi_dispatch * +GTM::dispatch_wbetl () +{ + return new wbetl_dispatch (); +} Index: libitm/alloc_c.cc =================================================================== --- libitm/alloc_c.cc (.../trunk) (revision 0) +++ libitm/alloc_c.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,72 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + + +using namespace GTM; + +extern "C" { + +/* Wrap: malloc (size_t sz) */ +void * +_ITM_malloc (size_t sz) +{ + void *r = malloc (sz); + if (r) + gtm_thr()->record_allocation (r, free); + return r; +} + +/* Wrap: calloc (size_t nm, size_t sz) */ +void * +_ITM_calloc (size_t nm, size_t sz) +{ + void *r = calloc (nm, sz); + if (r) + gtm_thr()->record_allocation (r, free); + return r; +} + +/* Wrap: free (void *ptr) */ +void +_ITM_free (void *ptr) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, free); +} + +/* Forget any internal references to PTR. */ + +__attribute__((transaction_pure)) +void ITM_REGPARM +_ITM_dropReferences (void *ptr, size_t len) +{ + // The semantics of _ITM_dropReferences are not sufficiently defined in the + // ABI specification, so it does not make sense to support it right now. See + // the libitm documentation for details. + GTM_fatal("_ITM_dropReferences is not supported"); +} + +} // extern "C" Index: libitm/clone.cc =================================================================== --- libitm/clone.cc (.../trunk) (revision 0) +++ libitm/clone.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,184 @@ +/* Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +struct clone_entry +{ + void *orig, *clone; +}; + +struct clone_table +{ + clone_entry *table; + size_t size; + clone_table *next; +}; + +static clone_table *all_tables; + +static void * +find_clone (void *ptr) +{ + clone_table *table; + + for (table = all_tables; table ; table = table->next) + { + clone_entry *t = table->table; + size_t lo = 0, hi = table->size, i; + + /* Quick test for whether PTR is present in this table. */ + if (ptr < t[0].orig || ptr > t[hi - 1].orig) + continue; + + /* Otherwise binary search. */ + while (lo < hi) + { + i = (lo + hi) / 2; + if (ptr < t[i].orig) + hi = i; + else if (ptr > t[i].orig) + lo = i + 1; + else + return t[i].clone; + } + + /* Given the quick test above, if we don't find the entry in + this table then it doesn't exist. */ + break; + } + + return NULL; +} + + +void * ITM_REGPARM +_ITM_getTMCloneOrIrrevocable (void *ptr) +{ + void *ret = find_clone (ptr); + if (ret) + return ret; + + gtm_thr()->serialirr_mode (); + + return ptr; +} + +void * ITM_REGPARM +_ITM_getTMCloneSafe (void *ptr) +{ + void *ret = find_clone (ptr); + if (ret == NULL) + abort (); + return ret; +} + +static int +clone_entry_compare (const void *a, const void *b) +{ + const clone_entry *aa = (const clone_entry *)a; + const clone_entry *bb = (const clone_entry *)b; + + if (aa->orig < bb->orig) + return -1; + else if (aa->orig > bb->orig) + return 1; + else + return 0; +} + +namespace { + +// Within find_clone, we know that we are inside a transaction. Because +// of that, we have already synchronized with serial_lock. By taking the +// serial_lock for write, we exclude all transactions while we make this +// change to the clone tables, without having to synchronize on a separate +// lock. Do be careful not to attempt a recursive write lock. + +class ExcludeTransaction +{ + bool do_lock; + + public: + ExcludeTransaction() + { + gtm_thread *tx = gtm_thr(); + do_lock = !(tx && (tx->state & gtm_thread::STATE_SERIAL)); + + if (do_lock) + gtm_thread::serial_lock.write_lock (); + } + + ~ExcludeTransaction() + { + if (do_lock) + gtm_thread::serial_lock.write_unlock (); + } +}; + +} // end anon namespace + + +void +_ITM_registerTMCloneTable (void *xent, size_t size) +{ + clone_entry *ent = static_cast(xent); + clone_table *table; + + table = (clone_table *) xmalloc (sizeof (clone_table)); + table->table = ent; + table->size = size; + + qsort (ent, size, sizeof (clone_entry), clone_entry_compare); + + // Hold the serial_lock while we update the ALL_TABLES datastructure. + { + ExcludeTransaction exclude; + table->next = all_tables; + all_tables = table; + } +} + +void +_ITM_deregisterTMCloneTable (void *xent) +{ + clone_entry *ent = static_cast(xent); + clone_table *tab; + + // Hold the serial_lock while we update the ALL_TABLES datastructure. + { + ExcludeTransaction exclude; + clone_table **pprev; + + for (pprev = &all_tables; + tab = *pprev, tab->table != ent; + pprev = &tab->next) + continue; + *pprev = tab->next; + } + + free (tab); +} Index: libitm/dispatch.h =================================================================== --- libitm/dispatch.h (.../trunk) (revision 0) +++ libitm/dispatch.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,334 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Torvald Riegel . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef DISPATCH_H +#define DISPATCH_H 1 + +#include "libitm.h" +#include "common.h" + +// Creates ABI load/store methods (can be made virtual or static using M, +// use M2 to create separate methods names for virtual and static) +// The _PV variants are for the pure-virtual methods in the base class. +#define ITM_READ_M(T, LSMOD, M, M2) \ + M _ITM_TYPE_##T ITM_REGPARM ITM_##LSMOD##T##M2 (const _ITM_TYPE_##T *ptr) \ + { \ + return load(ptr, abi_dispatch::LSMOD); \ + } + +#define ITM_READ_M_PV(T, LSMOD, M, M2) \ + M _ITM_TYPE_##T ITM_REGPARM ITM_##LSMOD##T##M2 (const _ITM_TYPE_##T *ptr) \ + = 0; + +#define ITM_WRITE_M(T, LSMOD, M, M2) \ + M void ITM_REGPARM ITM_##LSMOD##T##M2 (_ITM_TYPE_##T *ptr, \ + _ITM_TYPE_##T val) \ + { \ + store(ptr, val, abi_dispatch::LSMOD); \ + } + +#define ITM_WRITE_M_PV(T, LSMOD, M, M2) \ + M void ITM_REGPARM ITM_##LSMOD##T##M2 (_ITM_TYPE_##T *ptr, \ + _ITM_TYPE_##T val) \ + = 0; + +// Creates ABI load/store methods for all load/store modifiers for a particular +// type. +#define CREATE_DISPATCH_METHODS_T(T, M, M2) \ + ITM_READ_M(T, R, M, M2) \ + ITM_READ_M(T, RaR, M, M2) \ + ITM_READ_M(T, RaW, M, M2) \ + ITM_READ_M(T, RfW, M, M2) \ + ITM_WRITE_M(T, W, M, M2) \ + ITM_WRITE_M(T, WaR, M, M2) \ + ITM_WRITE_M(T, WaW, M, M2) +#define CREATE_DISPATCH_METHODS_T_PV(T, M, M2) \ + ITM_READ_M_PV(T, R, M, M2) \ + ITM_READ_M_PV(T, RaR, M, M2) \ + ITM_READ_M_PV(T, RaW, M, M2) \ + ITM_READ_M_PV(T, RfW, M, M2) \ + ITM_WRITE_M_PV(T, W, M, M2) \ + ITM_WRITE_M_PV(T, WaR, M, M2) \ + ITM_WRITE_M_PV(T, WaW, M, M2) + +// Creates ABI load/store methods for all types. +// See CREATE_DISPATCH_FUNCTIONS for comments. +#define CREATE_DISPATCH_METHODS(M, M2) \ + CREATE_DISPATCH_METHODS_T (U1, M, M2) \ + CREATE_DISPATCH_METHODS_T (U2, M, M2) \ + CREATE_DISPATCH_METHODS_T (U4, M, M2) \ + CREATE_DISPATCH_METHODS_T (U8, M, M2) \ + CREATE_DISPATCH_METHODS_T (F, M, M2) \ + CREATE_DISPATCH_METHODS_T (D, M, M2) \ + CREATE_DISPATCH_METHODS_T (E, M, M2) \ + CREATE_DISPATCH_METHODS_T (CF, M, M2) \ + CREATE_DISPATCH_METHODS_T (CD, M, M2) \ + CREATE_DISPATCH_METHODS_T (CE, M, M2) +#define CREATE_DISPATCH_METHODS_PV(M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (U1, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (U2, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (U4, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (U8, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (F, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (D, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (E, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (CF, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (CD, M, M2) \ + CREATE_DISPATCH_METHODS_T_PV (CE, M, M2) + +// Creates memcpy/memmove/memset methods. +#define CREATE_DISPATCH_METHODS_MEM() \ +virtual void memtransfer(void *dst, const void* src, size_t size, \ + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) \ +{ \ + memtransfer_static(dst, src, size, may_overlap, dst_mod, src_mod); \ +} \ +virtual void memset(void *dst, int c, size_t size, ls_modifier mod) \ +{ \ + memset_static(dst, c, size, mod); \ +} + +#define CREATE_DISPATCH_METHODS_MEM_PV() \ +virtual void memtransfer(void *dst, const void* src, size_t size, \ + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) = 0; \ +virtual void memset(void *dst, int c, size_t size, ls_modifier mod) = 0; + + +// Creates ABI load/store functions that can target either a class or an +// object. +#define ITM_READ(T, LSMOD, TARGET, M2) \ + _ITM_TYPE_##T ITM_REGPARM _ITM_##LSMOD##T (const _ITM_TYPE_##T *ptr) \ + { \ + return TARGET ITM_##LSMOD##T##M2(ptr); \ + } + +#define ITM_WRITE(T, LSMOD, TARGET, M2) \ + void ITM_REGPARM _ITM_##LSMOD##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \ + { \ + TARGET ITM_##LSMOD##T##M2(ptr, val); \ + } + +// Creates ABI load/store functions for all load/store modifiers for a +// particular type. +#define CREATE_DISPATCH_FUNCTIONS_T(T, TARGET, M2) \ + ITM_READ(T, R, TARGET, M2) \ + ITM_READ(T, RaR, TARGET, M2) \ + ITM_READ(T, RaW, TARGET, M2) \ + ITM_READ(T, RfW, TARGET, M2) \ + ITM_WRITE(T, W, TARGET, M2) \ + ITM_WRITE(T, WaR, TARGET, M2) \ + ITM_WRITE(T, WaW, TARGET, M2) + +// Creates ABI memcpy/memmove/memset functions. +#define ITM_MEMTRANSFER_DEF(TARGET, M2, NAME, READ, WRITE) \ +void ITM_REGPARM _ITM_memcpy##NAME(void *dst, const void *src, size_t size) \ +{ \ + TARGET memtransfer##M2 (dst, src, size, \ + false, GTM::abi_dispatch::WRITE, GTM::abi_dispatch::READ); \ +} \ +void ITM_REGPARM _ITM_memmove##NAME(void *dst, const void *src, size_t size) \ +{ \ + TARGET memtransfer##M2 (dst, src, size, \ + GTM::abi_dispatch::memmove_overlap_check(dst, src, size, \ + GTM::abi_dispatch::WRITE, GTM::abi_dispatch::READ), \ + GTM::abi_dispatch::WRITE, GTM::abi_dispatch::READ); \ +} + +#define ITM_MEMSET_DEF(TARGET, M2, WRITE) \ +void ITM_REGPARM _ITM_memset##WRITE(void *dst, int c, size_t size) \ +{ \ + TARGET memset##M2 (dst, c, size, GTM::abi_dispatch::WRITE); \ +} \ + + +// ??? The number of virtual methods is large (7*4 for integers, 7*6 for FP, +// 7*3 for vectors). Is the cache footprint so costly that we should go for +// a small table instead (i.e., only have two virtual load/store methods for +// each supported type)? Note that this doesn't affect custom code paths at +// all because these use only direct calls. +// A large cache footprint could especially decrease HTM performance (due +// to HTM capacity). We could add the modifier (RaR etc.) as parameter, which +// would give us just 4*2+6*2+3*2 functions (so we'd just need one line for +// the integer loads/stores), but then the modifier can be checked only at +// runtime. +// For memcpy/memmove/memset, we just have two virtual methods (memtransfer +// and memset). +#define CREATE_DISPATCH_FUNCTIONS(TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (U1, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (U2, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (U4, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (U8, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (F, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (D, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (E, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (CF, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (CD, TARGET, M2) \ + CREATE_DISPATCH_FUNCTIONS_T (CE, TARGET, M2) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RnWt, NONTXNAL, W) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RnWtaR, NONTXNAL, WaR) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RnWtaW, NONTXNAL, WaW) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtWn, R, NONTXNAL) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtWt, R, W) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtWtaR, R, WaR) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtWtaW, R, WaW) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaRWn, RaR, NONTXNAL) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaRWt, RaR, W) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaRWtaR, RaR, WaR) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaRWtaW, RaR, WaW) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaWWn, RaW, NONTXNAL) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaWWt, RaW, W) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaWWtaR, RaW, WaR) \ + ITM_MEMTRANSFER_DEF(TARGET, M2, RtaWWtaW, RaW, WaW) \ + ITM_MEMSET_DEF(TARGET, M2, W) \ + ITM_MEMSET_DEF(TARGET, M2, WaR) \ + ITM_MEMSET_DEF(TARGET, M2, WaW) + + +// Creates ABI load/store functions that delegate to a transactional memcpy. +#define ITM_READ_MEMCPY(T, LSMOD, TARGET, M2) \ + _ITM_TYPE_##T ITM_REGPARM _ITM_##LSMOD##T (const _ITM_TYPE_##T *ptr)\ + { \ + _ITM_TYPE_##T v; \ + TARGET memtransfer##M2(&v, ptr, sizeof(_ITM_TYPE_##T), false, \ + GTM::abi_dispatch::NONTXNAL, GTM::abi_dispatch::LSMOD); \ + return v; \ + } + +#define ITM_WRITE_MEMCPY(T, LSMOD, TARGET, M2) \ + void ITM_REGPARM _ITM_##LSMOD##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val)\ + { \ + TARGET memtransfer##M2(ptr, &val, sizeof(_ITM_TYPE_##T), false, \ + GTM::abi_dispatch::LSMOD, GTM::abi_dispatch::NONTXNAL); \ + } + +#define CREATE_DISPATCH_FUNCTIONS_T_MEMCPY(T, TARGET, M2) \ + ITM_READ_MEMCPY(T, R, TARGET, M2) \ + ITM_READ_MEMCPY(T, RaR, TARGET, M2) \ + ITM_READ_MEMCPY(T, RaW, TARGET, M2) \ + ITM_READ_MEMCPY(T, RfW, TARGET, M2) \ + ITM_WRITE_MEMCPY(T, W, TARGET, M2) \ + ITM_WRITE_MEMCPY(T, WaR, TARGET, M2) \ + ITM_WRITE_MEMCPY(T, WaW, TARGET, M2) + + +namespace GTM HIDDEN { + +struct gtm_transaction_cp; + +struct method_group +{ + // Start using a TM method from this group. This constructs required meta + // data on demand when this method group is actually used. Will be called + // either on first use or after a previous call to fini(). + virtual void init() = 0; + // Stop using any method from this group for now. This can be used to + // destruct meta data as soon as this method group is not used anymore. + virtual void fini() = 0; +}; + + +// This is the base interface that all TM methods have to implement. +struct abi_dispatch +{ +public: + enum ls_modifier { NONTXNAL, R, RaR, RaW, RfW, W, WaR, WaW }; + +private: + // Disallow copies + abi_dispatch(const abi_dispatch &) = delete; + abi_dispatch& operator=(const abi_dispatch &) = delete; + +public: + // Starts or restarts a transaction. Is called right before executing the + // transactional application code (by either returning from + // gtm_thread::begin_transaction or doing the longjmp when restarting). + // Returns NO_RESTART if the transaction started successfully. Returns + // a real restart reason if it couldn't start and does need to abort. This + // allows TM methods to just give up and delegate ensuring progress to the + // restart mechanism. If it returns a restart reason, this call must be + // idempotent because it will trigger the restart mechanism, which could + // switch to a different TM method. + virtual gtm_restart_reason begin_or_restart() = 0; + // Tries to commit the transaction. Iff this returns true, the transaction + // got committed and all per-transaction data will have been reset. + // Currently, this is called only for the commit of the outermost + // transaction, or when switching to serial mode (which can happen in a + // nested transaction). + // If privatization safety must be ensured in a quiescence-based way, set + // priv_time to a value different to 0. Nontransactional code will not be + // executed after this commit until all registered threads' shared_state is + // larger than or equal to this value. + virtual bool trycommit(gtm_word& priv_time) = 0; + // Rolls back a transaction. Called on abort or after trycommit() returned + // false. + virtual void rollback(gtm_transaction_cp *cp = 0) = 0; + + // Return an alternative method that is compatible with the current + // method but supports closed nesting. Return zero if there is none. + // Note that too be compatible, it must be possible to switch to this other + // method on begin of a nested transaction without committing or restarting + // the parent method. + virtual abi_dispatch* closed_nesting_alternative() { return 0; } + + bool read_only () const { return m_read_only; } + bool write_through() const { return m_write_through; } + bool can_run_uninstrumented_code() const + { + return m_can_run_uninstrumented_code; + } + // Returns true iff this TM method supports closed nesting. + bool closed_nesting() const { return m_closed_nesting; } + method_group* get_method_group() const { return m_method_group; } + + static void *operator new(size_t s) { return xmalloc (s); } + static void operator delete(void *p) { free (p); } + +public: + static bool memmove_overlap_check(void *dst, const void *src, size_t size, + ls_modifier dst_mod, ls_modifier src_mod); + + // Creates the ABI dispatch methods for loads and stores. + // ??? Should the dispatch table instead be embedded in the dispatch object + // to avoid the indirect lookup in the vtable? + CREATE_DISPATCH_METHODS_PV(virtual, ) + // Creates the ABI dispatch methods for memcpy/memmove/memset. + CREATE_DISPATCH_METHODS_MEM_PV() + +protected: + const bool m_read_only; + const bool m_write_through; + const bool m_can_run_uninstrumented_code; + const bool m_closed_nesting; + method_group* const m_method_group; + abi_dispatch(bool ro, bool wt, bool uninstrumented, bool closed_nesting, + method_group* mg) : + m_read_only(ro), m_write_through(wt), + m_can_run_uninstrumented_code(uninstrumented), + m_closed_nesting(closed_nesting), m_method_group(mg) + { } +}; + +} + +#endif // DISPATCH_H Index: libitm/aatree.cc =================================================================== --- libitm/aatree.cc (.../trunk) (revision 0) +++ libitm/aatree.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,222 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +// Implements an AA tree (http://en.wikipedia.org/wiki/AA_tree) with an +// integer key, and data attached to the node via flexible array member. + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// The code for rebalancing the tree is greatly simplified by never +// having to check for null pointers. Instead, leaf node links point +// to this node, NIL, which points to itself. +const aa_node_base aa_node_base::s_nil(0); + + +// Remove left horizontal links. Swap the pointers of horizontal left links. + +aa_node_base * +aa_node_base::skew () +{ + aa_node_base *l = this->link(L); + if (this->m_level != 0 && l->m_level == this->m_level) + { + this->set_link(L, l->link(R)); + l->set_link(R, this); + return l; + } + return this; +} + + +// Remove consecutive horizontal links. Take the middle node, +// elevate it, and return it. + +aa_node_base * +aa_node_base::split () +{ + aa_node_base *r = this->link(R); + if (this->m_level != 0 && r->link(R)->m_level == this->m_level) + { + this->set_link(R, r->link(L)); + r->set_link(L, this); + r->m_level += 1; + return r; + } + return this; +} + +// Decrease the level of THIS to be one more than the level of its children. + +void +aa_node_base::decrease_level () +{ + aa_node_base *l = this->link(L); + aa_node_base *r = this->link(R); + level_type llev = l->m_level; + level_type rlev = r->m_level; + level_type should_be = (llev < rlev ? llev : rlev) + 1; + + if (should_be < this->m_level) + { + this->m_level = should_be; + if (should_be < rlev) + r->m_level = should_be; + } +} + +// Find and return the node in the tree with key K. + +template +typename aa_tree_key::node_ptr +aa_tree_key::find(KEY k) const +{ + node_ptr t = m_tree; + if (t != 0) + do + { + if (t->key == k) + return t; + t = t->link(k > t->key); + } + while (!t->is_nil()); + return 0; +} + +// Insert N into T and rebalance. Return the new balanced tree. + +template +typename aa_tree_key::node_ptr +aa_tree_key::insert_1 (node_ptr t, node_ptr n) +{ + bool dir = n->key > t->key; + node_ptr c = t->link(dir); + + // Insert the node, recursively. + if (c->is_nil()) + c = n; + else + c = insert_1 (c, n); + t->set_link(dir, c); + + // Rebalance the tree, as needed. + t = t->skew(); + t = t->split(); + + return t; +} + +template +void +aa_tree_key::insert(node_ptr n) +{ + if (m_tree == 0) + m_tree = n; + else + m_tree = insert_1 (m_tree, n); +} + +// Delete K from T and rebalance. Return the new balanced tree. + +template +typename aa_tree_key::node_ptr +aa_tree_key::erase_1 (node_ptr t, KEY k, node_ptr *pfree) +{ + node_ptr r; + bool dir; + + // If this is the node we're looking for, delete it. Else recurse. + if (k == t->key) + { + node_ptr l, sub, end; + + l = t->link(node::L); + r = t->link(node::R); + + if (pfree) + *pfree = t; + + // If this is a leaf node, simply remove the node. Otherwise, + // we have to find either a predecessor or a successor node to + // replace this one. + if (l->is_nil()) + { + if (r->is_nil()) + return r; + sub = r, dir = node::L; + } + else + sub = l, dir = node::R; + + // Find the successor or predecessor. + for (end = sub; !end->link(dir)->is_nil(); end = end->link(dir)) + continue; + + // Remove it (but don't free) from the subtree. + sub = erase_1 (sub, end->key, 0); + + // Replace T with the successor we just extracted. + end->set_link(!dir, sub); + t = end; + } + else + { + dir = k > t->key; + t->set_link(dir, erase_1 (t->link(dir), k, pfree)); + } + + // Rebalance the tree. + t->decrease_level(); + t = t->skew(); + r = t->link(node::R)->skew(); + t->set_link(node::R, r); + r->set_link(node::R, r->link(node::R)->skew()); + t = t->split (); + t->set_link(node::R, t->link(node::R)->split()); + + return t; +} + +template +typename aa_tree_key::node_ptr +aa_tree_key::erase (KEY k) +{ + node_ptr t = m_tree; + if (t == 0) + return 0; + + node_ptr do_free = 0; + t = erase_1 (t, k, &do_free); + if (t->is_nil()) + t = 0; + m_tree = t; + return do_free; +} + +// Instantiate key classes. + +template class aa_tree_key; + +} // namespace GTM Index: libitm/aatree.h =================================================================== --- libitm/aatree.h (.../trunk) (revision 0) +++ libitm/aatree.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,215 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Implements an AA tree (http://en.wikipedia.org/wiki/AA_tree) with an + integer key, and data attached to the node via flexible array member. */ + +#ifndef LIBITM_AATREE_H +#define LIBITM_AATREE_H 1 + +namespace GTM HIDDEN { + +template class aa_tree_key; + +class aa_node_base +{ + public: + static const bool L = false; + static const bool R = true; + + private: + typedef unsigned int level_type; + + aa_node_base *m_link[2]; + level_type m_level; + + static const aa_node_base s_nil; + + public: + aa_node_base(level_type l = 1) + : m_link { const_cast(&s_nil), + const_cast(&s_nil) }, + m_level(l) + { } + + bool is_nil() const { return this == &s_nil; } + + aa_node_base * link(bool d) { return m_link[d]; } + void set_link(bool d, aa_node_base *val) { m_link[d] = val; } + + aa_node_base *skew(); + aa_node_base *split(); + void decrease_level(); + + static void *operator new (size_t s) { return xmalloc (s); } + static void operator delete (void *p) { free (p); } +}; + +template +struct aa_node_key : public aa_node_base +{ + typedef aa_node_base base; + + KEY key; + + explicit aa_node_key(KEY k) : key(k) { } + + aa_node_key * link(bool d) + { + return static_cast(base::link(d)); + } + + aa_node_key *skew() { return static_cast(base::skew()); } + aa_node_key *split() { return static_cast(base::split()); } +}; + +template +struct aa_node : public aa_node_key +{ + typedef aa_node_key base; + + DATA data; + + explicit aa_node(KEY k) : base(k) { } + + aa_node * link(bool d) + { + return static_cast(base::link(d)); + } +}; + +template +class aa_tree_key +{ + public: + typedef aa_node_key node; + typedef node *node_ptr; + + protected: + node_ptr m_tree; + + protected: + aa_tree_key() : m_tree(0) { } + + node_ptr find(KEY k) const; + + static node_ptr insert_1 (node_ptr t, node_ptr n); + void insert(node_ptr n); + + static node_ptr erase_1 (node_ptr t, KEY k, node_ptr *pfree); + node_ptr erase(KEY k); +}; + +extern template class aa_tree_key; + +template +class aa_tree : public aa_tree_key +{ + public: + typedef aa_tree_key base; + typedef aa_node node; + typedef node *node_ptr; + + typedef void (*trav_callback)(KEY, DATA *, void *); + + private: + static void clear_1 (node_ptr); + static void traverse_1 (node_ptr, trav_callback, void *); + + public: + aa_tree() = default; + ~aa_tree() { clear(); } + + static void *operator new (size_t s, aa_tree* p) { return p; } + + DATA *find(KEY k) const + { + node_ptr n = static_cast(base::find (k)); + return n ? &n->data : 0; + } + + DATA *insert(KEY k) + { + node_ptr n = new node(k); + base::insert(n); + return &n->data; + } + + void erase(KEY k) + { + node_ptr n = static_cast(base::erase (k)); + delete n; + } + + node_ptr remove(KEY k, DATA** data) + { + node_ptr n = static_cast(base::erase (k)); + *data = (n ? &n->data : 0); + return n; + } + + void clear() + { + node_ptr n = static_cast(this->m_tree); + if (n) + { + this->m_tree = 0; + clear_1 (n); + } + } + + void traverse (trav_callback cb, void *cb_data) + { + node_ptr t = static_cast(this->m_tree); + if (t != 0) + traverse_1 (t, cb, cb_data); + } +}; + + +template +void +aa_tree::clear_1 (node_ptr t) +{ + if (t->is_nil()) + return; + clear_1 (t->link(node::L)); + clear_1 (t->link(node::R)); + delete t; +} + +template +void +aa_tree::traverse_1 (node_ptr t, trav_callback cb, void *cb_data) +{ + if (t->is_nil()) + return; + cb (t->key, &t->data, cb_data); + traverse_1 (t->link(node::L), cb, cb_data); + traverse_1 (t->link(node::R), cb, cb_data); +} + +} // namespace GTM + +#endif // LIBITM_AATREE_H Index: libitm/libitm.texi =================================================================== --- libitm/libitm.texi (.../trunk) (revision 0) +++ libitm/libitm.texi (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,778 @@ +\input texinfo @c -*-texinfo-*- + +@c %**start of header +@setfilename libitm.info +@settitle GNU libitm +@c %**end of header + + +@copying +Copyright @copyright{} 2011 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``Funding Free Software'', the Front-Cover +texts being (a) (see below), and with the Back-Cover Texts being (b) +(see below). A copy of the license is included in the section entitled +``GNU Free Documentation License''. + +(a) The FSF's Front-Cover Text is: + + A GNU Manual + +(b) The FSF's Back-Cover Text is: + + You have freedom to copy and modify this GNU Manual, like GNU + software. Copies published by the Free Software Foundation raise + funds for GNU development. +@end copying + +@ifinfo +@dircategory GNU Libraries +@direntry +* libitm: (libitm). GNU Transactional Memory Library +@end direntry + +This manual documents the GNU Transactional Memory Library. + +Published by the Free Software Foundation +51 Franklin Street, Fifth Floor +Boston, MA 02110-1301 USA + +@insertcopying +@end ifinfo + + +@setchapternewpage odd + +@titlepage +@title The GNU Transactional Memory Library +@page +@vskip 0pt plus 1filll +@comment For the @value{version-GCC} Version* +@sp 1 +Published by the Free Software Foundation @* +51 Franklin Street, Fifth Floor@* +Boston, MA 02110-1301, USA@* +@sp 1 +@insertcopying +@end titlepage + +@summarycontents +@contents +@page + + +@node Top +@top Introduction +@cindex Introduction + +This manual documents the usage and internals of libitm, the GNU Transactional +Memory Library. It provides transaction support for accesses to a process' +memory, enabling easy-to-use synchronization of accesses to shared memory by +several threads. + + +@comment +@comment When you add a new menu item, please keep the right hand +@comment aligned to the same column. Do not use tabs. This provides +@comment better formatting. +@comment +@menu +* Enabling libitm:: How to enable libitm for your applications. +* C/C++ Language Constructs for TM:: + Notes on the language-level interface supported + by gcc. +* The libitm ABI:: Notes on the external ABI provided by libitm. +* Internals:: Notes on libitm's internal synchronization. +* Copying:: GNU general public license says + how you can copy and share libgomp. +* GNU Free Documentation License:: + How you can copy and share this manual. +* Funding:: How to help assure continued work for free + software. +* Index:: Index of this documentation. +@end menu + + +@c --------------------------------------------------------------------- +@c Enabling libitm +@c --------------------------------------------------------------------- + +@node Enabling libitm +@chapter Enabling libitm + +To activate support for TM in C/C++, the compile-time flag @option{-fgnu-tm} +must be specified. This enables TM language-level constructs such as +transaction statements (@code{__transaction}, @pxref{C/C++ Language +Constructs for TM} for details). + +@c --------------------------------------------------------------------- +@c C/C++ Language Constructs for TM +@c --------------------------------------------------------------------- + +@node C/C++ Language Constructs for TM +@chapter C/C++ Language Constructs for TM + +TODO: link to the C++ TM spec. a few examples. how gcc's support differs. + +@c --------------------------------------------------------------------- +@c The libitm ABI +@c --------------------------------------------------------------------- + +@node The libitm ABI +@chapter The libitm ABI + +The ABI provided by libitm is basically equal to the Linux variant of Intel's +current TM ABI specification document (Revision 1.1, May 6 2009) but with the +differences listed in this chapter. It would be good if these changes would +eventually be merged into a future version of this specification. To ease +look-up, the following subsections mirror the structure of this specification. + +@section [No changes] Objectives +@section [No changes] Non-objectives + +@section Library design principles +@subsection [No changes] Calling conventions +@subsection [No changes] TM library algorithms +@subsection [No changes] Optimized load and store routines +@subsection [No changes] Aligned load and store routines + +@subsection Data logging functions + +The memory locations accessed with transactional loads and stores and the +memory locations whose values are logged must not overlap. This required +separation only extends to the scope of the execution of one transaction +including all the executions of all nested transactions. + +The compiler must be consistent (within the scope of a single transaction) +about which memory locations are shared and which are not shared with other +threads (i.e., data must be accessed either transactionally or +nontransactionally). Otherwise, non-write-through TM algorithms would not work. + +@subsection [No changes] Scatter/gather calls +@subsection [No changes] Serial and irrevocable mode +@subsection [No changes] Transaction descriptor +@subsection Store allocation + +There is no @code{getTransaction} function. + +@subsection [No changes] Naming conventions + +@subsection Function pointer encryption + +Currently, this is not implemented. + + +@section Types and macros list + +@code{_ITM_codeProperties} has changed, @pxref{txn-code-properties,,Starting a +transaction}. +@code{_ITM_srcLocation} is not used. + + +@section Function list + +@subsection Initialization and finalization functions +These functions are not part of the ABI. + +@subsection [No changes] Version checking +@subsection [No changes] Error reporting +@subsection [No changes] inTransaction call + +@subsection State manipulation functions +There is no @code{getTransaction} function. Transaction identifiers for +nested transactions will be ordered but not necessarily sequential (i.e., for +a nested transaction's identifier @var{IN} and its enclosing transaction's +identifier @var{IE}, it is guaranteed that @math{IN >= IE}). + +@subsection [No changes] Source locations + +@subsection Starting a transaction + +@subsubsection Transaction code properties + +@anchor{txn-code-properties} +The bit @code{hasNoXMMUpdate} is instead called @code{hasNoVectorUpdate}. +Iff it is set, vector register save/restore is not necessary for any target +machine. + +The @code{hasNoFloatUpdate} bit (@code{0x0010}) is new. Iff it is set, floating +point register save/restore is not necessary for any target machine. + +@code{undoLogCode} is not supported and a fatal runtime error will be raised +if this bit is set. It is not properly defined in the ABI why barriers +other than undo logging are not present; Are they not necessary (e.g., a +transaction operating purely on thread-local data) or have they been omitted by +the compiler because it thinks that some kind of global synchronization +(e.g., serial mode) might perform better? The specification suggests that the +latter might be the case, but the former seems to be more useful. + +The @code{readOnly} bit (@code{0x4000}) is new. @strong{TODO} Lexical or dynamic +scope? + +@code{hasNoRetry} is not supported. If this bit is not set, but +@code{hasNoAbort} is set, the library can assume that transaction +rollback will not be requested. + +It would be useful if the absence of externally-triggered rollbacks would be +reported for the dynamic scope as well, not just for the lexical scope +(@code{hasNoAbort}). Without this, a library cannot exploit this together +with flat nesting. + +@code{exceptionBlock} is not supported because exception blocks are not used. + +@subsubsection [No changes] Windows exception state +@subsubsection [No changes] Other machine state + +@subsubsection [No changes] Results from beginTransaction + +@subsection Aborting a transaction + +@code{_ITM_rollbackTransaction} is not supported. @code{_ITM_abortTransaction} +is supported but the abort reasons @code{exceptionBlockAbort}, +@code{TMConflict}, and @code{userRetry} are not supported. There are no +exception blocks in general, so the related cases also do not have to be +considered. To encode @code{__transaction_cancel [[outer]]}, compilers must +set the new @code{outerAbort} bit (@code{0x10}) additionally to the +@code{userAbort} bit in the abort reason. + +@subsection Committing a transaction + +The exception handling (EH) scheme is different. The Intel ABI requires the +@code{_ITM_tryCommitTransaction} function that will return even when the +commit failed and will have to be matched with calls to either +@code{_ITM_abortTransaction} or @code{_ITM_commitTransaction}. In contrast, +gcc relies on transactional wrappers for the functions of the Exception +Handling ABI and on one additional commit function (shown below). This allows +the TM to keep track of EH internally and thus it does not have to embed the +cleanup of EH state into the existing EH code in the program. +@code{_ITM_tryCommitTransaction} is not supported. +@code{_ITM_commitTransactionToId} is also not supported because the +propagation of thrown exceptions will not bypass commits of nested +transactions. + +@example +void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; +void *_ITM_cxa_allocate_exception (size_t); +void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +void *_ITM_cxa_begin_catch (void *exc_ptr); +void _ITM_cxa_end_catch (void); +@end example + +@code{_ITM_commitTransactionEH} must be called to commit a transaction if an +exception could be in flight at this position in the code. @code{exc_ptr} is +the current exception or zero if there is no current exception. +The @code{_ITM_cxa...} functions are transactional wrappers for the respective +@code{__cxa...} functions and must be called instead of these in transactional +code. + +To support this EH scheme, libstdc++ needs to provide one additional function +(@code{_cxa_tm_cleanup}), which is used by the TM to clean up the exception +handling state while rolling back a transaction: + +@example +void __cxa_tm_cleanup (void *unthrown_obj, void *cleanup_exc, + unsigned int caught_count); +@end example + +@code{unthrown_obj} is non-null if the program called +@code{__cxa_allocate_exception} for this exception but did not yet called +@code{__cxa_throw} for it. @code{cleanup_exc} is non-null if the program is +currently processing a cleanup along an exception path but has not caught this +exception yet. @code{caught_count} is the nesting depth of +@code{__cxa_begin_catch} within the transaction (which can be counted by the TM +using @code{_ITM_cxa_begin_catch} and @code{_ITM_cxa_end_catch}); +@code{__cxa_tm_cleanup} then performs rollback by essentially performing +@code{__cxa_end_catch} that many times. + + + +@subsection Exception handling support + +Currently, there is no support for functionality like +@code{__transaction_cancel throw} as described in the C++ TM specification. +Supporting this should be possible with the EH scheme explained previously +because via the transactional wrappers for the EH ABI, the TM is able to +observe and intercept EH. + + +@subsection [No changes] Transition to serial--irrevocable mode +@subsection [No changes] Data transfer functions +@subsection [No changes] Transactional memory copies + +@subsection Transactional versions of memmove + +If either the source or destination memory region is to be accessed +nontransactionally, then source and destination regions must not be +overlapping. The respective @code{_ITM_memmove} functions are still +available but a fatal runtime error will be raised if such regions do overlap. +To support this functionality, the ABI would have to specify how the +intersection of the regions has to be accessed (i.e., transactionally or +nontransactionally). + +@subsection [No changes] Transactional versions of memset +@subsection [No changes] Logging functions + +@subsection User-registered commit and undo actions + +Commit actions will get executed in the same order in which the respective +calls to @code{_ITM_addUserCommitAction} happened. Only +@code{_ITM_noTransactionId} is allowed as value for the +@code{resumingTransactionId} argument. Commit actions get executed after +privatization safety has been ensured. + +Undo actions will get executed in reverse order compared to the order in which +the respective calls to @code{_ITM_addUserUndoAction} happened. The ordering of +undo actions w.r.t. the roll-back of other actions (e.g., data transfers or +memory allocations) is undefined. + +@code{_ITM_getThreadnum} is not supported currently because its only purpose +is to provide a thread ID that matches some assumed performance tuning output, +but this output is not part of the ABI nor further defined by it. + +@code{_ITM_dropReferences} is not supported currently because its semantics and +the intention behind it is not entirely clear. The +specification suggests that this function is necessary because of certain +orderings of data transfer undos and the releasing of memory regions (i.e., +privatization). However, this ordering is never defined, nor is the ordering of +dropping references w.r.t. other events. + +@subsection [New] Transactional indirect calls + +Indirect calls (i.e., calls through a function pointer) within transactions +should execute the transactional clone of the original function (i.e., a clone +of the original that has been fully instrumented to use the TM runtime), if +such a clone is available. The runtime provides two functions to +register/deregister clone tables: + +@example +struct clone_entry +@{ + void *orig, *clone; +@}; + +void _ITM_registerTMCloneTable (clone_entry *table, size_t entries); +void _ITM_deregisterTMCloneTable (clone_entry *table); +@end example + +Registered tables must be writable by the TM runtime, and must be live +throughout the life-time of the TM runtime. + +@strong{TODO} The intention was always to drop the registration functions +entirely, and create a new ELF Phdr describing the linker-sorted table. Much +like what currently happens for @code{PT_GNU_EH_FRAME}. +This work kept getting bogged down in how to represent the @var{N} different +code generation variants. We clearly needed at least two---SW and HW +transactional clones---but there was always a suggestion of more variants for +different TM assumptions/invariants. + +The compiler can then use two TM runtime functions to perform indirect calls in +transactions: +@example +void *_ITM_getTMCloneOrIrrevocable (void *function) ITM_REGPARM; +void *_ITM_getTMCloneSafe (void *function) ITM_REGPARM; +@end example + +If there is a registered clone for supplied function, both will return a +pointer to the clone. If not, the first runtime function will attempt to switch +to serial--irrevocable mode and return the original pointer, whereas the second +will raise a fatal runtime error. + +@subsection [New] Transactional dynamic memory management + +@example +void *_ITM_malloc (size_t) + __attribute__((__malloc__)) ITM_PURE; +void *_ITM_calloc (size_t, size_t) + __attribute__((__malloc__)) ITM_PURE; +void _ITM_free (void *) ITM_PURE; +@end example + +These functions are essentially transactional wrappers for @code{malloc}, +@code{calloc}, and @code{free}. Within transactions, the compiler should +replace calls to the original functions with calls to the wrapper functions. + + +@section [No changes] Future Enhancements to the ABI + +@section Sample code + +The code examples might not be correct w.r.t. the current version of the ABI, +especially everything related to exception handling. + + +@section [New] Memory model + +The ABI should define a memory model and the ordering that is guaranteed for +data transfers and commit/undo actions, or at least refer to another memory +model that needs to be preserved. Without that, the compiler cannot ensure the +memory model specified on the level of the programming language (e.g., by the +C++ TM specification). + +For example, if a transactional load is ordered before another load/store, then +the TM runtime must also ensure this ordering when accessing shared state. If +not, this might break the kind of publication safety used in the C++ TM +specification. Likewise, the TM runtime must ensure privatization safety. + + + +@c --------------------------------------------------------------------- +@c Internals +@c --------------------------------------------------------------------- + +@node Internals +@chapter Internals + +@section TM methods and method groups + +libitm supports several ways of synchronizing transactions with each other. +These TM methods (or TM algorithms) are implemented in the form of +subclasses of @code{abi_dispatch}, which provide methods for +transactional loads and stores as well as callbacks for rollback and commit. +All methods that are compatible with each other (i.e., that let concurrently +running transactions still synchronize correctly even if different methods +are used) belong to the same TM method group. Pointers to TM methods can be +obtained using the factory methods prefixed with @code{dispatch_} in +@file{libitm_i.h}. There are two special methods, @code{dispatch_serial} and +@code{dispatch_serialirr}, that are compatible with all methods because they +run transactions completely in serial mode. + +@subsection TM method life cycle + +The state of TM methods does not change after construction, but they do alter +the state of transactions that use this method. However, because +per-transaction data gets used by several methods, @code{gtm_thread} is +responsible for setting an initial state that is useful for all methods. +After that, methods are responsible for resetting/clearing this state on each +rollback or commit (of outermost transactions), so that the transaction +executed next is not affected by the previous transaction. + +There is also global state associated with each method group, which is +initialized and shut down (@code{method_group::init()} and @code{fini()}) +when switching between method groups (see @file{retry.cc}). + +@subsection Selecting the default method + +The default method that libitm uses for freshly started transactions (but +not necessarily for restarted transactions) can be set via an environment +variable (@env{ITM_DEFAULT_METHOD}), whose value should be equal to the name +of one of the factory methods returning abi_dispatch subclasses but without +the "dispatch_" prefix (e.g., "serialirr" instead of +@code{GTM::dispatch_serialirr()}). + +Note that this environment variable is only a hint for libitm and might not +be supported in the future. + + +@section Nesting: flat vs. closed + +We support two different kinds of nesting of transactions. In the case of +@emph{flat nesting}, the nesting structure is flattened and all nested +transactions are subsumed by the enclosing transaction. In contrast, +with @emph{closed nesting}, nested transactions that have not yet committed +can be rolled back separately from the enclosing transactions; when they +commit, they are subsumed by the enclosing transaction, and their effects +will be finally committed when the outermost transaction commits. +@emph{Open nesting} (where nested transactions can commit independently of the +enclosing transactions) are not supported. + +Flat nesting is the default nesting mode, but closed nesting is supported and +used when transactions contain user-controlled aborts +(@code{__transaction_cancel} statements). We assume that user-controlled +aborts are rare in typical code and used mostly in exceptional situations. +Thus, it makes more sense to use flat nesting by default to avoid the +performance overhead of the additional checkpoints required for closed +nesting. User-controlled aborts will correctly abort the innermost enclosing +transaction, whereas the whole (i.e., outermost) transaction will be restarted +otherwise (e.g., when a transaction encounters data conflicts during +optimistic execution). + + +@section Locking conventions + +This section documents the locking scheme and rules for all uses of locking +in libitm. We have to support serial(-irrevocable) mode, which is implemented +using a global lock as explained next (called the @emph{serial lock}). To +simplify the overall design, we use the same lock as catch-all locking +mechanism for other infrequent tasks such as (de)registering clone tables or +threads. Besides the serial lock, there are @emph{per-method-group locks} that +are managed by specific method groups (i.e., groups of similar TM concurrency +control algorithms), and lock-like constructs for quiescence-based operations +such as ensuring privatization safety. + +Thus, the actions that participate in the libitm-internal locking are either +@emph{active transactions} that do not run in serial mode, @emph{serial +transactions} (which (are about to) run in serial mode), and management tasks +that do not execute within a transaction but have acquired the serial mode +like a serial transaction would do (e.g., to be able to register threads with +libitm). Transactions become active as soon as they have successfully used the +serial lock to announce this globally (@pxref{serial-lock-impl,,Serial lock +implementation}). Likewise, transactions become serial transactions as soon as +they have acquired the exclusive rights provided by the serial lock (i.e., +serial mode, which also means that there are no other concurrent active or +serial transactions). Note that active transactions can become serial +transactions when they enter serial mode during the runtime of the +transaction. + +@subsection State-to-lock mapping + +Application data is protected by the serial lock if there is a serial +transaction and no concurrently running active transaction (i.e., non-serial). +Otherwise, application data is protected by the currently selected method +group, which might use per-method-group locks or other mechanisms. Also note +that application data that is about to be privatized might not be allowed to be +accessed by nontransactional code until privatization safety has been ensured; +the details of this are handled by the current method group. + +libitm-internal state is either protected by the serial lock or accessed +through custom concurrent code. The latter applies to the public/shared part +of a transaction object and most typical method-group-specific state. + +The former category (protected by the serial lock) includes: +@itemize @bullet +@item The list of active threads that have used transactions. +@item The tables that map functions to their transactional clones. +@item The current selection of which method group to use. +@item Some method-group-specific data, or invariants of this data. For example, +resetting a method group to its initial state is handled by switching to the +same method group, so the serial lock protects such resetting as well. +@end itemize +In general, such state is immutable whenever there exists an active +(non-serial) transaction. If there is no active transaction, a serial +transaction (or a thread that is not currently executing a transaction but has +acquired the serial lock) is allowed to modify this state (but must of course +be careful to not surprise the current method group's implementation with such +modifications). + +@subsection Lock acquisition order + +To prevent deadlocks, locks acquisition must happen in a globally agreed-upon +order. Note that this applies to other forms of blocking too, but does not +necessarily apply to lock acquisitions that do not block (e.g., trylock() +calls that do not get retried forever). Note that serial transactions are +never return back to active transactions until the transaction has committed. +Likewise, active transactions stay active until they have committed. +Per-method-group locks are typically also not released before commit. + +Lock acquisition / blocking rules: +@itemize @bullet + +@item Transactions must become active or serial before they are allowed to +use method-group-specific locks or blocking (i.e., the serial lock must be +acquired before those other locks, either in serial or nonserial mode). + +@item Any number of threads that do not currently run active transactions can +block while trying to get the serial lock in exclusive mode. Note that active +transactions must not block when trying to upgrade to serial mode unless there +is no other transaction that is trying that (the latter is ensured by the +serial lock implementation. + +@item Method groups must prevent deadlocks on their locks. In particular, they +must also be prepared for another active transaction that has acquired +method-group-specific locks but is blocked during an attempt to upgrade to +being a serial transaction. See below for details. + +@item Serial transactions can acquire method-group-specific locks because there +will be no other active nor serial transaction. + +@end itemize + +There is no single rule for per-method-group blocking because this depends on +when a TM method might acquire locks. If no active transaction can upgrade to +being a serial transaction after it has acquired per-method-group locks (e.g., +when those locks are only acquired during an attempt to commit), then the TM +method does not need to consider a potential deadlock due to serial mode. + +If there can be upgrades to serial mode after the acquisition of +per-method-group locks, then TM methods need to avoid those deadlocks: +@itemize @bullet +@item When upgrading to a serial transaction, after acquiring exclusive rights +to the serial lock but before waiting for concurrent active transactions to +finish (@pxref{serial-lock-impl,,Serial lock implementation} for details), +we have to wake up all active transactions waiting on the upgrader's +per-method-group locks. +@item Active transactions blocking on per-method-group locks need to check the +serial lock and abort if there is a pending serial transaction. +@item Lost wake-ups have to be prevented (e.g., by changing a bit in each +per-method-group lock before doing the wake-up, and only blocking on this lock +using a futex if this bit is not group). +@end itemize + +@strong{TODO}: Can reuse serial lock for gl-*? And if we can, does it make +sense to introduce further complexity in the serial lock? For gl-*, we can +really only avoid an abort if we do -wb and -vbv. + + +@subsection Serial lock implementation +@anchor{serial-lock-impl} + +The serial lock implementation is optimized towards assuming that serial +transactions are infrequent and not the common case. However, the performance +of entering serial mode can matter because when only few transactions are run +concurrently or if there are few threads, then it can be efficient to run +transactions serially. + +The serial lock is similar to a multi-reader-single-writer lock in that there +can be several active transactions but only one serial transaction. However, +we do want to avoid contention (in the lock implementation) between active +transactions, so we split up the reader side of the lock into per-transaction +flags that are true iff the transaction is active. The exclusive writer side +remains a shared single flag, which is acquired using a CAS, for example. +On the fast-path, the serial lock then works similar to Dekker's algorithm but +with several reader flags that a serial transaction would have to check. +A serial transaction thus requires a list of all threads with potentially +active transactions; we can use the serial lock itself to protect this list +(i.e., only threads that have acquired the serial lock can modify this list). + +We want starvation-freedom for the serial lock to allow for using it to ensure +progress for potentially starved transactions (@pxref{progress-guarantees,, +Progress Guarantees} for details). However, this is currently not enforced by +the implementation of the serial lock. + +Here is pseudo-code for the read/write fast paths of acquiring the serial +lock (read-to-write upgrade is similar to write_lock: +@example +// read_lock: +tx->shared_state |= active; +__sync_synchronize(); // or STLD membar, or C++0x seq-cst fence +while (!serial_lock.exclusive) + if (spinning_for_too_long) goto slowpath; + +// write_lock: +if (CAS(&serial_lock.exclusive, 0, this) != 0) + goto slowpath; // writer-writer contention +// need a membar here, but CAS already has full membar semantics +bool need_blocking = false; +for (t: all txns) + @{ + for (;t->shared_state & active;) + if (spinning_for_too_long) @{ need_blocking = true; break; @} + @} +if (need_blocking) goto slowpath; +@end example + +Releasing a lock in this spin-lock version then just consists of resetting +@code{tx->shared_state} to inactive or clearing @code{serial_lock.exclusive}. + +However, we can't rely on a pure spinlock because we need to get the OS +involved at some time (e.g., when there are more threads than CPUs to run on). +Therefore, the real implementation falls back to a blocking slow path, either +based on pthread mutexes or Linux futexes. + + +@subsection Reentrancy + +libitm has to consider the following cases of reentrancy: +@itemize @bullet + +@item Transaction calls unsafe code that starts a new transaction: The outer +transaction will become a serial transaction before executing unsafe code. +Therefore, nesting within serial transactions must work, even if the nested +transaction is called from within uninstrumented code. + +@item Transaction calls either a transactional wrapper or safe code, which in +turn starts a new transaction: It is not yet defined in the specification +whether this is allowed. Thus, it is undefined whether libitm supports this. + +@item Code that starts new transactions might be called from within any part +of libitm: This kind of reentrancy would likely be rather complex and can +probably be avoided. Therefore, it is not supported. + +@end itemize + +@subsection Privatization safety + +Privatization safety is ensured by libitm using a quiescence-based approach. +Basically, a privatizing transaction waits until all concurrent active +transactions will either have finished (are not active anymore) or operate on +a sufficiently recent snapshot to not access the privatized data anymore. This +happens after the privatizing transaction has stopped being an active +transaction, so waiting for quiescence does not contribute to deadlocks. + +In method groups that need to ensure publication safety explicitly, active +transactions maintain a flag or timestamp in the public/shared part of the +transaction descriptor. Before blocking, privatizers need to let the other +transactions know that they should wake up the privatizer. + +@strong{TODO} Ho to implement the waiters? Should those flags be +per-transaction or at a central place? We want to avoid one wake/wait call +per active transactions, so we might want to use either a tree or combining +to reduce the syscall overhead, or rather spin for a long amount of time +instead of doing blocking. Also, it would be good if only the last transaction +that the privatizer waits for would do the wake-up. + +@subsection Progress guarantees +@anchor{progress-guarantees} + +Transactions that do not make progress when using the current TM method will +eventually try to execute in serial mode. Thus, the serial lock's progress +guarantees determine the progress guarantees of the whole TM. Obviously, we at +least need deadlock-freedom for the serial lock, but it would also be good to +provide starvation-freedom (informally, all threads will finish executing a +transaction eventually iff they get enough cycles). + +However, the scheduling of transactions (e.g., thread scheduling by the OS) +also affects the handling of progress guarantees by the TM. First, the TM +can only guarantee deadlock-freedom if threads do not get stopped. Likewise, +low-priority threads can starve if they do not get scheduled when other +high-priority threads get those cycles instead. + +If all threads get scheduled eventually, correct lock implementations will +provide deadlock-freedom, but might not provide starvation-freedom. We can +either enforce the latter in the TM's lock implementation, or assume that +the scheduling is sufficiently random to yield a probabilistic guarantee that +no thread will starve (because eventually, a transaction will encounter a +scheduling that will allow it to run). This can indeed work well in practice +but is not necessarily guaranteed to work (e.g., simple spin locks can be +pretty efficient). + +Because enforcing stronger progress guarantees in the TM has a higher runtime +overhead, we focus on deadlock-freedom right now and assume that the threads +will get scheduled eventually by the OS (but don't consider threads with +different priorities). We should support starvation-freedom for serial +transactions in the future. Everything beyond that is highly related to proper +contention management across all of the TM (including with TM method to +choose), and is future work. + +@strong{TODO} Handling thread priorities: We want to avoid priority inversion +but it's unclear how often that actually matters in practice. Workloads that +have threads with different priorities will likely also require lower latency +or higher throughput for high-priority threads. Therefore, it probably makes +not that much sense (except for eventual progress guarantees) to use +priority inheritance until the TM has priority-aware contention management. + + +@c --------------------------------------------------------------------- +@c GNU General Public License +@c --------------------------------------------------------------------- + +@include gpl.texi + + + +@c --------------------------------------------------------------------- +@c GNU Free Documentation License +@c --------------------------------------------------------------------- + +@include fdl.texi + + + +@c --------------------------------------------------------------------- +@c Funding Free Software +@c --------------------------------------------------------------------- + +@include funding.texi + +@c --------------------------------------------------------------------- +@c Index +@c --------------------------------------------------------------------- + +@node Index +@unnumbered Index + +@printindex cp + +@bye Index: libitm/containers.h =================================================================== --- libitm/containers.h (.../trunk) (revision 0) +++ libitm/containers.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,108 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Torvald Riegel . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_CONTAINERS_H +#define LIBITM_CONTAINERS_H 1 + +#include "common.h" + +namespace GTM HIDDEN { + +// A simple vector-like container. +// If alloc_seperate_cl is true, allocations will happen on separate cache +// lines. +template +class vector +{ + private: + size_t m_capacity; + size_t m_size; + T* entries; + + // Initial capacity of the vector. + static const size_t default_initial_capacity = 32; + // Above that capacity, grow vector by that size for each call. + static const size_t default_resize_max = 2048; + // Resize vector to at least this capacity. + static const size_t default_resize_min = 32; + + // Don't try to copy this vector. + vector(const vector& x); + + public: + typedef T datatype; + typedef T* iterator; + + iterator begin() const { return entries; } + iterator end() const { return entries + m_size; } + T& operator[] (size_t pos) { return entries[pos]; } + const T& operator[] (size_t pos) const { return entries[pos]; } + + vector(size_t initial_size = default_initial_capacity) + : m_capacity(initial_size), + m_size(0) + { + if (m_capacity > 0) + entries = (T*) xmalloc(sizeof(T) * m_capacity, alloc_separate_cl); + else + entries = 0; + } + ~vector() { if (m_capacity) free(entries); } + + void resize() + { + if (m_capacity >= default_resize_max) + m_capacity = m_capacity + default_resize_max; + else + m_capacity = m_capacity * 2; + if (m_capacity < default_resize_min) + m_capacity = default_resize_min; + entries = (T*) xrealloc(entries, sizeof(T) * m_capacity, alloc_separate_cl); + } + void resize_noinline() __attribute__((noinline)) { resize(); } + + size_t size() const { return m_size; } + size_t capacity() const { return this->capacity; } + + void clear() { m_size = 0; } + + iterator push() { + // We don't want inlining here since push() is often on the fast path. + if (unlikely(m_size == m_capacity)) resize_noinline(); + return &entries[m_size++]; + } + + iterator pop() { + if (likely(m_size > 0)) + { + m_size--; + return entries + m_size; + } + else return 0; + } +}; + +} // namespace GTM + +#endif // LIBITM_CONTAINERS_H Index: libitm/libitm.map =================================================================== --- libitm/libitm.map (.../trunk) (revision 0) +++ libitm/libitm.map (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,185 @@ +LIBITM_1.0 { + global: + _ITM_abortTransaction; + _ITM_addUserCommitAction; + _ITM_addUserUndoAction; + _ITM_beginTransaction; + _ITM_changeTransactionMode; + _ITM_commitTransaction; + _ITM_commitTransactionEH; + _ITM_error; + _ITM_getThreadnum; + _ITM_getTransactionId; + _ITM_inTransaction; + _ITM_libraryVersion; + _ITM_versionCompatible; + + _ITM_registerTMCloneTable; + _ITM_deregisterTMCloneTable; + _ITM_getTMCloneOrIrrevocable; + _ITM_getTMCloneSafe; + + _ITM_LB; + _ITM_LCD; + _ITM_LCE; + _ITM_LCF; + _ITM_LD; + _ITM_LE; + _ITM_LF; + _ITM_LM128; + _ITM_LM256; + _ITM_LM64; + _ITM_LU1; + _ITM_LU2; + _ITM_LU4; + _ITM_LU8; + + _ITM_RCD; + _ITM_RCE; + _ITM_RCF; + _ITM_RD; + _ITM_RE; + _ITM_RF; + _ITM_RM128; + _ITM_RM256; + _ITM_RM64; + _ITM_RU1; + _ITM_RU2; + _ITM_RU4; + _ITM_RU8; + _ITM_RaRCD; + _ITM_RaRCE; + _ITM_RaRCF; + _ITM_RaRD; + _ITM_RaRE; + _ITM_RaRF; + _ITM_RaRM128; + _ITM_RaRM256; + _ITM_RaRM64; + _ITM_RaRU1; + _ITM_RaRU2; + _ITM_RaRU4; + _ITM_RaRU8; + _ITM_RaWCD; + _ITM_RaWCE; + _ITM_RaWCF; + _ITM_RaWD; + _ITM_RaWE; + _ITM_RaWF; + _ITM_RaWM128; + _ITM_RaWM256; + _ITM_RaWM64; + _ITM_RaWU1; + _ITM_RaWU2; + _ITM_RaWU4; + _ITM_RaWU8; + _ITM_RfWCD; + _ITM_RfWCE; + _ITM_RfWCF; + _ITM_RfWD; + _ITM_RfWE; + _ITM_RfWF; + _ITM_RfWM128; + _ITM_RfWM256; + _ITM_RfWM64; + _ITM_RfWU1; + _ITM_RfWU2; + _ITM_RfWU4; + _ITM_RfWU8; + + _ITM_WCD; + _ITM_WCE; + _ITM_WCF; + _ITM_WD; + _ITM_WE; + _ITM_WF; + _ITM_WM128; + _ITM_WM256; + _ITM_WM64; + _ITM_WU1; + _ITM_WU2; + _ITM_WU4; + _ITM_WU8; + _ITM_WaRCD; + _ITM_WaRCE; + _ITM_WaRCF; + _ITM_WaRD; + _ITM_WaRE; + _ITM_WaRF; + _ITM_WaRM128; + _ITM_WaRM256; + _ITM_WaRM64; + _ITM_WaRU1; + _ITM_WaRU2; + _ITM_WaRU4; + _ITM_WaRU8; + _ITM_WaWCD; + _ITM_WaWCE; + _ITM_WaWCF; + _ITM_WaWD; + _ITM_WaWE; + _ITM_WaWF; + _ITM_WaWM128; + _ITM_WaWM256; + _ITM_WaWM64; + _ITM_WaWU1; + _ITM_WaWU2; + _ITM_WaWU4; + _ITM_WaWU8; + + _ITM_memcpyRnWt; + _ITM_memcpyRnWtaR; + _ITM_memcpyRnWtaW; + _ITM_memcpyRtWn; + _ITM_memcpyRtWt; + _ITM_memcpyRtWtaR; + _ITM_memcpyRtWtaW; + _ITM_memcpyRtaRWn; + _ITM_memcpyRtaRWt; + _ITM_memcpyRtaRWtaR; + _ITM_memcpyRtaRWtaW; + _ITM_memcpyRtaWWn; + _ITM_memcpyRtaWWt; + _ITM_memcpyRtaWWtaR; + _ITM_memcpyRtaWWtaW; + _ITM_memmoveRnWt; + _ITM_memmoveRnWtaR; + _ITM_memmoveRnWtaW; + _ITM_memmoveRtWn; + _ITM_memmoveRtWt; + _ITM_memmoveRtWtaR; + _ITM_memmoveRtWtaW; + _ITM_memmoveRtaRWn; + _ITM_memmoveRtaRWt; + _ITM_memmoveRtaRWtaR; + _ITM_memmoveRtaRWtaW; + _ITM_memmoveRtaWWn; + _ITM_memmoveRtaWWt; + _ITM_memmoveRtaWWtaR; + _ITM_memmoveRtaWWtaW; + _ITM_memsetW; + _ITM_memsetWaR; + _ITM_memsetWaW; + + _ITM_malloc; + _ITM_calloc; + _ITM_free; + _ITM_dropReferences; + + _ZGTtnw?; + _ZGTtna?; + _ZGTtdlPv; + _ZGTtdaPv; + _ZGTtnw?RKSt9nothrow_t; + _ZGTtna?RKSt9nothrow_t; + _ZGTtdlPvRKSt9nothrow_t; + _ZGTtdaPvRKSt9nothrow_t; + + _ITM_cxa_allocate_exception; + _ITM_cxa_begin_catch; + _ITM_cxa_end_catch; + _ITM_cxa_throw; + + local: + *; +}; Index: libitm/util.cc =================================================================== --- libitm/util.cc (.../trunk) (revision 0) +++ libitm/util.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,85 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include +#include + +namespace GTM HIDDEN { + +static void +gtm_verror (const char *fmt, va_list list) +{ + fputs ("\nlibitm: ", stderr); + vfprintf (stderr, fmt, list); + fputc ('\n', stderr); +} + +void +GTM_error (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); +} + +void +GTM_fatal (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); + + exit (EXIT_FAILURE); +} + +void * +xmalloc (size_t size, bool separate_cl) +{ + // TODO Use posix_memalign if separate_cl is true, or some other allocation + // method that will avoid sharing cache lines with data used by other + // threads. + void *r = malloc (size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +void * +xrealloc (void *old, size_t size, bool separate_cl) +{ + // TODO Use posix_memalign if separate_cl is true, or some other allocation + // method that will avoid sharing cache lines with data used by other + // threads. + void *r = realloc (old, size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +} // namespace GTM Index: libitm/configure.ac =================================================================== --- libitm/configure.ac (.../trunk) (revision 0) +++ libitm/configure.ac (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,262 @@ +# Process this file with autoreconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([GNU TM Runtime Library], 1.0,,[libitm]) +AC_CONFIG_HEADER(config.h) + +# ------- +# Options +# ------- + +AC_MSG_CHECKING([for --enable-version-specific-runtime-libs]) +LIBITM_ENABLE(version-specific-runtime-libs, no, , + [Specify that runtime libraries should be installed in a compiler-specific directory], + permit yes|no) +AC_MSG_RESULT($enable_version_specific_runtime_libs) + +# We would like our source tree to be readonly. However when releases or +# pre-releases are generated, the flex/bison generated files as well as the +# various formats of manuals need to be included along with the rest of the +# sources. Therefore we have --enable-generated-files-in-srcdir to do +# just that. +AC_MSG_CHECKING([for --enable-generated-files-in-srcdir]) +LIBITM_ENABLE(generated-files-in-srcdir, no, , + [put copies of generated files in source dir intended for creating source + tarballs for users without texinfo bison or flex.], + permit yes|no) +AC_MSG_RESULT($enable_generated_files_in_srcdir) +AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes) + + +# ------- +# ------- + +# Gets build, host, target, *_vendor, *_cpu, *_os, etc. +# +# You will slowly go insane if you do not grok the following fact: when +# building this library, the top-level /target/ becomes the library's /host/. +# +# configure then causes --target to default to --host, exactly like any +# other package using autoconf. Therefore, 'target' and 'host' will +# always be the same. This makes sense both for native and cross compilers +# just think about it for a little while. :-) +# +# Also, if this library is being configured as part of a cross compiler, the +# top-level configure script will pass the "real" host as $with_cross_host. +# +# Do not delete or change the following two lines. For why, see +# http://gcc.gnu.org/ml/libstdc++/2003-07/msg00451.html +AC_CANONICAL_SYSTEM +target_alias=${target_alias-$host_alias} + +# Sets up automake. Must come after AC_CANONICAL_SYSTEM. Each of the +# following is magically included in AUTOMAKE_OPTIONS in each Makefile.am. +# 1.9.0: minimum required version +# no-define: PACKAGE and VERSION will not be #define'd in config.h (a bunch +# of other PACKAGE_* variables will, however, and there's nothing +# we can do about that; they come from AC_INIT). +# foreign: we don't follow the normal rules for GNU packages (no COPYING +# file in the top srcdir, etc, etc), so stop complaining. +# -Wall: turns on all automake warnings... +# -Wno-portability: ...except this one, since GNU make is required. +# -Wno-override: ... and this one, since we do want this in testsuite. +AM_INIT_AUTOMAKE([1.9.0 foreign -Wall -Wno-portability -Wno-override]) +AM_ENABLE_MULTILIB(, ..) + +# Calculate toolexeclibdir +# Also toolexecdir, though it's only used in toolexeclibdir +case ${enable_version_specific_runtime_libs} in + yes) + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. + toolexecdir='$(libdir)/gcc/$(target_alias)' + toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)' + ;; + no) + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + # Install a library built with a cross compiler in tooldir, not libdir. + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' + else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' + fi + multi_os_directory=`$CC -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; + esac + ;; +esac +AC_SUBST(toolexecdir) +AC_SUBST(toolexeclibdir) + +# Check the compiler. +# The same as in boehm-gc and libstdc++. Have to borrow it from there. +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. + +m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +AC_PROG_CC +AC_PROG_CXX +AM_PROG_AS +m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +AC_SUBST(CFLAGS) + +# In order to override CFLAGS_FOR_TARGET, all of our special flags go +# in XCFLAGS. But we need them in CFLAGS during configury. So put them +# in both places for now and restore CFLAGS at the end of config. +save_CFLAGS="$CFLAGS" + +# Find other programs we need. +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(NM, nm) +AC_CHECK_TOOL(RANLIB, ranlib, ranlib-not-found-in-path-error) +AC_PATH_PROG(PERL, perl, perl-not-found-in-path-error) +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +# See if makeinfo has been installed and is modern enough +# that we can use it. +ACX_CHECK_PROG_VER([MAKEINFO], [makeinfo], [--version], + [GNU texinfo.* \([0-9][0-9.]*\)], + [4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*]) +AM_CONDITIONAL(BUILD_INFO, test $gcc_cv_prog_makeinfo_modern = "yes") + + +# Configure libtool +AM_PROG_LIBTOOL +AC_SUBST(enable_shared) +AC_SUBST(enable_static) + +AM_MAINTAINER_MODE + +# We need gfortran to compile parts of the library +# We can't use AC_PROG_FC because it expects a fully working gfortran. +#AC_PROG_FC(gfortran) +FC="$GFORTRAN" +AC_PROG_FC(gfortran) +FCFLAGS="$FCFLAGS -Wall" + +# For libtool versioning info, format is CURRENT:REVISION:AGE +libtool_VERSION=1:0:0 +AC_SUBST(libtool_VERSION) + +# Check header files. +AC_STDC_HEADERS +AC_HEADER_TIME +ACX_HEADER_STRING +AC_CHECK_HEADERS(unistd.h semaphore.h sys/time.h malloc.h) + +GCC_HEADER_STDINT(gstdint.h) + +GCC_AC_FUNC_MMAP_BLACKLIST + +AC_C_BIGENDIAN +# I don't like the default behaviour of WORDS_BIGENDIAN undefined for LE. +AH_BOTTOM( +[#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif]) + +# Check to see if -pthread or -lpthread is needed. Prefer the former. +# In case the pthread.h system header is not found, this test will fail. +XPCFLAGS="" +CFLAGS="$CFLAGS -pthread" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include + void *g(void *d) { return NULL; }], + [pthread_t t; pthread_create(&t,NULL,g,NULL);])], + [XPCFLAGS=" -Wc,-pthread"], + [CFLAGS="$save_CFLAGS" LIBS="-lpthread $LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include + void *g(void *d) { return NULL; }], + [pthread_t t; pthread_create(&t,NULL,g,NULL);])], + [], + [AC_MSG_ERROR([Pthreads are required to build libitm])])]) + +# Check for functions needed. +AC_CHECK_FUNCS(strtoull memalign posix_memalign) + +# Check for broken semaphore implementation on darwin. +# sem_init returns: sem_init error: Function not implemented. +case "$host" in + *-darwin*) + AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1, + Define if the POSIX Semaphores do not work on your system.) + ;; +esac + +GCC_LINUX_FUTEX(:) + +# See if we support thread-local storage. +GCC_CHECK_TLS + +# See what sort of export controls are availible. +LIBITM_CHECK_ATTRIBUTE_VISIBILITY +LIBITM_CHECK_ATTRIBUTE_DLLEXPORT +LIBITM_CHECK_ATTRIBUTE_ALIAS +LIBITM_ENABLE_SYMVERS + +if test $enable_symvers = gnu; then + AC_DEFINE(LIBITM_GNU_SYMBOL_VERSIONING, 1, + [Define to 1 if GNU symbol versioning is used for libitm.]) +fi + +# Determine the proper ABI type for size_t. +LIBITM_CHECK_SIZE_T_MANGLING + +# Get target configury. +. ${srcdir}/configure.tgt +CFLAGS="$save_CFLAGS $XCFLAGS" + +# Check for __sync_val_compare_and_swap, but only after the target has +# had a chance to set XCFLAGS. +LIBITM_CHECK_SYNC_BUILTINS +LIBITM_CHECK_64BIT_SYNC_BUILTINS + +# Cleanup and exit. +CFLAGS="$save_CFLAGS" +AC_CACHE_SAVE + +# Add -Wall -Werror if we are using GCC. +if test "x$GCC" = "xyes"; then + XCFLAGS="$XCFLAGS -Wall -Werror" +fi + +XCFLAGS="$XCFLAGS $XPCFLAGS" + +AC_SUBST(config_path) +AC_SUBST(XCFLAGS) +AC_SUBST(XLDFLAGS) + +if test ${multilib} = yes; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +# Set up the set of libraries that we need to link against for libitm. +# Note that the GOMP_SELF_SPEC in gcc.c will force -pthread for -fopenmp, +# which will force linkage against -lpthread (or equivalent for the system). +# That's not 100% ideal, but about the best we can do easily. +if test $enable_shared = yes; then + link_itm="-litm %{static: $LIBS}" +else + link_itm="-litm $LIBS" +fi +AC_SUBST(link_itm) + +AM_CONDITIONAL([ARCH_X86], [test "$ARCH" = x86]) +AM_CONDITIONAL([ARCH_FUTEX], [test $enable_linux_futex = yes]) + +AC_CONFIG_FILES(Makefile testsuite/Makefile libitm.spec) +AC_OUTPUT Index: libitm/libitm.h =================================================================== --- libitm/libitm.h (.../trunk) (revision 0) +++ libitm/libitm.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,288 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* The external interface of this library follows the specification described + in version 1 of http://www.intel.com/some/path/here.pdf. */ + +#ifndef LIBITM_H +#define LIBITM_H 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __i386__ +/* Only for 32-bit x86. */ +# define ITM_REGPARM __attribute__((regparm(2))) +#else +# define ITM_REGPARM +#endif + +#define ITM_NORETURN __attribute__((noreturn)) +#define ITM_PURE __attribute__((transaction_pure)) + +/* The following are externally visible definitions and functions, though + only very few of these should be called by user code. */ + +/* Values used as arguments to abort. */ +typedef enum { + userAbort = 1, + userRetry = 2, + TMConflict= 4, + exceptionBlockAbort = 8, + outerAbort = 16 +} _ITM_abortReason; + +/* Arguments to changeTransactionMode */ +typedef enum +{ + modeSerialIrrevocable, +} _ITM_transactionState; + +/* Results from inTransaction */ +typedef enum +{ + outsideTransaction = 0, /* So "if (inTransaction(td))" works */ + inRetryableTransaction, + inIrrevocableTransaction +} _ITM_howExecuting; + +/* Values to describe properties of code, passed in to beginTransaction */ +typedef enum +{ + pr_instrumentedCode = 0x0001, + pr_uninstrumentedCode = 0x0002, + pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode, + /* Called pr_hasNoXMMUpdate in the Intel document, used for + avoiding vector register save/restore for any target. */ + pr_hasNoVectorUpdate = 0x0004, + pr_hasNoAbort = 0x0008, + /* Not present in the Intel document, used for avoiding + floating point register save/restore for any target. */ + pr_hasNoFloatUpdate = 0x0010, + pr_hasNoIrrevocable = 0x0020, + pr_doesGoIrrevocable = 0x0040, + pr_aWBarriersOmitted = 0x0100, + pr_RaRBarriersOmitted = 0x0200, + pr_undoLogCode = 0x0400, + pr_preferUninstrumented = 0x0800, + /* Exception blocks are not used nor supported. */ + pr_exceptionBlock = 0x1000, + pr_hasElse = 0x2000, + pr_readOnly = 0x4000, + pr_hasNoSimpleReads = 0x400000 +} _ITM_codeProperties; + +/* Result from startTransaction that describes what actions to take. */ +typedef enum +{ + a_runInstrumentedCode = 0x01, + a_runUninstrumentedCode = 0x02, + a_saveLiveVariables = 0x04, + a_restoreLiveVariables = 0x08, + a_abortTransaction = 0x10, +} _ITM_actions; + +typedef struct +{ + uint32_t reserved_1; + uint32_t flags; + uint32_t reserved_2; + uint32_t reserved_3; + const char *psource; +} _ITM_srcLocation; + +typedef void (* _ITM_userUndoFunction)(void *); +typedef void (* _ITM_userCommitFunction) (void *); + +#define _ITM_VERSION "0.90 (Feb 29 2008)" +#define _ITM_VERSION_NO 90 + +extern int _ITM_versionCompatible (int) ITM_REGPARM; +extern const char * _ITM_libraryVersion (void) ITM_REGPARM; + +void _ITM_error(const _ITM_srcLocation *, int errorCode) + ITM_REGPARM ITM_NORETURN; + +extern _ITM_howExecuting _ITM_inTransaction(void) ITM_REGPARM; + +typedef uint64_t _ITM_transactionId_t; /* Transaction identifier */ +#define _ITM_noTransactionId 1 /* Id for non-transactional code. */ + +extern _ITM_transactionId_t _ITM_getTransactionId(void) ITM_REGPARM; + +extern uint32_t _ITM_beginTransaction(uint32_t, ...) ITM_REGPARM; + +extern void _ITM_abortTransaction(_ITM_abortReason) ITM_REGPARM ITM_NORETURN; + +extern void _ITM_commitTransaction (void) ITM_REGPARM; + +extern void _ITM_changeTransactionMode (_ITM_transactionState) ITM_REGPARM; + +extern void _ITM_addUserCommitAction(_ITM_userCommitFunction, + _ITM_transactionId_t, void *) ITM_REGPARM; + +extern void _ITM_addUserUndoAction(_ITM_userUndoFunction, void *) ITM_REGPARM; + +extern int _ITM_getThreadnum(void) ITM_REGPARM; + +extern void _ITM_dropReferences (void *, size_t) ITM_REGPARM ITM_PURE; + +extern void *_ITM_malloc (size_t) + __attribute__((__malloc__)) ITM_PURE; + +extern void *_ITM_calloc (size_t, size_t) + __attribute__((__malloc__)) ITM_PURE; + +extern void _ITM_free (void *) ITM_PURE; + + +/* The following typedefs exist to make the macro expansions below work + properly. They are not part of any API. */ +typedef uint8_t _ITM_TYPE_U1; +typedef uint16_t _ITM_TYPE_U2; +typedef uint32_t _ITM_TYPE_U4; +typedef uint64_t _ITM_TYPE_U8; +typedef float _ITM_TYPE_F; +typedef double _ITM_TYPE_D; +typedef long double _ITM_TYPE_E; +typedef float _Complex _ITM_TYPE_CF; +typedef double _Complex _ITM_TYPE_CD; +typedef long double _Complex _ITM_TYPE_CE; + +#define ITM_BARRIERS(T) \ + extern _ITM_TYPE_##T _ITM_R##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RaR##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RaW##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RfW##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern void _ITM_W##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; \ + extern void _ITM_WaR##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; \ + extern void _ITM_WaW##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; + +ITM_BARRIERS(U1) +ITM_BARRIERS(U2) +ITM_BARRIERS(U4) +ITM_BARRIERS(U8) +ITM_BARRIERS(F) +ITM_BARRIERS(D) +ITM_BARRIERS(E) +ITM_BARRIERS(CF) +ITM_BARRIERS(CD) +ITM_BARRIERS(CE) + +#define ITM_LOG(T) \ + extern void _ITM_L##T (const _ITM_TYPE_##T *) ITM_REGPARM; + +ITM_LOG(U1) +ITM_LOG(U2) +ITM_LOG(U4) +ITM_LOG(U8) +ITM_LOG(F) +ITM_LOG(D) +ITM_LOG(E) +ITM_LOG(CF) +ITM_LOG(CD) +ITM_LOG(CE) + +#if defined(__i386__) || defined(__x86_64__) +# ifdef __MMX__ + typedef int _ITM_TYPE_M64 __attribute__((vector_size(8), may_alias)); + ITM_BARRIERS(M64) + ITM_LOG(M64) +# endif +# ifdef __SSE__ + typedef float _ITM_TYPE_M128 __attribute__((vector_size(16), may_alias)); + ITM_BARRIERS(M128) + ITM_LOG(M128) +# endif +# ifdef __AVX__ + typedef float _ITM_TYPE_M256 __attribute__((vector_size(32), may_alias)); + ITM_BARRIERS(M256) + ITM_LOG(M256) +# endif +#endif /* i386 */ + +#undef ITM_BARRIERS +#undef ITM_LOG + +extern void _ITM_LB (const void *, size_t) ITM_REGPARM; + +extern void _ITM_memcpyRnWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRnWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRnWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWtaW(void *, const void *, size_t) ITM_REGPARM; + +extern void _ITM_memmoveRnWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRnWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRnWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWtaW(void *, const void *, size_t) ITM_REGPARM; + +extern void _ITM_memsetW(void *, int, size_t) ITM_REGPARM; +extern void _ITM_memsetWaR(void *, int, size_t) ITM_REGPARM; +extern void _ITM_memsetWaW(void *, int, size_t) ITM_REGPARM; + +// ??? These are not yet in the official spec; still work-in-progress. + +extern void *_ITM_getTMCloneOrIrrevocable (void *) ITM_REGPARM; +extern void *_ITM_getTMCloneSafe (void *) ITM_REGPARM; +extern void _ITM_registerTMCloneTable (void *, size_t); +extern void _ITM_deregisterTMCloneTable (void *); + +extern void *_ITM_cxa_allocate_exception (size_t); +extern void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +extern void *_ITM_cxa_begin_catch (void *exc_ptr); +extern void _ITM_cxa_end_catch (void); +extern void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LIBITM_H */ Index: libitm/barrier.cc =================================================================== --- libitm/barrier.cc (.../trunk) (revision 0) +++ libitm/barrier.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,44 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +bool abi_dispatch::memmove_overlap_check(void *dst, const void *src, + size_t size, ls_modifier dst_mod, ls_modifier src_mod) +{ + if (dst_mod == NONTXNAL || src_mod == NONTXNAL) + { + if (((uintptr_t)dst <= (uintptr_t)src ? + (uintptr_t)dst + size > (uintptr_t)src : + (uintptr_t)src + size > (uintptr_t)dst)) + GTM::GTM_fatal("_ITM_memmove overlapping and t/nt is not allowed"); + return false; + } + return true; +} + +CREATE_DISPATCH_FUNCTIONS(GTM::abi_disp()->, ) + Index: libitm/alloc.cc =================================================================== --- libitm/alloc.cc (.../trunk) (revision 0) +++ libitm/alloc.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,129 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +void +gtm_thread::record_allocation (void *ptr, void (*free_fn)(void *)) +{ + uintptr_t iptr = (uintptr_t) ptr; + + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); + + a->free_fn = free_fn; + a->allocated = true; +} + +void +gtm_thread::forget_allocation (void *ptr, void (*free_fn)(void *)) +{ + uintptr_t iptr = (uintptr_t) ptr; + + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); + + a->free_fn = free_fn; + a->allocated = false; +} + +namespace { +struct commit_cb_data { + aa_tree* parent; + bool revert_p; +}; +} + +static void +commit_allocations_2 (uintptr_t key, gtm_alloc_action *a, void *data) +{ + void *ptr = (void *)key; + commit_cb_data *cb_data = static_cast(data); + + if (cb_data->revert_p) + { + // Roll back nested allocations. + if (a->allocated) + a->free_fn (ptr); + } + else + { + if (a->allocated) + { + // Add nested allocations to parent transaction. + gtm_alloc_action* a_parent = cb_data->parent->insert(key); + *a_parent = *a; + } + else + { + // ??? We could eliminate a parent allocation that matches this + // memory release, if we had support for removing all accesses + // to this allocation from the transaction's undo and redo logs + // (otherwise, the parent transaction's undo or redo might write to + // data that is already shared again because of calling free()). + // We don't have this support currently, and the benefit of this + // optimization is unknown, so just add it to the parent. + gtm_alloc_action* a_parent; + a_parent = cb_data->parent->insert(key); + *a_parent = *a; + } + } +} + +static void +commit_allocations_1 (uintptr_t key, gtm_alloc_action *a, void *cb_data) +{ + void *ptr = (void *)key; + uintptr_t revert_p = (uintptr_t) cb_data; + + if (a->allocated == revert_p) + a->free_fn (ptr); +} + +/* Permanently commit allocated memory during transaction. + + REVERT_P is true if instead of committing the allocations, we want + to roll them back (and vice versa). */ +void +gtm_thread::commit_allocations (bool revert_p, + aa_tree* parent) +{ + if (parent) + { + commit_cb_data cb_data; + cb_data.parent = parent; + cb_data.revert_p = revert_p; + this->alloc_actions.traverse (commit_allocations_2, &cb_data); + } + else + this->alloc_actions.traverse (commit_allocations_1, + (void *)(uintptr_t)revert_p); + this->alloc_actions.clear (); +} + +} // namespace GTM Index: libitm/configure.tgt =================================================================== --- libitm/configure.tgt (.../trunk) (revision 0) +++ libitm/configure.tgt (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,115 @@ +# -*- shell-script -*- +# This is the target specific configuration file. This is invoked by the +# autoconf generated configure script. Putting it in a separate shell file +# lets us skip running autoconf when modifying target specific information. + +# This file switches on the shell variable ${target}, and sets the +# following shell variables: +# config_path An ordered list of directories to search for +# sources and headers. This is relative to the +# config subdirectory of the source tree. +# XCFLAGS Add extra compile flags to use. +# XLDFLAGS Add extra link flags to use. + +# Optimize TLS usage by avoiding the overhead of dynamic allocation. +if test $gcc_cv_have_tls = yes ; then + case "${target}" in + + # For x86, we use slots in the TCB head for most of our TLS. + # The setup of those slots in beginTransaction can afford to + # use the global-dynamic model. + i[456]86-*-linux* | x86_64-*-linux*) + ;; + + *-*-linux*) + XCFLAGS="${XCFLAGS} -ftls-model=initial-exec" + ;; + esac +fi + +# Map the target cpu to an ARCH sub-directory. At the same time, +# work out any special compilation flags as necessary. +case "${target_cpu}" in + alpha*) ARCH=alpha ;; + ia64*) ARCH=ia64 ;; + mips*) ARCH=mips ;; + powerpc*) ARCH=powerpc ;; + s390*) ARCH=s390 ;; + + i[456]86) + case " ${CC} ${CFLAGS} " in + *" -m64 "*) + ;; + *) + if test -z "$with_arch"; then + XCFLAGS="${XCFLAGS} -march=i486 -mtune=${target_cpu}" + XCFLAGS="${XCFLAGS} -fomit-frame-pointer" + fi + esac + ARCH=x86 + ;; + + x86_64) + case " ${CC} ${CFLAGS} " in + *" -m32 "*) + XCFLAGS="${XCFLAGS} -march=i486 -mtune=i686" + XCFLAGS="${XCFLAGS} -fomit-frame-pointer" + ;; + esac + ARCH=x86 + ;; + + sparcv9 | sparc64) + # Note that sparcv7 and sparcv8 is not included here. We need cas. + echo "int i;" > conftestx.c + if ${CC} ${CFLAGS} -c -o conftestx.o conftestx.c > /dev/null 2>&1; then + case "`/usr/bin/file conftestx.o`" in + *32-bit*) + case " ${CC} ${CFLAGS}" in + *" -mcpu=ultrasparc"*) + ;; + *) + XCFLAGS="${XCFLAGS} -mcpu=v9" + ;; + esac + ;; + esac + fi + rm -f conftestx.c conftestx.o + ARCH=sparc + ;; + + *) + ARCH="${target_cpu}" + ;; +esac + +# Since we require POSIX threads, assume a POSIX system by default. +config_path="$ARCH posix generic" + +# Other system configury +case "${target}" in + *-*-linux*) + if test $enable_linux_futex = yes; then + config_path="linux/$ARCH linux $config_path" + fi + ;; + + *-*-hpux11*) + # HPUX v11.x requires -lrt to resolve sem_init in libgomp.la + XLDFLAGS="${XLDFLAGS} -lrt" + ;; + + *-*-mingw32*) + config_path="$ARCH mingw32 posix generic" + ;; + + *-*-solaris2.[56]*) + config_path="$ARCH posix95 posix generic" + XLDFLAGS="${XLDFLAGS} -lposix4" + ;; + + *-*-darwin*) + config_path="$ARCH bsd posix generic" + ;; +esac Index: libitm/libitm.spec.in =================================================================== --- libitm/libitm.spec.in (.../trunk) (revision 0) +++ libitm/libitm.spec.in (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,3 @@ +# This spec file is read by gcc when linking. It is used to specify the +# standard libraries we need in order to link with -fgnu-tm +*link_itm: @link_itm@ Index: libitm/memset.cc =================================================================== --- libitm/memset.cc (.../trunk) (revision 0) +++ libitm/memset.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,78 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +static void +do_memset(uintptr_t idst, int c, size_t size, abi_dispatch::lock_type W) +{ + abi_dispatch *disp = abi_disp(); + uintptr_t dofs = idst & (CACHELINE_SIZE - 1); + abi_dispatch::mask_pair dpair; + gtm_cacheline *dst + = reinterpret_cast(idst & -CACHELINE_SIZE); + + if (size == 0) + return; + + if (dofs != 0) + { + size_t dleft = CACHELINE_SIZE - dofs; + size_t min = (size <= dleft ? size : dleft); + + dpair = disp->write_lock(dst, W); + *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; + memset (&dpair.line->b[dofs], c, min); + dst++; + size -= min; + } + + while (size >= CACHELINE_SIZE) + { + dpair = disp->write_lock(dst, W); + *dpair.mask = -1; + memset (dpair.line, c, CACHELINE_SIZE); + dst++; + size -= CACHELINE_SIZE; + } + + if (size != 0) + { + dpair = disp->write_lock(dst, W); + *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; + memset (dpair.line, c, size); + } +} + +#define ITM_MEM_DEF(WRITE) \ +void ITM_REGPARM _ITM_memset##WRITE(void *dst, int c, size_t size) \ +{ \ + do_memset ((uintptr_t)dst, c, size, abi_dispatch::WRITE); \ +} + +ITM_MEM_DEF(W) +ITM_MEM_DEF(WaR) +ITM_MEM_DEF(WaW) Index: libitm/alloc_cpp.cc =================================================================== --- libitm/alloc_cpp.cc (.../trunk) (revision 0) +++ libitm/alloc_cpp.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,152 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +/* Mangling the names by hand requires that we know how size_t is handled. + We've gotten the letter from autoconf, now substitute it into the names. + Everything below uses X as a placeholder for clarity. */ + +#define S1(x,y) x##y +#define S(x,y) S1(x,y) + +#define _ZnwX S(_Znw,MANGLE_SIZE_T) +#define _ZnaX S(_Zna,MANGLE_SIZE_T) +#define _ZnwXRKSt9nothrow_t S(S(_Znw,MANGLE_SIZE_T),RKSt9nothrow_t) +#define _ZnaXRKSt9nothrow_t S(S(_Zna,MANGLE_SIZE_T),RKSt9nothrow_t) + +#define _ZGTtnwX S(_ZGTtnw,MANGLE_SIZE_T) +#define _ZGTtnaX S(_ZGTtna,MANGLE_SIZE_T) +#define _ZGTtnwXRKSt9nothrow_t S(S(_ZGTtnw,MANGLE_SIZE_T),RKSt9nothrow_t) +#define _ZGTtnaXRKSt9nothrow_t S(S(_ZGTtna,MANGLE_SIZE_T),RKSt9nothrow_t) + +/* Everything from libstdc++ is weak, to avoid requiring that library + to be linked into plain C applications using libitm.so. */ + +extern "C" { + +extern void *_ZnwX (size_t) __attribute__((weak)); +extern void _ZdlPv (void *) __attribute__((weak)); +extern void *_ZnaX (size_t) __attribute__((weak)); +extern void _ZdaPv (void *) __attribute__((weak)); + +typedef const struct nothrow_t { } *c_nothrow_p; + +extern void *_ZnwXRKSt9nothrow_t (size_t, c_nothrow_p) __attribute__((weak)); +extern void _ZdlPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak)); +extern void *_ZnaXRKSt9nothrow_t (size_t, c_nothrow_p) __attribute__((weak)); +extern void _ZdaPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak)); + +/* Wrap the delete nothrow symbols for usage with a single argument. + Perhaps should have a configure type check for this, because the + std::nothrow_t reference argument is unused (empty class), and most + targets don't actually need that second argument. So we _could_ + invoke these functions as if they were a single argument free. */ +static void +del_opnt (void *ptr) +{ + _ZdlPvRKSt9nothrow_t (ptr, NULL); +} + +static void +del_opvnt (void *ptr) +{ + _ZdaPvRKSt9nothrow_t (ptr, NULL); +} + +/* Wrap: operator new (std::size_t sz) */ +void * +_ZGTtnwX (size_t sz) +{ + void *r = _ZnwX (sz); + if (r) + gtm_thr()->record_allocation (r, _ZdlPv); + return r; +} + +/* Wrap: operator new (std::size_t sz, const std::nothrow_t&) */ +void * +_ZGTtnwXRKSt9nothrow_t (size_t sz, c_nothrow_p nt) +{ + void *r = _ZnwXRKSt9nothrow_t (sz, nt); + if (r) + gtm_thr()->record_allocation (r, del_opnt); + return r; +} + +/* Wrap: operator new[] (std::size_t sz) */ +void * +_ZGTtnaX (size_t sz) +{ + void *r = _ZnaX (sz); + if (r) + gtm_thr()->record_allocation (r, _ZdaPv); + return r; +} + +/* Wrap: operator new[] (std::size_t sz, const std::nothrow_t& nothrow) */ +void * +_ZGTtnaXRKSt9nothrow_t (size_t sz, c_nothrow_p nt) +{ + void *r = _ZnaXRKSt9nothrow_t (sz, nt); + if (r) + gtm_thr()->record_allocation (r, del_opvnt); + return r; +} + +/* Wrap: operator delete(void* ptr) */ +void +_ZGTtdlPv (void *ptr) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, _ZdlPv); +} + +/* Wrap: operator delete (void *ptr, const std::nothrow_t&) */ +void +_ZGTtdlPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, del_opnt); +} + +/* Wrap: operator delete[] (void *ptr) */ +void +_ZGTtdaPv (void *ptr) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, _ZdaPv); +} + +/* Wrap: operator delete[] (void *ptr, const std::nothrow_t&) */ +void +_ZGTtdaPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, del_opvnt); +} + +} // extern "C" Index: libitm/method-serial.cc =================================================================== --- libitm/method-serial.cc (.../trunk) (revision 0) +++ libitm/method-serial.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,285 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +// Avoid a dependency on libstdc++ for the pure virtuals in abi_dispatch. +extern "C" void HIDDEN +__cxa_pure_virtual () +{ + abort (); +} + +using namespace GTM; + +namespace { + +// This group consists of the serial, serialirr, and serialirr_onwrite +// methods, which all need no global state (except what is already provided +// by the serial mode implementation). +struct serial_mg : public method_group +{ + virtual void init() { } + virtual void fini() { } +}; + +static serial_mg o_serial_mg; + + +class serialirr_dispatch : public abi_dispatch +{ + public: + serialirr_dispatch() : abi_dispatch(false, true, true, false, &o_serial_mg) + { } + + protected: + serialirr_dispatch(bool ro, bool wt, bool uninstrumented, + bool closed_nesting, method_group* mg) : + abi_dispatch(ro, wt, uninstrumented, closed_nesting, mg) { } + + // Transactional loads and stores simply access memory directly. + // These methods are static to avoid indirect calls, and will be used by the + // virtual ABI dispatch methods or by static direct-access methods created + // below. + template static V load(const V* addr, ls_modifier mod) + { + return *addr; + } + template static void store(V* addr, const V value, + ls_modifier mod) + { + *addr = value; + } + + public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + if (!may_overlap) + ::memcpy(dst, src, size); + else + ::memmove(dst, src, size); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + ::memset(dst, c, size); + } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; } + virtual bool trycommit(gtm_word& priv_time) { return true; } + virtual void rollback(gtm_transaction_cp *cp) { abort(); } + + virtual abi_dispatch* closed_nesting_alternative() + { + // For nested transactions with an instrumented code path, we can do + // undo logging. + return GTM::dispatch_serial(); + } +}; + +class serial_dispatch : public abi_dispatch +{ +protected: + static void log(const void *addr, size_t len) + { + // TODO Ensure that this gets inlined: Use internal log interface and LTO. + GTM_LB(addr, len); + } + + template static V load(const V* addr, ls_modifier mod) + { + return *addr; + } + template static void store(V* addr, const V value, + ls_modifier mod) + { + if (mod != WaW) + log(addr, sizeof(V)); + *addr = value; + } + +public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + if (dst_mod != WaW && dst_mod != NONTXNAL) + log(dst, size); + if (!may_overlap) + ::memcpy(dst, src, size); + else + ::memmove(dst, src, size); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + if (mod != WaW) + log(dst, size); + ::memset(dst, c, size); + } + + virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; } + virtual bool trycommit(gtm_word& priv_time) { return true; } + // Local undo will handle this. + // trydropreference() need not be changed either. + virtual void rollback(gtm_transaction_cp *cp) { } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + serial_dispatch() : abi_dispatch(false, true, false, true, &o_serial_mg) { } +}; + + +// Like serialirr_dispatch but does not requests serial-irrevocable mode until +// the first write in the transaction. Can be useful for read-mostly workloads +// and testing, but is likely too simple to be of general purpose. +class serialirr_onwrite_dispatch : public serialirr_dispatch +{ + public: + serialirr_onwrite_dispatch() : + serialirr_dispatch(false, true, false, false, &o_serial_mg) { } + + protected: + static void pre_write() + { + gtm_thread *tx = gtm_thr(); + if (!(tx->state & (gtm_thread::STATE_SERIAL + | gtm_thread::STATE_IRREVOCABLE))) + tx->serialirr_mode(); + } + + // Transactional loads access memory directly. + // Transactional stores switch to serial mode first. + template static void store(V* addr, const V value, + ls_modifier mod) + { + pre_write(); + serialirr_dispatch::store(addr, value, mod); + } + + public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + pre_write(); + serialirr_dispatch::memtransfer_static(dst, src, size, may_overlap, + dst_mod, src_mod); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + pre_write(); + serialirr_dispatch::memset_static(dst, c, size, mod); + } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + virtual void rollback(gtm_transaction_cp *cp) + { + gtm_thread *tx = gtm_thr(); + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + abort(); + } +}; + +} // anon namespace + +static const serialirr_dispatch o_serialirr_dispatch; +static const serial_dispatch o_serial_dispatch; +static const serialirr_onwrite_dispatch o_serialirr_onwrite_dispatch; + +abi_dispatch * +GTM::dispatch_serialirr () +{ + return const_cast(&o_serialirr_dispatch); +} + +abi_dispatch * +GTM::dispatch_serial () +{ + return const_cast(&o_serial_dispatch); +} + +abi_dispatch * +GTM::dispatch_serialirr_onwrite () +{ + return + const_cast(&o_serialirr_onwrite_dispatch); +} + +// Put the transaction into serial-irrevocable mode. + +void +GTM::gtm_thread::serialirr_mode () +{ + struct abi_dispatch *disp = abi_disp (); + bool need_restart = true; + + if (this->state & STATE_SERIAL) + { + if (this->state & STATE_IRREVOCABLE) + return; + + // Try to commit the dispatch-specific part of the transaction, as we + // would do for an outermost commit. + // We're already serial, so we don't need to ensure privatization safety + // for other transactions here. + gtm_word priv_time = 0; + bool ok = disp->trycommit (priv_time); + // Given that we're already serial, the trycommit better work. + assert (ok); + need_restart = false; + } + else if (serial_lock.write_upgrade (this)) + { + this->state |= STATE_SERIAL; + // Try to commit the dispatch-specific part of the transaction, as we + // would do for an outermost commit. + // We have successfully upgraded to serial mode, so we don't need to + // ensure privatization safety for other transactions here. + gtm_word priv_time = 0; + if (disp->trycommit (priv_time)) + need_restart = false; + } + + if (need_restart) + restart (RESTART_SERIAL_IRR); + else + { + this->state |= (STATE_SERIAL | STATE_IRREVOCABLE); + set_abi_disp (dispatch_serialirr ()); + } +} + +void ITM_REGPARM +_ITM_changeTransactionMode (_ITM_transactionState state) +{ + assert (state == modeSerialIrrevocable); + gtm_thr()->serialirr_mode (); +} Index: libitm/eh_cpp.cc =================================================================== --- libitm/eh_cpp.cc (.../trunk) (revision 0) +++ libitm/eh_cpp.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,108 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +/* Everything from libstdc++ is weak, to avoid requiring that library + to be linked into plain C applications using libitm.so. */ + +#define WEAK __attribute__((weak)) + +extern "C" { + +extern void *__cxa_allocate_exception (size_t) WEAK; +extern void __cxa_throw (void *, void *, void *) WEAK; +extern void *__cxa_begin_catch (void *) WEAK; +extern void *__cxa_end_catch (void) WEAK; +extern void __cxa_tm_cleanup (void *, void *, unsigned int) WEAK; + +} + + +void * +_ITM_cxa_allocate_exception (size_t size) +{ + void *r = __cxa_allocate_exception (size); + gtm_thr()->cxa_unthrown = r; + return r; +} + +void +_ITM_cxa_throw (void *obj, void *tinfo, void *dest) +{ + gtm_thr()->cxa_unthrown = NULL; + __cxa_throw (obj, tinfo, dest); +} + +void * +_ITM_cxa_begin_catch (void *exc_ptr) +{ + gtm_thr()->cxa_catch_count++; + return __cxa_begin_catch (exc_ptr); +} + +void +_ITM_cxa_end_catch (void) +{ + gtm_thr()->cxa_catch_count--; + __cxa_end_catch (); +} + +void +GTM::gtm_thread::revert_cpp_exceptions (gtm_transaction_cp *cp) +{ + if (cp) + { + // If rolling back a nested transaction, only clean up unthrown + // exceptions since the last checkpoint. Always reset eh_in_flight + // because it just contains the argument provided to + // _ITM_commitTransactionEH + void *unthrown = + (cxa_unthrown != cp->cxa_unthrown ? cxa_unthrown : NULL); + assert (cxa_catch_count >= cp->cxa_catch_count); + uint32_t catch_count = cxa_catch_count - cp->cxa_catch_count; + if (unthrown || catch_count) + { + __cxa_tm_cleanup (unthrown, this->eh_in_flight, catch_count); + cxa_catch_count = cp->cxa_catch_count; + cxa_unthrown = cp->cxa_unthrown; + this->eh_in_flight = NULL; + } + } + else + { + // Both cxa_catch_count and cxa_unthrown are maximal because EH regions + // and transactions are properly nested. + if (this->cxa_unthrown || this->cxa_catch_count) + { + __cxa_tm_cleanup (this->cxa_unthrown, this->eh_in_flight, + this->cxa_catch_count); + this->cxa_catch_count = 0; + this->cxa_unthrown = NULL; + this->eh_in_flight = NULL; + } + } +} Index: libitm/barrier.tpl =================================================================== --- libitm/barrier.tpl (.../trunk) (revision 0) +++ libitm/barrier.tpl (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,170 @@ +/* -*- c++ -*- */ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "unaligned.h" + +namespace { + +using namespace GTM; + +template +T do_read (const T *ptr, abi_dispatch::lock_type lock) +{ + // + // Find the cacheline that holds the current value of *PTR. + // + abi_dispatch *disp = abi_disp(); + uintptr_t iptr = reinterpret_cast(ptr); + // Normalize PTR by chopping off the bottom bits so we can search + // for PTR in the cacheline hash. + uintptr_t iline = iptr & -CACHELINE_SIZE; + // The position in the resulting cacheline where *PTR is actually stored. + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + const gtm_cacheline *pline = reinterpret_cast(iline); + // Search for the actual cacheline that holds the current value of *PTR. + const gtm_cacheline *line = disp->read_lock(pline, lock); + + // Point to the position in the cacheline where *PTR is stored. + ptr = reinterpret_cast(&line->b[iofs]); + + // Straight up loads, because we're either aligned, or we don't care + // about alignment. + // + // If we require alignment on type T, do a straight load if we're + // aligned. Otherwise do a straight load IFF the load fits entirely + // in this cacheline. That is, it won't span multiple cachelines. + if (__builtin_expect (strict_alignment::value + ? (iofs & (sizeof (T) - 1)) == 0 + : iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_normal_load: + return *ptr; + } + // If alignment on T is necessary, but we're unaligned, yet we fit + // entirely in this cacheline... do the unaligned load dance. + else if (__builtin_expect (strict_alignment::value + && iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_unaligned_load: + return unaligned_load(ptr); + } + // Otherwise, this load will span multiple cachelines. + else + { + // Get the following cacheline for the rest of the data. + const gtm_cacheline *line2 = disp->read_lock(pline + 1, lock); + + // If the two cachelines are adjacent, just load it all in one + // swoop. + if (line2 == line + 1) + { + if (!strict_alignment::value) + goto do_normal_load; + else + goto do_unaligned_load; + } + else + { + // Otherwise, ask the backend to load from two different + // cachelines. + return unaligned_load2(line, line2, iofs); + } + } +} + +template +void do_write (T *ptr, T val, abi_dispatch::lock_type lock) +{ + // Note: See comments for do_read() above for hints on this + // function. Ideally we should abstract out a lot out of these two + // functions, and avoid all this duplication. + + abi_dispatch *disp = abi_disp(); + uintptr_t iptr = reinterpret_cast(ptr); + uintptr_t iline = iptr & -CACHELINE_SIZE; + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + gtm_cacheline *pline = reinterpret_cast(iline); + gtm_cacheline_mask m = ((gtm_cacheline_mask)2 << (sizeof(T) - 1)) - 1; + abi_dispatch::mask_pair pair = disp->write_lock(pline, lock); + + ptr = reinterpret_cast(&pair.line->b[iofs]); + + if (__builtin_expect (strict_alignment::value + ? (iofs & (sizeof (val) - 1)) == 0 + : iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_normal_store: + *ptr = val; + } + else if (__builtin_expect (strict_alignment::value + && iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_unaligned_store: + unaligned_store(ptr, val); + } + else + { + *pair.mask |= m << iofs; + abi_dispatch::mask_pair pair2 = disp->write_lock(pline + 1, lock); + + uintptr_t ileft = CACHELINE_SIZE - iofs; + *pair2.mask |= m >> ileft; + + if (pair2.line == pair.line + 1) + { + if (!strict_alignment::value) + goto do_normal_store; + else + goto do_unaligned_store; + } + else + unaligned_store2(pair.line, pair2.line, iofs, val); + } +} + +} /* anonymous namespace */ + +#define ITM_READ(T, LOCK) \ + _ITM_TYPE_##T ITM_REGPARM _ITM_##LOCK##T (const _ITM_TYPE_##T *ptr) \ + { \ + return do_read (ptr, abi_dispatch::LOCK); \ + } + +#define ITM_WRITE(T, LOCK) \ + void ITM_REGPARM _ITM_##LOCK##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \ + { \ + do_write (ptr, val, abi_dispatch::LOCK); \ + } + +#define ITM_BARRIERS(T) \ + ITM_READ(T, R) \ + ITM_READ(T, RaR) \ + ITM_READ(T, RaW) \ + ITM_READ(T, RfW) \ + ITM_WRITE(T, W) \ + ITM_WRITE(T, WaR) \ + ITM_WRITE(T, WaW) Index: libitm/retry.cc =================================================================== --- libitm/retry.cc (.../trunk) (revision 0) +++ libitm/retry.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,265 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include +#include +#include +#include "libitm_i.h" + +// The default TM method used when starting a new transaction. +static GTM::abi_dispatch* default_dispatch = 0; +// The default TM method as requested by the user, if any. +static GTM::abi_dispatch* default_dispatch_user = 0; + +void +GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r) +{ + struct abi_dispatch *disp = abi_disp (); + + this->restart_reason[r]++; + this->restart_total++; + + if (r == RESTART_INIT_METHOD_GROUP) + { + // A re-initializations of the method group has been requested. Switch + // to serial mode, initialize, and resume normal operation. + if ((state & STATE_SERIAL) == 0) + { + // We have to eventually re-init the method group. Therefore, + // we cannot just upgrade to a write lock here because this could + // fail forever when other transactions execute in serial mode. + // However, giving up the read lock then means that a change of the + // method group could happen in-between, so check that we're not + // re-initializing without a need. + // ??? Note that we can still re-initialize too often, but avoiding + // that would increase code complexity, which seems unnecessary + // given that re-inits should be very infrequent. + serial_lock.read_unlock(this); + serial_lock.write_lock(); + if (disp->get_method_group() == default_dispatch->get_method_group()) + { + // Still the same method group. + disp->get_method_group()->fini(); + disp->get_method_group()->init(); + } + serial_lock.write_unlock(); + serial_lock.read_lock(this); + if (disp->get_method_group() != default_dispatch->get_method_group()) + { + disp = default_dispatch; + set_abi_disp(disp); + } + } + else + { + // We are a serial transaction already, which makes things simple. + disp->get_method_group()->fini(); + disp->get_method_group()->init(); + } + } + + bool retry_irr = (r == RESTART_SERIAL_IRR); + bool retry_serial = (retry_irr || this->restart_total > 100); + + // We assume closed nesting to be infrequently required, so just use + // dispatch_serial (with undo logging) if required. + if (r == RESTART_CLOSED_NESTING) + retry_serial = true; + + if (retry_serial) + { + // In serialirr_mode we can succeed with the upgrade to + // write-lock but fail the trycommit. In any case, if the + // write lock is not yet held, grab it. Don't do this with + // an upgrade, since we've no need to preserve the state we + // acquired with the read. + // Note that we will be restarting with either dispatch_serial or + // dispatch_serialirr, which are compatible with all TM methods; if + // we would retry with a different method, we would have to first check + // whether the default dispatch or the method group have changed. Also, + // the caller must have rolled back the previous transaction, so we + // don't have to worry about things such as privatization. + if ((this->state & STATE_SERIAL) == 0) + { + this->state |= STATE_SERIAL; + serial_lock.read_unlock (this); + serial_lock.write_lock (); + } + + // We can retry with dispatch_serialirr if the transaction + // doesn't contain an abort and if we don't need closed nesting. + if ((this->prop & pr_hasNoAbort) && (r != RESTART_CLOSED_NESTING)) + retry_irr = true; + } + + // Note that we can just use serial mode here without having to switch + // TM method sets because serial mode is compatible with all of them. + if (retry_irr) + { + this->state = (STATE_SERIAL | STATE_IRREVOCABLE); + disp = dispatch_serialirr (); + set_abi_disp (disp); + } + else if (retry_serial) + { + disp = dispatch_serial(); + set_abi_disp (disp); + } +} + + +// Decides which TM method should be used on the first attempt to run this +// transaction. +GTM::abi_dispatch* +GTM::gtm_thread::decide_begin_dispatch (uint32_t prop) +{ + // TODO Pay more attention to prop flags (eg, *omitted) when selecting + // dispatch. + if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode)) + return dispatch_serialirr(); + + // If we might need closed nesting and the default dispatch has an + // alternative that supports closed nesting, use it. + // ??? We could choose another TM method that we know supports closed + // nesting but isn't the default (e.g., dispatch_serial()). However, we + // assume that aborts that need closed nesting are infrequent, so don't + // choose a non-default method until we have to actually restart the + // transaction. + if (!(prop & pr_hasNoAbort) && !default_dispatch->closed_nesting() + && default_dispatch->closed_nesting_alternative()) + return default_dispatch->closed_nesting_alternative(); + + // No special case, just use the default dispatch. + return default_dispatch; +} + + +void +GTM::gtm_thread::set_default_dispatch(GTM::abi_dispatch* disp) +{ + if (default_dispatch == disp) + return; + if (default_dispatch) + { + // If we are switching method groups, initialize and shut down properly. + if (default_dispatch->get_method_group() != disp->get_method_group()) + { + default_dispatch->get_method_group()->fini(); + disp->get_method_group()->init(); + } + } + else + disp->get_method_group()->init(); + default_dispatch = disp; +} + + +static GTM::abi_dispatch* +parse_default_method() +{ + const char *env = getenv("ITM_DEFAULT_METHOD"); + GTM::abi_dispatch* disp = 0; + if (env == NULL) + return 0; + + while (isspace((unsigned char) *env)) + ++env; + if (strncmp(env, "serialirr_onwrite", 17) == 0) + { + disp = GTM::dispatch_serialirr_onwrite(); + env += 17; + } + else if (strncmp(env, "serialirr", 9) == 0) + { + disp = GTM::dispatch_serialirr(); + env += 9; + } + else if (strncmp(env, "serial", 6) == 0) + { + disp = GTM::dispatch_serial(); + env += 6; + } + else if (strncmp(env, "gl_wt", 5) == 0) + { + disp = GTM::dispatch_gl_wt(); + env += 5; + } + else + goto unknown; + + while (isspace((unsigned char) *env)) + ++env; + if (*env == '\0') + return disp; + + unknown: + GTM::GTM_error("Unknown TM method in environment variable " + "ITM_DEFAULT_METHOD\n"); + return 0; +} + +// Gets notifications when the number of registered threads changes. This is +// used to initialize the method set choice and trigger straightforward choice +// adaption. +// This must be called only by serial threads. +void +GTM::gtm_thread::number_of_threads_changed(unsigned previous, unsigned now) +{ + if (previous == 0) + { + // No registered threads before, so initialize. + static bool initialized = false; + if (!initialized) + { + initialized = true; + // Check for user preferences here. + default_dispatch_user = parse_default_method(); + } + } + else if (now == 0) + { + // No registered threads anymore. The dispatch based on serial mode do + // not have any global state, so this effectively shuts down properly. + set_default_dispatch(dispatch_serialirr()); + } + + if (now == 1) + { + // Only one thread, so use a serializing method. + // ??? If we don't have a fast serial mode implementation, it might be + // better to use the global lock method set here. + if (default_dispatch_user) + set_default_dispatch(default_dispatch_user); + else + set_default_dispatch(dispatch_serialirr()); + } + else if (now > 1 && previous <= 1) + { + // More than one thread, use the default method. + if (default_dispatch_user) + set_default_dispatch(default_dispatch_user); + else + set_default_dispatch(dispatch_serialirr_onwrite()); + } +} Index: libitm/query.cc =================================================================== --- libitm/query.cc (.../trunk) (revision 0) +++ libitm/query.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,70 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +int ITM_REGPARM +_ITM_versionCompatible (int version) +{ + return version == _ITM_VERSION_NO; +} + + +const char * ITM_REGPARM +_ITM_libraryVersion (void) +{ + return "GNU libitm " _ITM_VERSION; +} + + +_ITM_howExecuting ITM_REGPARM +_ITM_inTransaction (void) +{ + struct gtm_thread *tx = gtm_thr(); + if (tx && (tx->nesting > 0)) + { + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + return inIrrevocableTransaction; + else + return inRetryableTransaction; + } + return outsideTransaction; +} + + +_ITM_transactionId_t ITM_REGPARM +_ITM_getTransactionId (void) +{ + struct gtm_thread *tx = gtm_thr(); + return (tx && (tx->nesting > 0)) ? tx->id : _ITM_noTransactionId; +} + + +void ITM_REGPARM ITM_NORETURN +_ITM_error (const _ITM_srcLocation * loc UNUSED, int errorCode UNUSED) +{ + abort (); +} Index: libitm/beginend.cc =================================================================== --- libitm/beginend.cc (.../trunk) (revision 0) +++ libitm/beginend.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,536 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include + + +using namespace GTM; + +#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP) +extern __thread gtm_thread_tls _gtm_thr_tls; +#endif + +gtm_rwlock GTM::gtm_thread::serial_lock; +gtm_thread *GTM::gtm_thread::list_of_threads = 0; +unsigned GTM::gtm_thread::number_of_threads = 0; + +gtm_stmlock GTM::gtm_stmlock_array[LOCK_ARRAY_SIZE]; +gtm_version GTM::gtm_clock; + +/* ??? Move elsewhere when we figure out library initialization. */ +uint64_t GTM::gtm_spin_count_var = 1000; + +static _ITM_transactionId_t global_tid; + +// Provides a on-thread-exit callback used to release per-thread data. +static pthread_key_t thr_release_key; +static pthread_once_t thr_release_once = PTHREAD_ONCE_INIT; + + +/* Allocate a transaction structure. */ +void * +GTM::gtm_thread::operator new (size_t s) +{ + void *tx; + + assert(s == sizeof(gtm_thread)); + + tx = xmalloc (sizeof (gtm_thread), true); + memset (tx, 0, sizeof (gtm_thread)); + + return tx; +} + +/* Free the given transaction. Raises an error if the transaction is still + in use. */ +void +GTM::gtm_thread::operator delete(void *tx) +{ + free(tx); +} + +static void +thread_exit_handler(void *) +{ + gtm_thread *thr = gtm_thr(); + if (thr) + delete thr; + set_gtm_thr(0); +} + +static void +thread_exit_init() +{ + if (pthread_key_create(&thr_release_key, thread_exit_handler)) + GTM_fatal("Creating thread release TLS key failed."); +} + + +GTM::gtm_thread::~gtm_thread() +{ + if (nesting > 0) + GTM_fatal("Thread exit while a transaction is still active."); + + // Deregister this transaction. + serial_lock.write_lock (); + gtm_thread **prev = &list_of_threads; + for (; *prev; prev = &(*prev)->next_thread) + { + if (*prev == this) + { + *prev = (*prev)->next_thread; + break; + } + } + number_of_threads--; + number_of_threads_changed(number_of_threads + 1, number_of_threads); + serial_lock.write_unlock (); +} + +GTM::gtm_thread::gtm_thread () +{ + // This object's memory has been set to zero by operator new, so no need + // to initialize any of the other primitive-type members that do not have + // constructors. + shared_state = ~(typeof shared_state)0; + + // Register this transaction with the list of all threads' transactions. + serial_lock.write_lock (); + next_thread = list_of_threads; + list_of_threads = this; + number_of_threads++; + number_of_threads_changed(number_of_threads - 1, number_of_threads); + serial_lock.write_unlock (); + + if (pthread_once(&thr_release_once, thread_exit_init)) + GTM_fatal("Initializing thread release TLS key failed."); + // Any non-null value is sufficient to trigger destruction of this + // transaction when the current thread terminates. + if (pthread_setspecific(thr_release_key, this)) + GTM_fatal("Setting thread release TLS key failed."); +} + + + +#ifndef HAVE_64BIT_SYNC_BUILTINS +static pthread_mutex_t global_tid_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +static inline uint32_t choose_code_path(uint32_t prop, abi_dispatch *disp) +{ + if ((prop & pr_uninstrumentedCode) && disp->can_run_uninstrumented_code()) + return a_runUninstrumentedCode; + else + return a_runInstrumentedCode; +} + +uint32_t +GTM::gtm_thread::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb) +{ + static const _ITM_transactionId_t tid_block_size = 1 << 16; + + gtm_thread *tx; + abi_dispatch *disp; + uint32_t ret; + + // ??? pr_undoLogCode is not properly defined in the ABI. Are barriers + // omitted because they are not necessary (e.g., a transaction on thread- + // local data) or because the compiler thinks that some kind of global + // synchronization might perform better? + if (unlikely(prop & pr_undoLogCode)) + GTM_fatal("pr_undoLogCode not supported"); + + tx = gtm_thr(); + if (unlikely(tx == NULL)) + { + // Create the thread object. The constructor will also set up automatic + // deletion on thread termination. + tx = new gtm_thread(); + set_gtm_thr(tx); + } + + if (tx->nesting > 0) + { + // This is a nested transaction. + // Check prop compatibility: + // The ABI requires pr_hasNoFloatUpdate, pr_hasNoVectorUpdate, + // pr_hasNoIrrevocable, pr_aWBarriersOmitted, pr_RaRBarriersOmitted, and + // pr_hasNoSimpleReads to hold for the full dynamic scope of a + // transaction. We could check that these are set for the nested + // transaction if they are also set for the parent transaction, but the + // ABI does not require these flags to be set if they could be set, + // so the check could be too strict. + // ??? For pr_readOnly, lexical or dynamic scope is unspecified. + + if (prop & pr_hasNoAbort) + { + // We can use flat nesting, so elide this transaction. + if (!(prop & pr_instrumentedCode)) + { + if (!(tx->state & STATE_SERIAL) || + !(tx->state & STATE_IRREVOCABLE)) + tx->serialirr_mode(); + } + // Increment nesting level after checking that we have a method that + // allows us to continue. + tx->nesting++; + return choose_code_path(prop, abi_disp()); + } + + // The transaction might abort, so use closed nesting if possible. + // pr_hasNoAbort has lexical scope, so the compiler should really have + // generated an instrumented code path. + assert(prop & pr_instrumentedCode); + + // Create a checkpoint of the current transaction. + gtm_transaction_cp *cp = tx->parent_txns.push(); + cp->save(tx); + new (&tx->alloc_actions) aa_tree(); + + // Check whether the current method actually supports closed nesting. + // If we can switch to another one, do so. + // If not, we assume that actual aborts are infrequent, and rather + // restart in _ITM_abortTransaction when we really have to. + disp = abi_disp(); + if (!disp->closed_nesting()) + { + // ??? Should we elide the transaction if there is no alternative + // method that supports closed nesting? If we do, we need to set + // some flag to prevent _ITM_abortTransaction from aborting the + // wrong transaction (i.e., some parent transaction). + abi_dispatch *cn_disp = disp->closed_nesting_alternative(); + if (cn_disp) + { + disp = cn_disp; + set_abi_disp(disp); + } + } + } + else + { + // Outermost transaction + disp = tx->decide_begin_dispatch (prop); + if (disp == dispatch_serialirr() || disp == dispatch_serial()) + { + tx->state = STATE_SERIAL; + if (disp == dispatch_serialirr()) + tx->state |= STATE_IRREVOCABLE; + serial_lock.write_lock (); + } + else + serial_lock.read_lock (tx); + + set_abi_disp (disp); + } + + // Initialization that is common for outermost and nested transactions. + tx->prop = prop; + tx->nesting++; + + tx->jb = *jb; + + // As long as we have not exhausted a previously allocated block of TIDs, + // we can avoid an atomic operation on a shared cacheline. + if (tx->local_tid & (tid_block_size - 1)) + tx->id = tx->local_tid++; + else + { +#ifdef HAVE_64BIT_SYNC_BUILTINS + tx->id = __sync_add_and_fetch (&global_tid, tid_block_size); + tx->local_tid = tx->id + 1; +#else + pthread_mutex_lock (&global_tid_lock); + global_tid += tid_block_size; + tx->id = global_tid; + tx->local_tid = tx->id + 1; + pthread_mutex_unlock (&global_tid_lock); +#endif + } + + // Run dispatch-specific restart code. Retry until we succeed. + GTM::gtm_restart_reason rr; + while ((rr = disp->begin_or_restart()) != NO_RESTART) + { + tx->decide_retry_strategy(rr); + disp = abi_disp(); + } + + // Determine the code path to run. Only irrevocable transactions cannot be + // restarted, so all other transactions need to save live variables. + ret = choose_code_path(prop, disp); + if (!(tx->state & STATE_IRREVOCABLE)) + ret |= a_saveLiveVariables; + return ret; +} + + +void +GTM::gtm_transaction_cp::save(gtm_thread* tx) +{ + // Save everything that we might have to restore on restarts or aborts. + jb = tx->jb; + undolog_size = tx->undolog.size(); + memcpy(&alloc_actions, &tx->alloc_actions, sizeof(alloc_actions)); + user_actions_size = tx->user_actions.size(); + id = tx->id; + prop = tx->prop; + cxa_catch_count = tx->cxa_catch_count; + cxa_unthrown = tx->cxa_unthrown; + disp = abi_disp(); + nesting = tx->nesting; +} + +void +GTM::gtm_transaction_cp::commit(gtm_thread* tx) +{ + // Restore state that is not persistent across commits. Exception handling, + // information, nesting level, and any logs do not need to be restored on + // commits of nested transactions. Allocation actions must be committed + // before committing the snapshot. + tx->jb = jb; + memcpy(&tx->alloc_actions, &alloc_actions, sizeof(alloc_actions)); + tx->id = id; + tx->prop = prop; +} + + +void +GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool aborting) +{ + // The undo log is special in that it used for both thread-local and shared + // data. Because of the latter, we have to roll it back before any + // dispatch-specific rollback (which handles synchronization with other + // transactions). + rollback_undolog (cp ? cp->undolog_size : 0); + + // Perform dispatch-specific rollback. + abi_disp()->rollback (cp); + + // Roll back all actions that are supposed to happen around the transaction. + rollback_user_actions (cp ? cp->user_actions_size : 0); + commit_allocations (true, (cp ? &cp->alloc_actions : 0)); + revert_cpp_exceptions (cp); + + if (cp) + { + // We do not yet handle restarts of nested transactions. To do that, we + // would have to restore some state (jb, id, prop, nesting) not to the + // checkpoint but to the transaction that was started from this + // checkpoint (e.g., nesting = cp->nesting + 1); + assert(aborting); + // Roll back the rest of the state to the checkpoint. + jb = cp->jb; + id = cp->id; + prop = cp->prop; + if (cp->disp != abi_disp()) + set_abi_disp(cp->disp); + memcpy(&alloc_actions, &cp->alloc_actions, sizeof(alloc_actions)); + nesting = cp->nesting; + } + else + { + // Roll back to the outermost transaction. + // Restore the jump buffer and transaction properties, which we will + // need for the longjmp used to restart or abort the transaction. + if (parent_txns.size() > 0) + { + jb = parent_txns[0].jb; + id = parent_txns[0].id; + prop = parent_txns[0].prop; + } + // Reset the transaction. Do not reset this->state, which is handled by + // the callers. Note that if we are not aborting, we reset the + // transaction to the point after having executed begin_transaction + // (we will return from it), so the nesting level must be one, not zero. + nesting = (aborting ? 0 : 1); + parent_txns.clear(); + } + + if (this->eh_in_flight) + { + _Unwind_DeleteException ((_Unwind_Exception *) this->eh_in_flight); + this->eh_in_flight = NULL; + } +} + +void ITM_REGPARM +_ITM_abortTransaction (_ITM_abortReason reason) +{ + gtm_thread *tx = gtm_thr(); + + assert (reason == userAbort || reason == (userAbort | outerAbort)); + assert ((tx->prop & pr_hasNoAbort) == 0); + + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + abort (); + + // Roll back to innermost transaction. + if (tx->parent_txns.size() > 0 && !(reason & outerAbort)) + { + // If the current method does not support closed nesting but we are + // nested and must only roll back the innermost transaction, then + // restart with a method that supports closed nesting. + abi_dispatch *disp = abi_disp(); + if (!disp->closed_nesting()) + tx->restart(RESTART_CLOSED_NESTING); + + // The innermost transaction is a closed nested transaction. + gtm_transaction_cp *cp = tx->parent_txns.pop(); + uint32_t longjmp_prop = tx->prop; + gtm_jmpbuf longjmp_jb = tx->jb; + + tx->rollback (cp, true); + + // Jump to nested transaction (use the saved jump buffer). + GTM_longjmp (&longjmp_jb, a_abortTransaction | a_restoreLiveVariables, + longjmp_prop); + } + else + { + // There is no nested transaction or an abort of the outermost + // transaction was requested, so roll back to the outermost transaction. + tx->rollback (0, true); + + // Aborting an outermost transaction finishes execution of the whole + // transaction. Therefore, reset transaction state. + if (tx->state & gtm_thread::STATE_SERIAL) + gtm_thread::serial_lock.write_unlock (); + else + gtm_thread::serial_lock.read_unlock (tx); + tx->state = 0; + + GTM_longjmp (&tx->jb, a_abortTransaction | a_restoreLiveVariables, + tx->prop); + } +} + +bool +GTM::gtm_thread::trycommit () +{ + nesting--; + + // Skip any real commit for elided transactions. + if (nesting > 0 && (parent_txns.size() == 0 || + nesting > parent_txns[parent_txns.size() - 1].nesting)) + return true; + + if (nesting > 0) + { + // Commit of a closed-nested transaction. Remove one checkpoint and add + // any effects of this transaction to the parent transaction. + gtm_transaction_cp *cp = parent_txns.pop(); + commit_allocations(false, &cp->alloc_actions); + cp->commit(this); + return true; + } + + // Commit of an outermost transaction. + gtm_word priv_time = 0; + if (abi_disp()->trycommit (priv_time)) + { + // The transaction is now inactive. Everything that we still have to do + // will not synchronize with other transactions anymore. + if (state & gtm_thread::STATE_SERIAL) + gtm_thread::serial_lock.write_unlock (); + else + gtm_thread::serial_lock.read_unlock (this); + state = 0; + + // We can commit the undo log after dispatch-specific commit and after + // making the transaction inactive because we only have to reset + // gtm_thread state. + commit_undolog (); + // Reset further transaction state. + cxa_catch_count = 0; + cxa_unthrown = NULL; + restart_total = 0; + + // Ensure privatization safety, if necessary. + if (priv_time) + { + // TODO Don't just spin but also block using cond vars / futexes + // here. Should probably be integrated with the serial lock code. + // TODO For C++0x atomics, the loads of other threads' shared_state + // should have acquire semantics (together with releases for the + // respective updates). But is this unnecessary overhead because + // weaker barriers are sufficient? + for (gtm_thread *it = gtm_thread::list_of_threads; it != 0; + it = it->next_thread) + { + if (it == this) continue; + while (it->shared_state < priv_time) + cpu_relax(); + } + } + + // After ensuring privatization safety, we execute potentially + // privatizing actions (e.g., calling free()). User actions are first. + commit_user_actions (); + commit_allocations (false, 0); + + return true; + } + return false; +} + +void ITM_NORETURN +GTM::gtm_thread::restart (gtm_restart_reason r) +{ + // Roll back to outermost transaction. Do not reset transaction state because + // we will continue executing this transaction. + rollback (); + decide_retry_strategy (r); + + // Run dispatch-specific restart code. Retry until we succeed. + abi_dispatch* disp = abi_disp(); + GTM::gtm_restart_reason rr; + while ((rr = disp->begin_or_restart()) != NO_RESTART) + { + decide_retry_strategy(rr); + disp = abi_disp(); + } + + GTM_longjmp (&jb, + choose_code_path(prop, disp) | a_restoreLiveVariables, prop); +} + +void ITM_REGPARM +_ITM_commitTransaction(void) +{ + gtm_thread *tx = gtm_thr(); + if (!tx->trycommit ()) + tx->restart (RESTART_VALIDATE_COMMIT); +} + +void ITM_REGPARM +_ITM_commitTransactionEH(void *exc_ptr) +{ + gtm_thread *tx = gtm_thr(); + if (!tx->trycommit ()) + { + tx->eh_in_flight = exc_ptr; + tx->restart (RESTART_VALIDATE_COMMIT); + } +} Index: libitm/useraction.cc =================================================================== --- libitm/useraction.cc (.../trunk) (revision 0) +++ libitm/useraction.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,81 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +void +gtm_thread::rollback_user_actions(size_t until_size) +{ + for (size_t s = user_actions.size(); s > until_size; s--) + { + user_action *a = user_actions.pop(); + if (!a->on_commit) + a->fn (a->arg); + } +} + + +void +gtm_thread::commit_user_actions() +{ + for (vector::iterator i = user_actions.begin(), + ie = user_actions.end(); i != ie; i++) + { + if (i->on_commit) + i->fn (i->arg); + } + user_actions.clear(); +} + +} // namespace GTM + +using namespace GTM; + +void ITM_REGPARM +_ITM_addUserCommitAction(_ITM_userCommitFunction fn, + _ITM_transactionId_t tid, void *arg) +{ + gtm_thread *tx = gtm_thr(); + if (tid != _ITM_noTransactionId) + GTM_fatal("resumingTransactionId in _ITM_addUserCommitAction must be " + "_ITM_noTransactionId"); + gtm_thread::user_action *a = tx->user_actions.push(); + a->fn = fn; + a->arg = arg; + a->on_commit = true; + a->resuming_id = tid; +} + + +void ITM_REGPARM +_ITM_addUserUndoAction(_ITM_userUndoFunction fn, void * arg) +{ + gtm_thread *tx = gtm_thr(); + gtm_thread::user_action *a = tx->user_actions.push(); + a->fn = fn; + a->arg = arg; + a->on_commit = false; +} Index: libitm/config.h.in =================================================================== --- libitm/config.h.in (.../trunk) (revision 0) +++ libitm/config.h.in (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,159 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if the target supports 64-bit __sync_*_compare_and_swap */ +#undef HAVE_64BIT_SYNC_BUILTINS + +/* Define to 1 if the target supports __attribute__((alias(...))). */ +#undef HAVE_ATTRIBUTE_ALIAS + +/* Define to 1 if the target supports __attribute__((dllexport)). */ +#undef HAVE_ATTRIBUTE_DLLEXPORT + +/* Define to 1 if the target supports __attribute__((visibility(...))). */ +#undef HAVE_ATTRIBUTE_VISIBILITY + +/* Define if the POSIX Semaphores do not work on your system. */ +#undef HAVE_BROKEN_POSIX_SEMAPHORES + +/* Define to 1 if the target assembler supports thread-local storage. */ +#undef HAVE_CC_TLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memalign' function. */ +#undef HAVE_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +#undef HAVE_MMAP_ANON + +/* Define if mmap of /dev/zero works. */ +#undef HAVE_MMAP_DEV_ZERO + +/* Define if read-only mmap of a plain file works. */ +#undef HAVE_MMAP_FILE + +/* Define to 1 if you have the `posix_memalign' function. */ +#undef HAVE_POSIX_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_SEMAPHORE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if the target supports __sync_*_compare_and_swap */ +#undef HAVE_SYNC_BUILTINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if the target supports thread-local storage. */ +#undef HAVE_TLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if GNU symbol versioning is used for libitm. */ +#undef LIBITM_GNU_SYMBOL_VERSIONING + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to the letter to which size_t is mangled. */ +#undef MANGLE_SIZE_T + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char', as computed by sizeof. */ +#undef SIZEOF_CHAR + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef STRING_WITH_STRINGS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif Index: libitm/stmlock.h =================================================================== --- libitm/stmlock.h (.../trunk) (revision 0) +++ libitm/stmlock.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,123 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_STMLOCK_H +#define LIBITM_STMLOCK_H 1 + +namespace GTM HIDDEN { + +/* A versioned write lock on a cacheline. This must be wide enough to + store a pointer, and preferably wide enough to avoid overflowing the + version counter. Thus we use a "word", which should be 64-bits on + 64-bit systems even when their pointer size is forced smaller. */ +typedef gtm_word gtm_stmlock; + +/* This has to be the same size as gtm_stmlock, we just use this name + for documentation purposes. */ +typedef gtm_word gtm_version; + +/* The maximum value a version number can have. This is a consequence + of having the low bit of gtm_stmlock reserved for the owned bit. */ +#define GTM_VERSION_MAX (~(gtm_version)0 >> 1) + +/* A value that may be used to indicate "uninitialized" for a version. */ +#define GTM_VERSION_INVALID (~(gtm_version)0) + +/* This bit is set when the write lock is held. When set, the balance of + the bits in the lock is a pointer that references STM backend specific + data; it is up to the STM backend to determine if this thread holds the + lock. If this bit is clear, the balance of the bits are the last + version number committed to the cacheline. */ +static inline bool +gtm_stmlock_owned_p (gtm_stmlock lock) +{ + return lock & 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_owned (void *data) +{ + return (gtm_stmlock)(uintptr_t)data | 1; +} + +static inline void * +gtm_stmlock_get_addr (gtm_stmlock lock) +{ + return (void *)((uintptr_t)lock & ~(uintptr_t)1); +} + +static inline gtm_version +gtm_stmlock_get_version (gtm_stmlock lock) +{ + return lock >> 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_version (gtm_version ver) +{ + return ver << 1; +} + +/* We use a fixed set of locks for all memory, hashed into the + following table. */ +#define LOCK_ARRAY_SIZE (1024 * 1024) +extern gtm_stmlock gtm_stmlock_array[LOCK_ARRAY_SIZE]; + +static inline gtm_stmlock * +gtm_get_stmlock (const gtm_cacheline *addr) +{ + size_t idx = ((uintptr_t) addr / CACHELINE_SIZE) % LOCK_ARRAY_SIZE; + return gtm_stmlock_array + idx; +} + +/* The current global version number. */ +extern gtm_version gtm_clock; + +static inline gtm_version +gtm_get_clock (void) +{ + gtm_version r; + + __sync_synchronize (); + r = gtm_clock; + atomic_read_barrier (); + + return r; +} + +static inline gtm_version +gtm_inc_clock (void) +{ + gtm_version r = __sync_add_and_fetch (>m_clock, 1); + + /* ??? Ought to handle wraparound for 32-bit. */ + if (sizeof(r) < 8 && r > GTM_VERSION_MAX) + abort (); + + return r; +} + +} // namespace GTM + +#endif // LIBITM_STMLOCK_H Index: libitm/method-gl.cc =================================================================== --- libitm/method-gl.cc (.../trunk) (revision 0) +++ libitm/method-gl.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,303 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Torvald Riegel . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +namespace { + +// This group consists of all TM methods that synchronize via just a single +// global lock (or ownership record). +struct gl_mg : public method_group +{ + static const gtm_word LOCK_BIT = (~(gtm_word)0 >> 1) + 1; + // We can't use the full bitrange because ~0 in gtm_thread::shared_state has + // special meaning. + static const gtm_word VERSION_MAX = (~(gtm_word)0 >> 1) - 1; + static bool is_locked(gtm_word l) { return l & LOCK_BIT; } + static gtm_word set_locked(gtm_word l) { return l | LOCK_BIT; } + static gtm_word clear_locked(gtm_word l) { return l & ~LOCK_BIT; } + + // The global ownership record. + gtm_word orec; + virtual void init() + { + orec = 0; + } + virtual void fini() { } +}; + +static gl_mg o_gl_mg; + + +// The global lock, write-through TM method. +// Acquires the orec eagerly before the first write, and then writes through. +// Reads abort if the global orec's version number changed or if it is locked. +// Currently, writes require undo-logging to prevent deadlock between the +// serial lock and the global orec (writer txn acquires orec, reader txn +// upgrades to serial and waits for all other txns, writer tries to upgrade to +// serial too but cannot, writer cannot abort either, deadlock). We could +// avoid this if the serial lock would allow us to prevent other threads from +// going to serial mode, but this probably is too much additional complexity +// just to optimize this TM method. +// gtm_thread::shared_state is used to store a transaction's current +// snapshot time (or commit time). The serial lock uses ~0 for inactive +// transactions and 0 for active ones. Thus, we always have a meaningful +// timestamp in shared_state that can be used to implement quiescence-based +// privatization safety. This even holds if a writing transaction has the +// lock bit set in its shared_state because this is fine for both the serial +// lock (the value will be smaller than ~0) and privatization safety (we +// validate that no other update transaction comitted before we acquired the +// orec, so we have the most recent timestamp and no other transaction can +// commit until we have committed). +// However, we therefore cannot use this method for a serial transaction +// (because shared_state needs to remain at ~0) and we have to be careful +// when switching to serial mode (see the special handling in trycommit() and +// rollback()). +// ??? This sharing adds some complexity wrt. serial mode. Just use a separate +// state variable? +class gl_wt_dispatch : public abi_dispatch +{ +protected: + static void pre_write(const void *addr, size_t len) + { + gtm_thread *tx = gtm_thr(); + if (unlikely(!gl_mg::is_locked(tx->shared_state))) + { + // Check for and handle version number overflow. + if (unlikely(tx->shared_state >= gl_mg::VERSION_MAX)) + tx->restart(RESTART_INIT_METHOD_GROUP); + + // CAS global orec from our snapshot time to the locked state. + // This validates that we have a consistent snapshot, which is also + // for making privatization safety work (see the class' comments). + gtm_word now = o_gl_mg.orec; + if (now != tx->shared_state) + tx->restart(RESTART_VALIDATE_WRITE); + if (__sync_val_compare_and_swap(&o_gl_mg.orec, now, + gl_mg::set_locked(now)) != now) + tx->restart(RESTART_LOCKED_WRITE); + + // Set shared_state to new value. The CAS is a full barrier, so the + // acquisition of the global orec is visible before this store here, + // and the store will not be visible before earlier data loads, which + // is required to correctly ensure privatization safety (see + // begin_and_restart() and release_orec() for further comments). + tx->shared_state = gl_mg::set_locked(now); + } + + // TODO Ensure that this gets inlined: Use internal log interface and LTO. + GTM_LB(addr, len); + } + + static void validate() + { + // Check that snapshot is consistent. The barrier ensures that this + // happens after previous data loads. + atomic_read_barrier(); + gtm_thread *tx = gtm_thr(); + gtm_word l = o_gl_mg.orec; + if (l != tx->shared_state) + tx->restart(RESTART_VALIDATE_READ); + } + + template static V load(const V* addr, ls_modifier mod) + { + // Read-for-write should be unlikely, but we need to handle it or will + // break later WaW optimizations. + if (unlikely(mod == RfW)) + { + pre_write(addr, sizeof(V)); + return *addr; + } + V v = *addr; + if (likely(mod != RaW)) + validate(); + return v; + } + + template static void store(V* addr, const V value, + ls_modifier mod) + { + if (unlikely(mod != WaW)) + pre_write(addr, sizeof(V)); + *addr = value; + } + +public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + if ((dst_mod != WaW && src_mod != RaW) + && (dst_mod != NONTXNAL || src_mod == RfW)) + pre_write(dst, size); + + if (!may_overlap) + ::memcpy(dst, src, size); + else + ::memmove(dst, src, size); + + if (src_mod != RfW && src_mod != RaW && src_mod != NONTXNAL + && dst_mod != WaW) + validate(); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + if (mod != WaW) + pre_write(dst, size); + ::memset(dst, c, size); + } + + virtual gtm_restart_reason begin_or_restart() + { + // We don't need to do anything for nested transactions. + gtm_thread *tx = gtm_thr(); + if (tx->parent_txns.size() > 0) + return NO_RESTART; + + // Spin until global orec is not locked. + // TODO This is not necessary if there are no pure loads (check txn props). + gtm_word v; + unsigned i = 0; + while (gl_mg::is_locked(v = o_gl_mg.orec)) + { + // TODO need method-specific max spin count + if (++i > gtm_spin_count_var) return RESTART_VALIDATE_READ; + cpu_relax(); + } + // This barrier ensures that we have read the global orec before later + // data loads. + atomic_read_barrier(); + + // Everything is okay, we have a snapshot time. + // We don't need to enforce any ordering for the following store. There + // are no earlier data loads in this transaction, so the store cannot + // become visible before those (which could lead to the violation of + // privatization safety). The store can become visible after later loads + // but this does not matter because the previous value will have been + // smaller or equal (the serial lock will set shared_state to zero when + // marking the transaction as active, and restarts enforce immediate + // visibility of a smaller or equal value with a barrier (see + // release_orec()). + tx->shared_state = v; + return NO_RESTART; + } + + virtual bool trycommit(gtm_word& priv_time) + { + gtm_thread* tx = gtm_thr(); + gtm_word v = tx->shared_state; + + // Special case: If shared_state is ~0, then we have acquired the + // serial lock (tx->state is not updated yet). In this case, the previous + // value isn't available anymore, so grab it from the global lock, which + // must have a meaningful value because no other transactions are active + // anymore. In particular, if it is locked, then we are an update + // transaction, which is all we care about for commit. + if (v == ~(typeof v)0) + v = o_gl_mg.orec; + + // Release the orec but do not reset shared_state, which will be modified + // by the serial lock right after our commit anyway. Also, resetting + // shared state here would interfere with the serial lock's use of this + // location. + if (gl_mg::is_locked(v)) + { + // Release the global orec, increasing its version number / timestamp. + // TODO replace with C++0x-style atomics (a release in this case) + atomic_write_barrier(); + v = gl_mg::clear_locked(v) + 1; + o_gl_mg.orec = v; + + // Need to ensure privatization safety. Every other transaction must + // have a snapshot time that is at least as high as our commit time + // (i.e., our commit must be visible to them). + priv_time = v; + } + return true; + } + + virtual void rollback(gtm_transaction_cp *cp) + { + // We don't do anything for rollbacks of nested transactions. + if (cp != 0) + return; + + gtm_thread *tx = gtm_thr(); + gtm_word v = tx->shared_state; + // Special case: If shared_state is ~0, then we have acquired the + // serial lock (tx->state is not updated yet). In this case, the previous + // value isn't available anymore, so grab it from the global lock, which + // must have a meaningful value because no other transactions are active + // anymore. In particular, if it is locked, then we are an update + // transaction, which is all we care about for rollback. + if (v == ~(typeof v)0) + v = o_gl_mg.orec; + + // Release lock and increment version number to prevent dirty reads. + // Also reset shared state here, so that begin_or_restart() can expect a + // value that is correct wrt. privatization safety. + if (gl_mg::is_locked(v)) + { + // Release the global orec, increasing its version number / timestamp. + // TODO replace with C++0x-style atomics (a release in this case) + atomic_write_barrier(); + v = gl_mg::clear_locked(v) + 1; + o_gl_mg.orec = v; + + // Also reset the timestamp published via shared_state. + // Special case: Only do this if we are not a serial transaction + // because otherwise, we would interfere with the serial lock. + if (tx->shared_state != ~(typeof tx->shared_state)0) + tx->shared_state = v; + + // We need a store-load barrier after this store to prevent it + // from becoming visible after later data loads because the + // previous value of shared_state has been higher than the actual + // snapshot time (the lock bit had been set), which could break + // privatization safety. We do not need a barrier before this + // store (see pre_write() for an explanation). + __sync_synchronize(); + } + + } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + gl_wt_dispatch() : abi_dispatch(false, true, false, false, &o_gl_mg) + { } +}; + +} // anon namespace + +static const gl_wt_dispatch o_gl_wt_dispatch; + +abi_dispatch * +GTM::dispatch_gl_wt () +{ + return const_cast(&o_gl_wt_dispatch); +} Index: libitm/config/linux/futex.cc =================================================================== --- libitm/config/linux/futex.cc (.../trunk) (revision 0) +++ libitm/config/linux/futex.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,82 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Provide access to the futex system call. */ + +#include "libitm_i.h" +#include "futex.h" +#include + +namespace GTM HIDDEN { + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_PRIVATE_FLAG 128L + + +static long int gtm_futex_wait = FUTEX_WAIT | FUTEX_PRIVATE_FLAG; +static long int gtm_futex_wake = FUTEX_WAKE | FUTEX_PRIVATE_FLAG; + + +void +futex_wait (int *addr, int val) +{ + long res; + + res = sys_futex0 (addr, gtm_futex_wait, val); + if (__builtin_expect (res == -ENOSYS, 0)) + { + gtm_futex_wait = FUTEX_WAIT; + gtm_futex_wake = FUTEX_WAKE; + res = sys_futex0 (addr, FUTEX_WAIT, val); + } + if (__builtin_expect (res < 0, 0)) + { + if (res == -EWOULDBLOCK || res == -ETIMEDOUT) + ; + else if (res == -EFAULT) + GTM_fatal ("futex failed (EFAULT %p)", addr); + else + GTM_fatal ("futex failed (%s)", strerror(-res)); + } +} + + +long +futex_wake (int *addr, int count) +{ + long res = sys_futex0 (addr, gtm_futex_wake, count); + if (__builtin_expect (res == -ENOSYS, 0)) + { + gtm_futex_wait = FUTEX_WAIT; + gtm_futex_wake = FUTEX_WAKE; + res = sys_futex0 (addr, FUTEX_WAKE, count); + } + if (__builtin_expect (res < 0, 0)) + GTM_fatal ("futex failed (%s)", strerror(-res)); + else + return res; +} + +} // namespace GTM Index: libitm/config/linux/futex.h =================================================================== --- libitm/config/linux/futex.h (.../trunk) (revision 0) +++ libitm/config/linux/futex.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,39 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Provide access to the futex system call. */ + +#ifndef GTM_FUTEX_H +#define GTM_FUTEX_H 1 + +namespace GTM HIDDEN { + +#include "futex_bits.h" + +extern void futex_wait (int *addr, int val); +extern long futex_wake (int *addr, int count); + +} + +#endif /* GTM_FUTEX_H */ Index: libitm/config/linux/alpha/futex_bits.h =================================================================== --- libitm/config/linux/alpha/futex_bits.h (.../trunk) (revision 0) +++ libitm/config/linux/alpha/futex_bits.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,56 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Provide target-specific access to the futex system call. */ + +#ifndef SYS_futex +#define SYS_futex 394 +#endif + +static inline long +sys_futex0 (int *addr, long op, long val) +{ + register long sc_0 __asm__("$0"); + register long sc_16 __asm__("$16"); + register long sc_17 __asm__("$17"); + register long sc_18 __asm__("$18"); + register long sc_19 __asm__("$19"); + long res; + + sc_0 = SYS_futex; + sc_16 = (long) addr; + sc_17 = op; + sc_18 = val; + sc_19 = 0; + __asm volatile ("callsys" + : "=r" (sc_0), "=r"(sc_19) + : "0"(sc_0), "r" (sc_16), "r"(sc_17), "r"(sc_18), "1"(sc_19) + : "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", + "$22", "$23", "$24", "$25", "$27", "$28", "memory"); + + res = sc_0; + if (__builtin_expect (sc_19, 0)) + res = -res; + return res; +} Index: libitm/config/linux/rwlock.cc =================================================================== --- libitm/config/linux/rwlock.cc (.../trunk) (revision 0) +++ libitm/config/linux/rwlock.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,235 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Torvald Riegel . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include "futex.h" +#include + +namespace GTM HIDDEN { + +// Acquire a RW lock for reading. + +void +gtm_rwlock::read_lock (gtm_thread *tx) +{ + for (;;) + { + // Fast path: first announce our intent to read, then check for + // conflicting intents to write. The barrier makes sure that this + // happens in exactly this order. + tx->shared_state = 0; + __sync_synchronize(); + if (likely(writers == 0)) + return; + + // There seems to be an active, waiting, or confirmed writer, so enter + // the futex-based slow path. + + // Before waiting, we clear our read intent check whether there are any + // writers that might potentially wait for readers. If so, wake them. + // We need the barrier here for the same reason that we need it in + // read_unlock(). + // TODO Potentially too many wake-ups. See comments in read_unlock(). + tx->shared_state = ~(typeof tx->shared_state)0; + __sync_synchronize(); + if (writer_readers > 0) + { + writer_readers = 0; + futex_wake(&writer_readers, 1); + } + + // Signal that there are waiting readers and wait until there is no + // writer anymore. + // TODO Spin here on writers for a while. Consider whether we woke + // any writers before? + while (writers) + { + // An active writer. Wait until it has finished. To avoid lost + // wake-ups, we need to use Dekker-like synchronization. + // Note that we cannot reset readers to zero when we see that there + // are no writers anymore after the barrier because this pending + // store could then lead to lost wake-ups at other readers. + readers = 1; + __sync_synchronize(); + if (writers) + futex_wait(&readers, 1); + } + + // And we try again to acquire a read lock. + } +} + + +// Acquire a RW lock for writing. Generic version that also works for +// upgrades. +// Note that an upgrade might fail (and thus waste previous work done during +// this transaction) if there is another thread that tried to go into serial +// mode earlier (i.e., upgrades do not have higher priority than pure writers). +// However, this seems rare enough to not consider it further as we need both +// a non-upgrade writer and a writer to happen to switch to serial mode +// concurrently. If we'd want to handle this, a writer waiting for readers +// would have to coordinate with later arriving upgrades and hand over the +// lock to them, including the the reader-waiting state. We can try to support +// this if this will actually happen often enough in real workloads. + +bool +gtm_rwlock::write_lock_generic (gtm_thread *tx) +{ + // Try to acquire the write lock. + unsigned int w; + if (unlikely((w = __sync_val_compare_and_swap(&writers, 0, 1)) != 0)) + { + // If this is an upgrade, we must not wait for other writers or + // upgrades. + if (tx != 0) + return false; + + // There is already a writer. If there are no other waiting writers, + // switch to contended mode. + // Note that this is actually an atomic exchange, not a TAS. Also, + // it's only guaranteed to have acquire semantics, whereas we need a + // full barrier to make the Dekker-style synchronization work. However, + // we rely on the xchg being a full barrier on the architectures that we + // consider here. + // ??? Use C++0x atomics as soon as they are available. + if (w != 2) + w = __sync_lock_test_and_set(&writers, 2); + while (w != 0) + { + futex_wait(&writers, 2); + w = __sync_lock_test_and_set(&writers, 2); + } + } + + // We have acquired the writer side of the R/W lock. Now wait for any + // readers that might still be active. + // We don't need an extra barrier here because the CAS and the xchg + // operations have full barrier semantics already. + + // If this is an upgrade, we are not a reader anymore. This is only safe to + // do after we have acquired the writer lock. + // TODO In the worst case, this requires one wait/wake pair for each + // active reader. Reduce this! + if (tx != 0) + tx->shared_state = ~(typeof tx->shared_state)0; + + for (gtm_thread *it = gtm_thread::list_of_threads; it != 0; + it = it->next_thread) + { + // Use a loop here to check reader flags again after waiting. + while (it->shared_state != ~(typeof it->shared_state)0) + { + // An active reader. Wait until it has finished. To avoid lost + // wake-ups, we need to use Dekker-like synchronization. + // Note that we can reset writer_readers to zero when we see after + // the barrier that the reader has finished in the meantime; + // however, this is only possible because we are the only writer. + // TODO Spin for a while on this reader flag. + writer_readers = 1; + __sync_synchronize(); + if (it->shared_state != ~(typeof it->shared_state)0) + futex_wait(&writer_readers, 1); + else + writer_readers = 0; + } + } + + return true; +} + +// Acquire a RW lock for writing. + +void +gtm_rwlock::write_lock () +{ + write_lock_generic (0); +} + + +// Upgrade a RW lock that has been locked for reading to a writing lock. +// Do this without possibility of another writer incoming. Return false +// if this attempt fails (i.e. another thread also upgraded). + +bool +gtm_rwlock::write_upgrade (gtm_thread *tx) +{ + return write_lock_generic (tx); +} + + +// Release a RW lock from reading. + +void +gtm_rwlock::read_unlock (gtm_thread *tx) +{ + tx->shared_state = ~(typeof tx->shared_state)0; + + // If there is a writer waiting for readers, wake it up. We need the barrier + // to avoid lost wake-ups. + // ??? We might not be the last active reader, so the wake-up might happen + // too early. How do we avoid this without slowing down readers too much? + // Each reader could scan the list of txns for other active readers but + // this can result in many cache misses. Use combining instead? + // TODO Sends out one wake-up for each reader in the worst case. + __sync_synchronize(); + if (unlikely(writer_readers > 0)) + { + writer_readers = 0; + futex_wake(&writer_readers, 1); + } +} + + +// Release a RW lock from writing. + +void +gtm_rwlock::write_unlock () +{ + // This is supposed to be a full barrier. + if (__sync_fetch_and_sub(&writers, 1) == 2) + { + // There might be waiting writers, so wake them. + writers = 0; + if (futex_wake(&writers, 1) == 0) + { + // If we did not wake any waiting writers, we might indeed be the + // last writer (this can happen because write_lock_generic() + // exchanges 0 or 1 to 2 and thus might go to contended mode even if + // no other thread holds the write lock currently). Therefore, we + // have to wake up readers here as well. + futex_wake(&readers, INT_MAX); + } + return; + } + // No waiting writers, so wake up all waiting readers. + // Because the fetch_and_sub is a full barrier already, we don't need + // another barrier here (as in read_unlock()). + if (readers > 0) + { + readers = 0; + futex_wake(&readers, INT_MAX); + } +} + +} // namespace GTM Index: libitm/config/linux/x86/futex_bits.h =================================================================== --- libitm/config/linux/x86/futex_bits.h (.../trunk) (revision 0) +++ libitm/config/linux/x86/futex_bits.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,82 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifdef __x86_64__ +# ifndef SYS_futex +# define SYS_futex 202 +# endif + +static inline long +sys_futex0 (int *addr, long op, long val) +{ + register long r10 __asm__("%r10") = 0; + long res; + + __asm volatile ("syscall" + : "=a" (res) + : "0" (SYS_futex), "D" (addr), "S" (op), "d" (val), "r" (r10) + : "r11", "rcx", "memory"); + + return res; +} + +#else +# ifndef SYS_futex +# define SYS_futex 240 +# endif + +# ifdef __PIC__ + +static inline long +sys_futex0 (int *addr, int op, int val) +{ + long res; + + __asm volatile ("xchgl\t%%ebx, %2\n\t" + "int\t$0x80\n\t" + "xchgl\t%%ebx, %2" + : "=a" (res) + : "0"(SYS_futex), "r" (addr), "c"(op), + "d"(val), "S"(0) + : "memory"); + return res; +} + +# else + +static inline long +sys_futex0 (int *addr, int op, int val) +{ + long res; + + __asm volatile ("int $0x80" + : "=a" (res) + : "0"(SYS_futex), "b" (addr), "c"(op), + "d"(val), "S"(0) + : "memory"); + return res; +} + +# endif /* __PIC__ */ +#endif /* __x86_64__ */ Index: libitm/config/linux/x86/tls.h =================================================================== --- libitm/config/linux/x86/tls.h (.../trunk) (revision 0) +++ libitm/config/linux/x86/tls.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,105 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_X86_TLS_H +#define LIBITM_X86_TLS_H 1 + +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) +/* Use slots in the TCB head rather than __thread lookups. + GLIBC has reserved words 10 through 13 for TM. */ +#define HAVE_ARCH_GTM_THREAD 1 +#define HAVE_ARCH_GTM_THREAD_DISP 1 +#endif + +#include "config/generic/tls.h" + +#if defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 10) +namespace GTM HIDDEN { + +#ifdef __x86_64__ +#ifdef __LP64__ +# define SEG_READ(OFS) "movq\t%%fs:(" #OFS "*8),%0" +# define SEG_WRITE(OFS) "movq\t%0,%%fs:(" #OFS "*8)" +# define SEG_DECODE_READ(OFS) SEG_READ(OFS) "\n\t" \ + "rorq\t$17,%0\n\t" \ + "xorq\t%%fs:48,%0" +# define SEG_ENCODE_WRITE(OFS) "xorq\t%%fs:48,%0\n\t" \ + "rolq\t$17,%0\n\t" \ + SEG_WRITE(OFS) +#else +// For X32. +# define SEG_READ(OFS) "movl\t%%fs:(" #OFS "*4),%0" +# define SEG_WRITE(OFS) "movl\t%0,%%fs:(" #OFS "*4)" +# define SEG_DECODE_READ(OFS) SEG_READ(OFS) "\n\t" \ + "rorl\t$9,%0\n\t" \ + "xorl\t%%fs:24,%0" +# define SEG_ENCODE_WRITE(OFS) "xorl\t%%fs:24,%0\n\t" \ + "roll\t$9,%0\n\t" \ + SEG_WRITE(OFS) +#endif +#else +# define SEG_READ(OFS) "movl\t%%gs:(" #OFS "*4),%0" +# define SEG_WRITE(OFS) "movl\t%0,%%gs:(" #OFS "*4)" +# define SEG_DECODE_READ(OFS) SEG_READ(OFS) "\n\t" \ + "rorl\t$9,%0\n\t" \ + "xorl\t%%gs:24,%0" +# define SEG_ENCODE_WRITE(OFS) "xorl\t%%gs:24,%0\n\t" \ + "roll\t$9,%0\n\t" \ + SEG_WRITE(OFS) +#endif + +static inline struct gtm_thread *gtm_thr(void) +{ + struct gtm_thread *r; + asm volatile (SEG_READ(10) : "=r"(r)); + return r; +} + +static inline void set_gtm_thr(struct gtm_thread *x) +{ + asm volatile (SEG_WRITE(10) : : "r"(x)); +} + +static inline struct abi_dispatch *abi_disp(void) +{ + struct abi_dispatch *r; + asm volatile (SEG_DECODE_READ(11) : "=r"(r)); + return r; +} + +static inline void set_abi_disp(struct abi_dispatch *x) +{ + void *scratch; + asm volatile (SEG_ENCODE_WRITE(11) : "=r"(scratch) : "0"(x)); +} + +#undef SEG_READ +#undef SEG_WRITE +#undef SEG_DECODE_READ +#undef SEG_ENCODE_WRITE + +} // namespace GTM +#endif /* >= GLIBC 2.10 */ + +#endif // LIBITM_X86_TLS_H Index: libitm/config/linux/rwlock.h =================================================================== --- libitm/config/linux/rwlock.h (.../trunk) (revision 0) +++ libitm/config/linux/rwlock.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,66 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + Contributed by Torvald Riegel . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef GTM_RWLOCK_H +#define GTM_RWLOCK_H + +#include "common.h" + +namespace GTM HIDDEN { + +struct gtm_thread; + +// This datastructure is the blocking, futex-based version of the Dekker-style +// reader-writer lock used to provide mutual exclusion between active and +// serial transactions. +// See libitm's documentation for further details. +// +// In this implementation, writers are given highest priority access but +// read-to-write upgrades do not have a higher priority than writers. + +class gtm_rwlock +{ + // TODO Put futexes on different cachelines? + int writers; // Writers' futex. + int writer_readers; // A confirmed writer waits here for readers. + int readers; // Readers wait here for writers (iff true). + + public: + gtm_rwlock() : writers(0), writer_readers(0), readers(0) {}; + + void read_lock (gtm_thread *tx); + void read_unlock (gtm_thread *tx); + + void write_lock (); + void write_unlock (); + + bool write_upgrade (gtm_thread *tx); + + protected: + bool write_lock_generic (gtm_thread *tx); +}; + +} // namespace GTM + +#endif // GTM_RWLOCK_H Index: libitm/config/posix/cachepage.cc =================================================================== --- libitm/config/posix/cachepage.cc (.../trunk) (revision 0) +++ libitm/config/posix/cachepage.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,183 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include + +// +// We have three possibilities for alloction: mmap, memalign, posix_memalign +// + +#if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) +#include +#include +#endif +#ifdef HAVE_MALLOC_H +#include +#endif + +namespace GTM HIDDEN { + +#if defined(HAVE_MMAP_ANON) +# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +# define dev_zero -1 +#elif defined(HAVE_MMAP_DEV_ZERO) +# ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS 0 +# endif +static int dev_zero = -1; +#endif + +#if defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) +/* If we get here, we've already opened /dev/zero and verified that + PAGE_SIZE is valid for the system. */ +static gtm_cacheline_page * alloc_mmap (void) UNUSED; +static gtm_cacheline_page * +alloc_mmap (void) +{ + gtm_cacheline_page *r; + r = (gtm_cacheline_page *) mmap (NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, dev_zero, 0); + if (r == (gtm_cacheline_page *) MAP_FAILED) + abort (); + return r; +} +#endif /* MMAP_ANON | MMAP_DEV_ZERO */ + +#ifdef HAVE_MEMALIGN +static gtm_cacheline_page * alloc_memalign (void) UNUSED; +static gtm_cacheline_page * +alloc_memalign (void) +{ + gtm_cacheline_page *r; + r = (gtm_cacheline_page *) memalign (PAGE_SIZE, PAGE_SIZE); + if (r == NULL) + abort (); + return r; +} +#endif /* MEMALIGN */ + +#ifdef HAVE_POSIX_MEMALIGN +static gtm_cacheline_page *alloc_posix_memalign (void) UNUSED; +static gtm_cacheline_page * +alloc_posix_memalign (void) +{ + void *r; + if (posix_memalign (&r, PAGE_SIZE, PAGE_SIZE)) + abort (); + return (gtm_cacheline_page *) r; +} +#endif /* POSIX_MEMALIGN */ + +#if defined(HAVE_MMAP_ANON) && defined(FIXED_PAGE_SIZE) +# define alloc_page alloc_mmap +#elif defined(HAVE_MMAP_DEV_ZERO) && defined(FIXED_PAGE_SIZE) +static gtm_cacheline_page * +alloc_page (void) +{ + if (dev_zero < 0) + { + dev_zero = open ("/dev/zero", O_RDWR); + assert (dev_zero >= 0); + } + return alloc_mmap (); +} +#elif defined(HAVE_MMAP_ANON) || defined(HAVE_MMAP_DEV_ZERO) +static gtm_cacheline_page * (*alloc_page) (void); +static void __attribute__((constructor)) +init_alloc_page (void) +{ + size_t page_size = getpagesize (); + if (page_size <= PAGE_SIZE && PAGE_SIZE % page_size == 0) + { +# ifndef HAVE_MMAP_ANON + dev_zero = open ("/dev/zero", O_RDWR); + assert (dev_zero >= 0); +# endif + alloc_page = alloc_mmap; + return; + } +# ifdef HAVE_MEMALIGN + alloc_page = alloc_memalign; +# elif defined(HAVE_POSIX_MEMALIGN) + alloc_page = alloc_posix_memalign; +# else +# error "No fallback aligned memory allocation method" +# endif +} +#elif defined(HAVE_MEMALIGN) +# define alloc_page alloc_memalign +#elif defined(HAVE_POSIX_MEMALIGN) +# define alloc_page alloc_posix_memalign +#else +# error "No aligned memory allocation method" +#endif + +static gtm_cacheline_page *free_pages; +static pthread_mutex_t free_page_lock = PTHREAD_MUTEX_INITIALIZER; + +void * +gtm_cacheline_page::operator new (size_t size) +{ + assert (size == sizeof (gtm_cacheline_page)); + assert (size <= PAGE_SIZE); + + pthread_mutex_lock(&free_page_lock); + + gtm_cacheline_page *r = free_pages; + free_pages = r ? r->prev : NULL; + + pthread_mutex_unlock(&free_page_lock); + + if (r == NULL) + r = alloc_page (); + + return r; +} + +void +gtm_cacheline_page::operator delete (void *xhead) +{ + gtm_cacheline_page *head = static_cast(xhead); + gtm_cacheline_page *tail; + + if (head == 0) + return; + + /* ??? We should eventually really free some of these. */ + + for (tail = head; tail->prev != 0; tail = tail->prev) + continue; + + pthread_mutex_lock(&free_page_lock); + + tail->prev = free_pages; + free_pages = head; + + pthread_mutex_unlock(&free_page_lock); +} + +} // namespace GTM Index: libitm/config/posix/rwlock.cc =================================================================== --- libitm/config/posix/rwlock.cc (.../trunk) (revision 0) +++ libitm/config/posix/rwlock.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,288 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// Initialize a new RW lock. +// ??? Move this back to the header file when constexpr is implemented. + +gtm_rwlock::gtm_rwlock() + : mutex (PTHREAD_MUTEX_INITIALIZER), + c_readers (PTHREAD_COND_INITIALIZER), + c_writers (PTHREAD_COND_INITIALIZER), + c_confirmed_writers (PTHREAD_COND_INITIALIZER), + summary (0), + a_readers (0), + w_readers (0), + w_writers (0) +{ } + +gtm_rwlock::~gtm_rwlock() +{ + pthread_mutex_destroy (&this->mutex); + pthread_cond_destroy (&this->c_readers); + pthread_cond_destroy (&this->c_writers); +} + +// Acquire a RW lock for reading. + +void +gtm_rwlock::read_lock (gtm_thread *tx) +{ + // Fast path: first announce our intent to read, then check for conflicting + // intents to write. The barrier makes sure that this happens in exactly + // this order. + tx->shared_state = 0; + __sync_synchronize(); + unsigned int sum = this->summary; + if (likely(!(sum & (a_writer | w_writer)))) + return; + + // There seems to be an active, waiting, or confirmed writer, so enter the + // mutex-based slow path. To try to keep the number of readers small that + // the writer will see, we clear our read flag right away before entering + // the critical section. Otherwise, the writer would have to wait for us to + // get into the critical section. (Note that for correctness, this only has + // to happen before we leave the slow path and before we wait for any + // writer). + // ??? Add a barrier to enforce early visibility of this? + tx->shared_state = ~(typeof tx->shared_state)0; + + pthread_mutex_lock (&this->mutex); + + // Read summary again after acquiring the mutex because it might have + // changed during waiting for the mutex to become free. + sum = this->summary; + + // If there is a writer waiting for readers, wake it up. Only do that if we + // might be the last reader that could do the wake-up, otherwise skip the + // wake-up but decrease a_readers to show that we have entered the slow path. + // This has to happen before we wait for any writers or upgraders. + // See write_lock_generic() for further explanations. + if (this->a_readers > 0) + { + this->a_readers--; + if (this->a_readers == 0) + pthread_cond_signal(&this->c_confirmed_writers); + } + + // If there is an active or waiting writer, we must wait. + while (sum & (a_writer | w_writer)) + { + this->summary = sum | w_reader; + this->w_readers++; + pthread_cond_wait (&this->c_readers, &this->mutex); + sum = this->summary; + if (--this->w_readers == 0) + sum &= ~w_reader; + } + + // Otherwise we can acquire the lock for read. + tx->shared_state = 0; + + pthread_mutex_unlock(&this->mutex); +} + + +// Acquire a RW lock for writing. Generic version that also works for +// upgrades. +// Note that an upgrade might fail (and thus waste previous work done during +// this transaction) if there is another thread that tried to go into serial +// mode earlier (i.e., upgrades do not have higher priority than pure writers). +// However, this seems rare enough to not consider it further as we need both +// a non-upgrade writer and a writer to happen to switch to serial mode +// concurrently. If we'd want to handle this, a writer waiting for readers +// would have to coordinate with later arriving upgrades and hand over the +// lock to them, including the the reader-waiting state. We can try to support +// this if this will actually happen often enough in real workloads. + +bool +gtm_rwlock::write_lock_generic (gtm_thread *tx) +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + + // If there is an active writer, wait. + while (sum & a_writer) + { + if (tx != 0) + { + // If this is an upgrade, we must not wait for other writers or + // upgrades that already have gone in + pthread_mutex_unlock (&this->mutex); + return false; + } + + this->summary = sum | w_writer; + this->w_writers++; + pthread_cond_wait (&this->c_writers, &this->mutex); + sum = this->summary; + if (--this->w_writers == 0) + sum &= ~w_writer; + } + + // Otherwise we can acquire the lock for write. As a writer, we have + // priority, so we don't need to take this back. + this->summary = sum | a_writer; + + // We still need to wait for active readers to finish. The barrier makes + // sure that we first set our write intent and check for active readers + // after that, in strictly this order (similar to the barrier in the fast + // path of read_lock()). + __sync_synchronize(); + + // If this is an upgrade, we are not a reader anymore. + if (tx != 0) + tx->shared_state = ~(typeof tx->shared_state)0; + + // Count the number of active readers to be able to decrease the number of + // wake-ups and wait calls that are necessary. + // + // This number is an upper bound of the number of readers that actually + // are still active and which we need to wait for: + // - We set our write flag before checking the reader flags, and readers + // check our write flag after clearing their read flags in read_unlock(). + // Therefore, they will enter the slow path whenever we have seen them. + // - Readers will have cleared their read flags before leaving the slow + // path in read_lock() (prevents lost wake-ups), and before waiting for + // any writer (prevents deadlocks). + // + // However, this number is also just a lower bound of the number of readers + // that will actually enter the slow path in read_unlock() or read_lock(): + // - Because the read flag is cleared outside of a critical section, writers + // can see it as cleared while the reader still goes into the slow path. + // + // Therefore, readers can skip (lower bound - 1) wake-ups, but we do need + // the following loop to check that the readers that we wanted to wait for + // are actually those that entered the slow path so far (and either skipped + // or sent a wake-up). + // + // ??? Do we need to optimize further? (The writer could publish a list of + // readers that it suspects to be active. Readers could check this list and + // only decrement a_readers if they are in this list.) + for (;;) + { + // ??? Keep a list of active readers that we saw and update it on the + // next retry instead? This might reduce the number of cache misses that + // we get when checking reader flags. + int readers = 0; + for (gtm_thread *it = gtm_thread::list_of_threads; it != 0; + it = it->next_thread) + { + // Don't count ourself if this is an upgrade. + if (it->shared_state != ~(typeof it->shared_state)0) + readers++; + } + + // If we have not seen any readers, we will not wait. + if (readers == 0) + break; + + // We've seen a number of readers, so we publish this number and wait. + this->a_readers = readers; + pthread_cond_wait (&this->c_confirmed_writers, &this->mutex); + } + + pthread_mutex_unlock (&this->mutex); + return true; +} + +// Acquire a RW lock for writing. + +void +gtm_rwlock::write_lock () +{ + write_lock_generic (0); +} + + +// Upgrade a RW lock that has been locked for reading to a writing lock. +// Do this without possibility of another writer incoming. Return false +// if this attempt fails (i.e. another thread also upgraded). + +bool +gtm_rwlock::write_upgrade (gtm_thread *tx) +{ + return write_lock_generic (tx); +} + + +// Release a RW lock from reading. + +void +gtm_rwlock::read_unlock (gtm_thread *tx) +{ + tx->shared_state = ~(typeof tx->shared_state)0; + __sync_synchronize(); + unsigned int sum = this->summary; + if (likely(!(sum & (a_writer | w_writer)))) + return; + + // There is a writer, either active or waiting for other readers or writers. + // Thus, enter the mutex-based slow path. + pthread_mutex_lock (&this->mutex); + + // If there is a writer waiting for readers, wake it up. Only do that if we + // might be the last reader that could do the wake-up, otherwise skip the + // wake-up and decrease a_readers to publish that we have entered the slow + // path but skipped the wake-up. + if (this->a_readers > 0) + { + this->a_readers--; + if (this->a_readers == 0) + pthread_cond_signal(&this->c_confirmed_writers); + } + + // We don't need to wake up any writers waiting for other writers. Active + // writers will take care of that. + + pthread_mutex_unlock (&this->mutex); +} + + +// Release a RW lock from writing. + +void +gtm_rwlock::write_unlock () +{ + pthread_mutex_lock (&this->mutex); + + unsigned int sum = this->summary; + this->summary = sum & ~a_writer; + + // If there is a waiting writer, wake it. + if (unlikely (sum & w_writer)) + pthread_cond_signal (&this->c_writers); + + // If there are waiting readers, wake them. + else if (unlikely (sum & w_reader)) + pthread_cond_broadcast (&this->c_readers); + + pthread_mutex_unlock (&this->mutex); +} + +} // namespace GTM Index: libitm/config/posix/rwlock.h =================================================================== --- libitm/config/posix/rwlock.h (.../trunk) (revision 0) +++ libitm/config/posix/rwlock.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,81 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef GTM_RWLOCK_H +#define GTM_RWLOCK_H + +#include + +namespace GTM HIDDEN { + +struct gtm_thread; + +// This datastructure is the blocking, mutex-based side of the Dekker-style +// reader-writer lock used to provide mutual exclusion between active and +// serial transactions. It has similarities to POSIX pthread_rwlock_t except +// that we also provide for upgrading a reader->writer lock, with a +// positive indication of failure (another writer acquired the lock +// before we were able to acquire). While the writer flag (a_writer below) is +// global and protected by the mutex, there are per-transaction reader flags, +// which are stored in a transaction's shared state. +// See libitm's documentation for further details. +// +// In this implementation, writers are given highest priority access but +// read-to-write upgrades do not have a higher priority than writers. + +class gtm_rwlock +{ + pthread_mutex_t mutex; // Held if manipulating any field. + pthread_cond_t c_readers; // Readers wait here + pthread_cond_t c_writers; // Writers wait here for writers + pthread_cond_t c_confirmed_writers; // Writers wait here for readers + + static const unsigned a_writer = 1; // An active writer. + static const unsigned w_writer = 2; // The w_writers field != 0 + static const unsigned w_reader = 4; // The w_readers field != 0 + + unsigned int summary; // Bitmask of the above. + unsigned int a_readers; // Nr active readers as observed by a writer + unsigned int w_readers; // Nr waiting readers + unsigned int w_writers; // Nr waiting writers + + public: + gtm_rwlock(); + ~gtm_rwlock(); + + void read_lock (gtm_thread *tx); + void read_unlock (gtm_thread *tx); + + void write_lock (); + void write_unlock (); + + bool write_upgrade (gtm_thread *tx); + + protected: + bool write_lock_generic (gtm_thread *tx); +}; + +} // namespace GTM + +#endif // GTM_RWLOCK_H Index: libitm/config/alpha/cacheline.h =================================================================== --- libitm/config/alpha/cacheline.h (.../trunk) (revision 0) +++ libitm/config/alpha/cacheline.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,122 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_ALPHA_CACHELINE_H +#define LIBITM_ALPHA_CACHELINE_H 1 + +// A cacheline is the smallest unit with which locks are associated. +// The current implementation of the _ITM_[RW] barriers assumes that +// all data types can fit (aligned) within a cachline, which means +// in practice sizeof(complex long double) is the smallest cacheline size. +// It ought to be small enough for efficient manipulation of the +// modification mask, below. +#define CACHELINE_SIZE 64 + +#ifdef __alpha_bwx__ +# include "config/generic/cacheline.h" +#else +// If we don't have byte-word stores, then we'll never be able to +// adjust *all* of the byte loads/stores to be truely atomic. So +// only guarantee 4-byte aligned values atomicly stored, exactly +// like the native system. Use byte zap instructions to accelerate +// sub-word masked stores. + +namespace GTM HIDDEN { + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral::type gtm_cacheline_mask; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + + // Store S into D, but only the bytes specified by M. + static void store_mask(uint32_t *d, uint32_t s, uint8_t m); + static void store_mask(uint64_t *d, uint64_t s, uint8_t m); + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + static void copy_mask_wb () { atomic_write_barrier(); } +}; + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint32_t *d, uint32_t s, uint8_t m) +{ + const uint8_t tm = (1 << sizeof(uint32_t)) - 1; + + m &= tm; + if (__builtin_expect (m, tm)) + { + if (__builtin_expect (m == tm, 1)) + *d = s; + else + *d = __builtin_alpha_zap (*d, m) | __builtin_alpha_zapnot (s, m); + } +} + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint64_t *d, uint64_t s, uint8_t m) +{ + if (__builtin_expect (m, 0xff)) + { + if (__builtin_expect (m == 0xff, 1)) + *d = s; + else + { + typedef uint32_t *p32 __attribute__((may_alias)); + p32 d32 = reinterpret_cast(d); + + if ((m & 0x0f) == 0x0f) + { + d32[0] = s; + m &= 0xf0; + } + else if ((m & 0xf0) == 0xf0) + { + d32[1] = s >> 32; + m &= 0x0f; + } + + if (m) + *d = __builtin_alpha_zap (*d, m) | __builtin_alpha_zapnot (s, m); + } + } +} + +} // namespace GTM + +#endif // __alpha_bwx__ +#endif // LIBITM_ALPHA_CACHELINE_H Index: libitm/config/alpha/sjlj.S =================================================================== --- libitm/config/alpha/sjlj.S (.../trunk) (revision 0) +++ libitm/config/alpha/sjlj.S (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,108 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + + .text + .align 4 + .globl _ITM_beginTransaction + .ent _ITM_beginTransaction + +#define FRAME 144 + +_ITM_beginTransaction: + ldgp $29, 0($27) + subq $30, FRAME, $30 + .frame $30, FRAME, $26, 0 + .mask 0x04000000, 0 + stq $26, 0($30) + .prologue 1 + + stq $9, 8($30) + stq $10, 16($30) + addq $30, FRAME, $0 + stq $11, 24($30) + + stq $12, 32($30) + stq $13, 40($30) + stq $14, 48($30) + stq $15, 56($30) + + stq $0, 64($30) + stt $f2, 72($30) + stt $f3, 80($30) + stt $f4, 88($30) + + stt $f5, 96($30) + stt $f6, 104($30) + stt $f7, 112($30) + stt $f8, 120($30) + + stt $f9, 128($30) + mov $30, $17 +#ifdef __PIC__ + unop + bsr $26, GTM_begin_transaction !samegp +#else + jsr $26, GTM_begin_transaction + ldgp $29, 0($26) +#endif + + ldq $26, 0($30) + addq $30, FRAME, $30 + ret +.end _ITM_beginTransaction + + .align 4 + .globl GTM_longjmp + .hidden GTM_longjmp + .ent GTM_longjmp + +GTM_longjmp: + .prologue 0 + ldq $26, 0($16) + ldq $9, 8($16) + ldq $10, 16($16) + ldq $11, 24($16) + + ldq $12, 32($16) + ldq $13, 40($16) + ldq $14, 48($16) + ldq $15, 56($16) + + ldq $1, 64($16) + ldt $f2, 72($16) + ldt $f3, 80($16) + ldt $f4, 88($16) + + ldt $f5, 96($16) + ldt $f6, 104($16) + ldt $f7, 112($16) + ldt $f8, 120($16) + + ldt $f9, 128($16) + mov $17, $0 + mov $1, $30 + ret +.end GTM_longjmp + +.section .note.GNU-stack, "", @progbits Index: libitm/config/alpha/target.h =================================================================== --- libitm/config/alpha/target.h (.../trunk) (revision 0) +++ libitm/config/alpha/target.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,60 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +namespace GTM HIDDEN { + +typedef struct gtm_jmpbuf +{ + unsigned long pc; + unsigned long s[7]; + void *cfa; + unsigned long f[8]; +} gtm_jmpbuf; + +/* Alpha generally uses a fixed page size of 8K. */ +#define PAGE_SIZE 8192 +#define FIXED_PAGE_SIZE 1 + +/* The size of one line in hardware caches (in bytes). */ +#define HW_CACHELINE_SIZE 64 + +static inline void +cpu_relax (void) +{ + __asm volatile ("" : : : "memory"); +} + +static inline void +atomic_read_barrier (void) +{ + __sync_synchronize (); +} + +static inline void +atomic_write_barrier (void) +{ + __asm volatile ("wmb" : : : "memory"); +} + +} // namespace GTM Index: libitm/config/alpha/unaligned.h =================================================================== --- libitm/config/alpha/unaligned.h (.../trunk) (revision 0) +++ libitm/config/alpha/unaligned.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,118 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_ALPHA_UNALIGNED_H +#define LIBITM_ALPHA_UNALIGNED_H 1 + +#define HAVE_ARCH_UNALIGNED_LOAD2_U2 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U4 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U8 1 + +#ifndef __alpha_bwx__ +#define HAVE_ARCH_UNALIGNED_STORE2_U2 1 +#endif +#define HAVE_ARCH_UNALIGNED_STORE2_U4 1 +#define HAVE_ARCH_UNALIGNED_STORE2_U8 1 + +#include "config/generic/unaligned.h" + +namespace GTM HIDDEN { + +template<> +inline uint16_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extwl (v1, ofs) | __builtin_alpha_extwh (v2, ofs); +} + +template<> +inline uint32_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extll (v1, ofs) + __builtin_alpha_extlh (v2, ofs); +} + +template<> +inline uint64_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + + return __builtin_alpha_extql (v1, ofs) | __builtin_alpha_extqh (v2, ofs); +} + +#ifndef __alpha_bwx__ +template<> +inline void +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint16_t val) +{ + uint32_t vl = (uint32_t)val << 24, vh = val >> 8; + + gtm_cacheline::store_mask (&c1->u32[CACHELINE_SIZE / 4 - 1], vl, 4); + gtm_cacheline::store_mask (&c2->u32[0], vh, 1); +} +#endif + +template<> +inline void +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint32_t val) +{ + uint64_t vl = __builtin_alpha_insll (val, ofs); + uint64_t ml = __builtin_alpha_insll (~0u, ofs); + uint64_t vh = __builtin_alpha_inslh (val, ofs); + uint64_t mh = __builtin_alpha_inslh (~0u, ofs); + + gtm_cacheline::store_mask (&c1->u64[CACHELINE_SIZE / 8 - 1], vl, ml); + gtm_cacheline::store_mask (&c2->u64[0], vh, mh); +} + +template<> +inline void +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint64_t val) +{ + uint64_t vl = __builtin_alpha_insql (val, ofs); + uint64_t ml = __builtin_alpha_insql (~0u, ofs); + uint64_t vh = __builtin_alpha_insqh (val, ofs); + uint64_t mh = __builtin_alpha_insqh (~0u, ofs); + + gtm_cacheline::store_mask (&c1->u64[CACHELINE_SIZE / 8 - 1], vl, ml); + gtm_cacheline::store_mask (&c2->u64[0], vh, mh); +} + +} // namespace GTM + +#endif // LIBITM_ALPHA_UNALIGNED_H Index: libitm/config/x86/cacheline.cc =================================================================== --- libitm/config/x86/cacheline.cc (.../trunk) (revision 0) +++ libitm/config/x86/cacheline.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,73 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +uint32_t const gtm_bit_to_byte_mask[16] = +{ + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +#ifdef __SSE2__ +# define MEMBER m128i +#else +# define MEMBER w +#endif + +void +gtm_cacheline::copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m) +{ + if (m == (gtm_cacheline_mask)-1) + { + *d = *s; + return; + } + if (__builtin_expect (m == 0, 0)) + return; + + size_t n = sizeof(d->MEMBER[0]); + for (size_t i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) + store_mask (&d->MEMBER[i], s->MEMBER[i], m); +} + +} // namespace GTM Index: libitm/config/x86/cacheline.h =================================================================== --- libitm/config/x86/cacheline.h (.../trunk) (revision 0) +++ libitm/config/x86/cacheline.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,242 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_CACHELINE_H +#define LIBITM_CACHELINE_H 1 + +// Minimum cacheline size is 32, due to both complex long double and __m256. +// There's no requirement that 64-bit use a 64-byte cacheline size, but do +// so for now to make sure everything is parameterized properly. +#ifdef __x86_64__ +# define CACHELINE_SIZE 64 +#else +# define CACHELINE_SIZE 32 +#endif + +namespace GTM HIDDEN { + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral::type gtm_cacheline_mask; + +extern uint32_t const gtm_bit_to_byte_mask[16]; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + +#ifdef __MMX__ + __m64 m64[CACHELINE_SIZE / sizeof(__m64)]; +#endif +#ifdef __SSE__ + __m128 m128[CACHELINE_SIZE / sizeof(__m128)]; +#endif +#ifdef __SSE2__ + __m128i m128i[CACHELINE_SIZE / sizeof(__m128i)]; +#endif +#ifdef __AVX__ + __m256 m256[CACHELINE_SIZE / sizeof(__m256)]; + __m256i m256i[CACHELINE_SIZE / sizeof(__m256i)]; +#endif + + // Store S into D, but only the bytes specified by M. + static void store_mask (uint32_t *d, uint32_t s, uint8_t m); + static void store_mask (uint64_t *d, uint64_t s, uint8_t m); +#ifdef __SSE2__ + static void store_mask (__m128i *d, __m128i s, uint16_t m); +#endif + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + // When we're emitting non-temporal stores, the normal strong + // ordering of the machine doesn't apply. + static void copy_mask_wb (); + +#if defined(__SSE__) || defined(__AVX__) + // Copy S to D; only bother defining if we can do this more efficiently + // than the compiler-generated default implementation. + gtm_cacheline& operator= (const gtm_cacheline &s); +#endif // SSE, AVX +}; + +inline void +gtm_cacheline::copy_mask_wb () +{ +#ifdef __SSE2__ + _mm_sfence (); +#endif +} + +#if defined(__SSE__) || defined(__AVX__) +inline gtm_cacheline& ALWAYS_INLINE +gtm_cacheline::operator= (const gtm_cacheline & __restrict s) +{ +#ifdef __AVX__ +# define CP m256 +# define TYPE __m256 +#else +# define CP m128 +# define TYPE __m128 +#endif + + TYPE w, x, y, z; + + // ??? Wouldn't it be nice to have a pragma to tell the compiler + // to completely unroll a given loop? + switch (CACHELINE_SIZE / sizeof(TYPE)) + { + case 1: + this->CP[0] = s.CP[0]; + break; + case 2: + x = s.CP[0]; + y = s.CP[1]; + this->CP[0] = x; + this->CP[1] = y; + break; + case 4: + w = s.CP[0]; + x = s.CP[1]; + y = s.CP[2]; + z = s.CP[3]; + this->CP[0] = w; + this->CP[1] = x; + this->CP[2] = y; + this->CP[3] = z; + break; + default: + __builtin_trap (); + } + + return *this; +} +#endif + +// ??? Support masked integer stores more efficiently with an unlocked cmpxchg +// insn. My reasoning is that while we write to locations that we do not wish +// to modify, we do it in an uninterruptable insn, and so we either truely +// write back the original data or the insn fails -- unlike with a +// load/and/or/write sequence which can be interrupted either by a kernel +// task switch or an unlucky cacheline steal by another processor. Avoiding +// the LOCK prefix improves performance by a factor of 10, and we don't need +// the memory barrier semantics implied by that prefix. + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint32_t *d, uint32_t s, uint8_t m) +{ + gtm_cacheline_mask tm = (1 << sizeof (s)) - 1; + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { + gtm_cacheline_mask bm = gtm_bit_to_byte_mask[m & 15]; + gtm_word n, o = *d; + + __asm("\n0:\t" + "mov %[o], %[n]\n\t" + "and %[m], %[n]\n\t" + "or %[s], %[n]\n\t" + "cmpxchg %[n], %[d]\n\t" + "jnz,pn 0b" + : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) + : [s] "r" (s & bm), [m] "r" (~bm)); + } + } +} + +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint64_t *d, uint64_t s, uint8_t m) +{ + gtm_cacheline_mask tm = (1 << sizeof (s)) - 1; + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { +#ifdef __x86_64__ + uint32_t bl = gtm_bit_to_byte_mask[m & 15]; + uint32_t bh = gtm_bit_to_byte_mask[(m >> 4) & 15]; + gtm_cacheline_mask bm = bl | ((gtm_cacheline_mask)bh << 31 << 1); + uint64_t n, o = *d; + __asm("\n0:\t" + "mov %[o], %[n]\n\t" + "and %[m], %[n]\n\t" + "or %[s], %[n]\n\t" + "cmpxchg %[n], %[d]\n\t" + "jnz,pn 0b" + : [d] "+m"(*d), [n] "=&r" (n), [o] "+a"(o) + : [s] "r" (s & bm), [m] "r" (~bm)); +#else + /* ??? While it's possible to perform this operation with + cmpxchg8b, the sequence requires all 7 general registers + and thus cannot be performed with -fPIC. Don't even try. */ + uint32_t *d32 = reinterpret_cast(d); + store_mask (d32, s, m); + store_mask (d32 + 1, s >> 32, m >> 4); +#endif + } + } +} + +#ifdef __SSE2__ +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (__m128i *d, __m128i s, uint16_t m) +{ + if (__builtin_expect (m == 0, 0)) + return; + if (__builtin_expect (m == 0xffff, 1)) + *d = s; + else + { + __m128i bm0, bm1, bm2, bm3; + bm0 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm1 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm2 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm3 = _mm_set_epi32 (0, 0, 0, gtm_bit_to_byte_mask[m & 15]); m >>= 4; + bm0 = _mm_unpacklo_epi32 (bm0, bm1); + bm2 = _mm_unpacklo_epi32 (bm2, bm3); + bm0 = _mm_unpacklo_epi64 (bm0, bm2); + + _mm_maskmoveu_si128 (s, bm0, (char *)d); + } +} +#endif // SSE2 + +} // namespace GTM + +#endif // LIBITM_CACHELINE_H Index: libitm/config/x86/sjlj.S =================================================================== --- libitm/config/x86/sjlj.S (.../trunk) (revision 0) +++ libitm/config/x86/sjlj.S (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,105 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + + .text + .p2align 4 + .globl _ITM_beginTransaction + .type _ITM_beginTransaction, @function + +_ITM_beginTransaction: + .cfi_startproc +#ifdef __x86_64__ + leaq 8(%rsp), %rax + movq (%rsp), %r8 + subq $72, %rsp + .cfi_def_cfa_offset 80 + movq %rax, (%rsp) + movq %r8, 8(%rsp) + movq %rbx, 16(%rsp) + movq %rbp, 24(%rsp) + movq %r12, 32(%rsp) + movq %r13, 40(%rsp) + movq %r14, 48(%rsp) + movq %r15, 56(%rsp) + movq %rsp, %rsi + call GTM_begin_transaction + addq $72, %rsp + .cfi_def_cfa_offset 8 + ret +#else + leal 4(%esp), %ecx + subl $28, %esp + .cfi_def_cfa_offset 32 + movl %ecx, 8(%esp) + movl %ebx, 12(%esp) + movl %esi, 16(%esp) + movl %edi, 20(%esp) + movl %ebp, 24(%esp) + leal 8(%esp), %edx + call GTM_begin_transaction + addl $28, %esp + .cfi_def_cfa_offset 4 + ret +#endif + .cfi_endproc + .size _ITM_beginTransaction, .-_ITM_beginTransaction + + .p2align 4 + .globl GTM_longjmp + .type GTM_longjmp, @function + .hidden GTM_longjmp + +GTM_longjmp: + .cfi_startproc +#ifdef __x86_64__ + movq (%rdi), %rcx + movq 8(%rdi), %rdx + movq 16(%rdi), %rbx + movq 24(%rdi), %rbp + movq 32(%rdi), %r12 + movq 40(%rdi), %r13 + movq 48(%rdi), %r14 + movq 56(%rdi), %r15 + movl %esi, %eax + .cfi_def_cfa %rcx, 0 + .cfi_register %rip, %rdx + movq %rcx, %rsp + jmp *%rdx +#else + xchgl %eax, %edx + movl (%edx), %ecx + movl 4(%edx), %ebx + movl 8(%edx), %esi + movl 12(%edx), %edi + movl 16(%edx), %ebp + movl 20(%edx), %edx + .cfi_def_cfa %ecx, 0 + .cfi_register %eip, %edx + movl %ecx, %esp + jmp *%edx +#endif + .cfi_endproc + .size GTM_longjmp, .-GTM_longjmp + +.section .note.GNU-stack, "", @progbits Index: libitm/config/x86/x86_sse.cc =================================================================== --- libitm/config/x86/x86_sse.cc (.../trunk) (revision 0) +++ libitm/config/x86/x86_sse.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,122 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include "dispatch.h" + +// ??? Use memcpy for now, until we have figured out how to best instantiate +// these loads/stores. +CREATE_DISPATCH_FUNCTIONS_T_MEMCPY(M64, GTM::abi_disp()->, ) +CREATE_DISPATCH_FUNCTIONS_T_MEMCPY(M128, GTM::abi_disp()->, ) + +void ITM_REGPARM +_ITM_LM64 (const _ITM_TYPE_M64 *ptr) +{ + GTM::GTM_LB (ptr, sizeof (*ptr)); +} + +void ITM_REGPARM +_ITM_LM128 (const _ITM_TYPE_M128 *ptr) +{ + GTM::GTM_LB (ptr, sizeof (*ptr)); +} + +// Helpers for re-aligning two 128-bit values. +#ifdef __SSSE3__ +# define INSN0 "movdqa %xmm1, %xmm0" +# define INSN(N) "palignr $" #N ", %xmm1, %xmm0" +# define TABLE_ENT_0 INSN0 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 8\n\t" INSN(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_palignr_table\n\ + .hidden GTM_palignr_table\n\ + .type GTM_palignr_table, @function\n\ +GTM_palignr_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT(8) + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_palignr_table, .-GTM_palignr_table\n\ + .popsection"); + +# undef INSN0 +# undef INSN +# undef TABLE_ENT_0 +# undef TABLE_ENT +#elif defined(__SSE2__) +# define INSNS_8 "punpcklqdq %xmm1, %xmm0" +# define INSNS(N) "psrldq $"#N", %xmm0\n\t" \ + "pslldq $(16-"#N"), %xmm1\n\t" \ + "por %xmm1, %xmm0" +# define TABLE_ENT_0 "ret\n\t" +# define TABLE_ENT_8 ".balign 16\n\t" INSNS_8 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 16\n\t" INSNS(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_pshift_table\n\ + .hidden GTM_pshift_table\n\ + .type GTM_pshift_table, @function\n\ +GTM_pshift_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT_8 + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_pshift_table, .-GTM_pshift_table\n\ + .popsection"); + +# undef INSNS_8 +# undef INSNS +# undef TABLE_ENT_0 +# undef TABLE_ENT_8 +# undef TABLE_ENT +#endif Index: libitm/config/x86/x86_avx.cc =================================================================== --- libitm/config/x86/x86_avx.cc (.../trunk) (revision 0) +++ libitm/config/x86/x86_avx.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,95 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include "dispatch.h" + +// ??? Use memcpy for now, until we have figured out how to best instantiate +// these loads/stores. +CREATE_DISPATCH_FUNCTIONS_T_MEMCPY(M256, GTM::abi_disp()->, ) + +void ITM_REGPARM +_ITM_LM256 (const _ITM_TYPE_M256 *ptr) +{ + GTM::GTM_LB (ptr, sizeof (*ptr)); +} + +// Helpers for re-aligning two 128-bit values. +#ifdef __XOP__ +const __v16qi GTM::GTM_vpperm_shift[16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, + { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 }, + { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }, + { 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }, + { 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }, + { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }, + { 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }, + { 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }, + { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 }, + { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }, + { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }, + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, + { 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }, + { 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 }, + { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }, +}; +#else +# define INSN0 "movdqa %xmm1, %xmm0" +# define INSN(N) "vpalignr $" #N ", %xmm0, %xmm1, %xmm0" +# define TABLE_ENT_0 INSN0 "\n\tret\n\t" +# define TABLE_ENT(N) ".balign 8\n\t" INSN(N) "\n\tret\n\t" + +asm(".pushsection .text\n\ + .balign 16\n\ + .globl GTM_vpalignr_table\n\ + .hidden GTM_vpalignr_table\n\ + .type GTM_vpalignr_table, @function\n\ +GTM_vpalignr_table:\n\t" + TABLE_ENT_0 + TABLE_ENT(1) + TABLE_ENT(2) + TABLE_ENT(3) + TABLE_ENT(4) + TABLE_ENT(5) + TABLE_ENT(6) + TABLE_ENT(7) + TABLE_ENT(8) + TABLE_ENT(9) + TABLE_ENT(10) + TABLE_ENT(11) + TABLE_ENT(12) + TABLE_ENT(13) + TABLE_ENT(14) + TABLE_ENT(15) + ".balign 8\n\ + .size GTM_vpalignr_table, .-GTM_vpalignr_table\n\ + .popsection"); + +# undef INSN0 +# undef INSN +# undef TABLE_ENT_0 +# undef TABLE_ENT +#endif Index: libitm/config/x86/target.h =================================================================== --- libitm/config/x86/target.h (.../trunk) (revision 0) +++ libitm/config/x86/target.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,98 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +namespace GTM HIDDEN { + +#ifdef __x86_64__ +/* ??? This doesn't work for Win64. */ +typedef struct gtm_jmpbuf +{ + void *cfa; + unsigned long rip; + unsigned long rbx; + unsigned long rbp; + unsigned long r12; + unsigned long r13; + unsigned long r14; + unsigned long r15; +} gtm_jmpbuf; +#else +typedef struct gtm_jmpbuf +{ + void *cfa; + unsigned long ebx; + unsigned long esi; + unsigned long edi; + unsigned long ebp; + unsigned long eip; +} gtm_jmpbuf; +#endif + +/* x86 doesn't require strict alignment for the basic types. */ +#define STRICT_ALIGNMENT 0 + +/* x86 uses a fixed page size of 4K. */ +#define PAGE_SIZE 4096 +#define FIXED_PAGE_SIZE 1 + +/* The size of one line in hardware caches (in bytes). */ +#define HW_CACHELINE_SIZE 64 + + +static inline void +cpu_relax (void) +{ + __asm volatile ("rep; nop" : : : "memory"); +} + +static inline void +atomic_read_barrier (void) +{ + /* x86 is a strong memory ordering machine. */ + __asm volatile ("" : : : "memory"); +} + +static inline void +atomic_write_barrier (void) +{ + /* x86 is a strong memory ordering machine. */ + __asm volatile ("" : : : "memory"); +} + +} // namespace GTM + +// We'll be using some of the cpu builtins, and their associated types. +#ifndef __cplusplus +/* ??? It's broken for C++. */ +#include +#else +# ifdef __SSE2__ +# include +# elif defined(__SSE__) +# include +# endif +# ifdef __AVX__ +# include +# endif +#endif Index: libitm/config/x86/unaligned.h =================================================================== --- libitm/config/x86/unaligned.h (.../trunk) (revision 0) +++ libitm/config/x86/unaligned.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,237 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_X86_UNALIGNED_H +#define LIBITM_X86_UNALIGNED_H 1 + +#define HAVE_ARCH_UNALIGNED_LOAD2_U4 1 +#define HAVE_ARCH_UNALIGNED_LOAD2_U8 1 + +#include "config/generic/unaligned.h" + +namespace GTM HIDDEN { + +template<> +inline uint32_t +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint32_t r, lo, hi; + lo = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + hi = c2->u32[0]; + asm("shrd %b2, %1, %0" : "=r"(r) : "r"(hi), "c"((ofs & 3) * 8), "0"(lo)); + return r; +} + +template<> +inline uint64_t +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ +#ifdef __x86_64__ + uint64_t r, lo, hi; + lo = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + hi = c2->u64[0]; + asm("shrd %b2, %1, %0" : "=r"(r) : "r"(hi), "c"((ofs & 3) * 8), "0"(lo)); + return r; +#else + uint32_t v0, v1, v2; + uint64_t r; + + if (ofs < CACHELINE_SIZE - 4) + { + v0 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 2]; + v1 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + v2 = c2->u32[0]; + } + else + { + v0 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + v1 = c2->u32[0]; + v2 = c2->u32[1]; + } + ofs = (ofs & 3) * 8; + asm("shrd %%cl, %[v1], %[v0]; shrd %%cl, %[v2], %[v1]" + : "=A"(r) : "c"(ofs), [v0] "a"(v0), [v1] "d"(v1), [v2] "r"(v2)); + + return r; +#endif +} + +#if defined(__SSE2__) || defined(__MMX__) +template<> +inline _ITM_TYPE_M64 +unaligned_load2<_ITM_TYPE_M64>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ +# ifdef __x86_64__ + __m128i lo = _mm_movpi64_epi64 (c1->m64[CACHELINE_SIZE / 8 - 1]); + __m128i hi = _mm_movpi64_epi64 (c2->m64[0]); + + ofs = (ofs & 7) * 8; + lo = _mm_srli_epi64 (lo, ofs); + hi = _mm_slli_epi64 (hi, 64 - ofs); + lo = lo | hi; + return _mm_movepi64_pi64 (lo); +# else + // On 32-bit we're about to return the result in an MMX register, so go + // ahead and do the computation in that unit, even if SSE2 is available. + __m64 lo = c1->m64[CACHELINE_SIZE / 8 - 1]; + __m64 hi = c2->m64[0]; + + ofs = (ofs & 7) * 8; + lo = _mm_srli_si64 (lo, ofs); + hi = _mm_slli_si64 (hi, 64 - ofs); + return lo | hi; +# endif +} +#endif // SSE2 or MMX + +// The SSE types are strictly aligned. +#ifdef __SSE__ +template<> + struct strict_alignment<_ITM_TYPE_M128> + : public std::true_type + { }; + +// Expand the unaligned SSE move instructions. +template<> +inline _ITM_TYPE_M128 +unaligned_load<_ITM_TYPE_M128>(const void *t) +{ + return _mm_loadu_ps (static_cast(t)); +} + +template<> +inline void +unaligned_store<_ITM_TYPE_M128>(void *t, _ITM_TYPE_M128 val) +{ + _mm_storeu_ps (static_cast(t), val); +} +#endif // SSE + +#ifdef __AVX__ +// The AVX types are strictly aligned when it comes to vmovaps vs vmovups. +template<> + struct strict_alignment<_ITM_TYPE_M256> + : public std::true_type + { }; + +template<> +inline _ITM_TYPE_M256 +unaligned_load<_ITM_TYPE_M256>(const void *t) +{ + return _mm256_loadu_ps (static_cast(t)); +} + +template<> +inline void +unaligned_store<_ITM_TYPE_M256>(void *t, _ITM_TYPE_M256 val) +{ + _mm256_storeu_ps (static_cast(t), val); +} +#endif // AVX + +#ifdef __XOP__ +# define HAVE_ARCH_REALIGN_M128I 1 +extern const __v16qi GTM_vpperm_shift[16]; +inline __m128i +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + return _mm_perm_epi8 (lo, hi, GTM_vpperm_shift[byte_count]); +} +#elif defined(__AVX__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const uint64_t GTM_vpalignr_table[16]; +inline __m128i +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = hi; + register __m128i xmm1 __asm__("xmm1") = lo; + __asm("call *%2" : "+x"(xmm0) : "x"(xmm1), + "r"(>M_vpalignr_table[byte_count])); + return xmm0; +} +#elif defined(__SSSE3__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const uint64_t GTM_palignr_table[16]; +inline __m128i +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = hi; + register __m128i xmm1 __asm__("xmm1") = lo; + __asm("call *%2" : "+x"(xmm0) : "x"(xmm1), + "r"(>M_palignr_table[byte_count])); + return xmm0; +} +#elif defined(__SSE2__) +# define HAVE_ARCH_REALIGN_M128I 1 +extern "C" const char GTM_pshift_table[16 * 16]; +inline __m128i +realign_m128i (__m128i lo, __m128i hi, unsigned byte_count) +{ + register __m128i xmm0 __asm__("xmm0") = lo; + register __m128i xmm1 __asm__("xmm1") = hi; + __asm("call *%2" : "+x"(xmm0), "+x"(xmm1) + : "r"(GTM_pshift_table + byte_count*16)); + return xmm0; +} +#endif // XOP, AVX, SSSE3, SSE2 + +#ifdef HAVE_ARCH_REALIGN_M128I +template<> +inline _ITM_TYPE_M128 +unaligned_load2<_ITM_TYPE_M128>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + return (_ITM_TYPE_M128) + realign_m128i (c1->m128i[CACHELINE_SIZE / 16 - 1], + c2->m128i[0], ofs & 15); +} +#endif // HAVE_ARCH_REALIGN_M128I + +#ifdef __AVX__ +template<> +inline _ITM_TYPE_M256 +unaligned_load2<_ITM_TYPE_M256>(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + __m128i v0, v1; + __m256i r; + + v0 = (__m128i) unaligned_load2<_ITM_TYPE_M128>(c1, c2, ofs); + if (ofs < CACHELINE_SIZE - 16) + v1 = v0, v0 = _mm_loadu_si128 ((const __m128i *) &c1->b[ofs]); + else + v1 = _mm_loadu_si128((const __m128i *)&c2->b[ofs + 16 - CACHELINE_SIZE]); + + r = _mm256_castsi128_si256 ((__m128i)v0); + r = _mm256_insertf128_si256 (r, (__m128i)v1, 1); + return (_ITM_TYPE_M256) r; +} +#endif // AVX + +} // namespace GTM + +#endif // LIBITM_X86_UNALIGNED_H Index: libitm/config/generic/cacheline.cc =================================================================== --- libitm/config/generic/cacheline.cc (.../trunk) (revision 0) +++ libitm/config/generic/cacheline.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,49 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + + +namespace GTM HIDDEN { + +void +gtm_cacheline::copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m) +{ + const size_t n = sizeof (gtm_word); + + if (m == (gtm_cacheline_mask) -1) + { + *d = *s; + return; + } + if (__builtin_expect (m == 0, 0)) + return; + + for (size_t i = 0; i < CACHELINE_SIZE / n; ++i, m >>= n) + store_mask (&d->w[i], s->w[i], m); +} + +} // namespace GTM Index: libitm/config/generic/cacheline.h =================================================================== --- libitm/config/generic/cacheline.h (.../trunk) (revision 0) +++ libitm/config/generic/cacheline.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,107 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_CACHELINE_H +#define LIBITM_CACHELINE_H 1 + +namespace GTM HIDDEN { + +// A cacheline is the smallest unit with which locks are associated. +// The current implementation of the _ITM_[RW] barriers assumes that +// all data types can fit (aligned) within a cachline, which means +// in practice sizeof(complex long double) is the smallest cacheline size. +// It ought to be small enough for efficient manipulation of the +// modification mask, below. +#ifndef CACHELINE_SIZE +# define CACHELINE_SIZE 32 +#endif + +// A gtm_cacheline_mask stores a modified bit for every modified byte +// in the cacheline with which it is associated. +typedef sized_integral::type gtm_cacheline_mask; + +union gtm_cacheline +{ + // Byte access to the cacheline. + unsigned char b[CACHELINE_SIZE] __attribute__((aligned(CACHELINE_SIZE))); + + // Larger sized access to the cacheline. + uint16_t u16[CACHELINE_SIZE / sizeof(uint16_t)]; + uint32_t u32[CACHELINE_SIZE / sizeof(uint32_t)]; + uint64_t u64[CACHELINE_SIZE / sizeof(uint64_t)]; + gtm_word w[CACHELINE_SIZE / sizeof(gtm_word)]; + + // Store S into D, but only the bytes specified by M. + template static void store_mask (T *d, T s, uint8_t m); + + // Copy S to D, but only the bytes specified by M. + static void copy_mask (gtm_cacheline * __restrict d, + const gtm_cacheline * __restrict s, + gtm_cacheline_mask m); + + // A write barrier to emit after (a series of) copy_mask. + // When we're emitting non-temporal stores, the normal strong + // ordering of the machine doesn't apply. + static void copy_mask_wb () { atomic_write_barrier(); } +}; + +template +inline void +gtm_cacheline::store_mask (T *d, T s, uint8_t m) +{ + const uint8_t tm = (1 << sizeof(T)) - 1; + + if (__builtin_expect (m & tm, tm)) + { + if (__builtin_expect ((m & tm) == tm, 1)) + *d = s; + else + { + const int half = sizeof(T) / 2; + typedef typename sized_integral::type half_t; + half_t *dhalf = reinterpret_cast(d); + half_t s1, s2; + + if (WORDS_BIGENDIAN) + s1 = s >> half*8, s2 = s; + else + s1 = s, s2 = s >> half*8; + + store_mask (dhalf, s1, m); + store_mask (dhalf + 1, s2, m >> half); + } + } +} + +template<> +inline void ALWAYS_INLINE +gtm_cacheline::store_mask (uint8_t *d, uint8_t s, uint8_t m) +{ + if (m & 1) + *d = s; +} + +} // namespace GTM + +#endif // LIBITM_CACHELINE_H Index: libitm/config/generic/cachepage.h =================================================================== --- libitm/config/generic/cachepage.h (.../trunk) (revision 0) +++ libitm/config/generic/cachepage.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,77 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_CACHEPAGE_H +#define LIBITM_CACHEPAGE_H 1 + +namespace GTM HIDDEN { + +// A "page" worth of saved cachelines plus modification masks. This +// arrangement is intended to minimize the overhead of alignment. The +// PAGE_SIZE defined by the target must be a constant for this to work, +// which means that this definition may not be the same as the real +// system page size. An additional define of FIXED_PAGE_SIZE by the +// target indicates that PAGE_SIZE exactly matches the system page size. + +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +struct gtm_cacheline_page +{ + static const size_t LINES + = ((PAGE_SIZE - sizeof(gtm_cacheline_page *)) + / (CACHELINE_SIZE + sizeof(gtm_cacheline_mask))); + + gtm_cacheline lines[LINES] __attribute__((aligned(PAGE_SIZE))); + gtm_cacheline_mask masks[LINES]; + gtm_cacheline_page *prev; + + static gtm_cacheline_page * + page_for_line (gtm_cacheline *c) + { + return (gtm_cacheline_page *)((uintptr_t)c & -PAGE_SIZE); + } + + gtm_cacheline_mask * + mask_for_line (gtm_cacheline *c) + { + size_t index = c - &this->lines[0]; + return &this->masks[index]; + } + + static gtm_cacheline_mask * + mask_for_page_line (gtm_cacheline *c) + { + gtm_cacheline_page *p = page_for_line (c); + return p->mask_for_line (c); + } + + static void *operator new (size_t); + static void operator delete (void *); +}; + +} // namespace GTM + +#endif // LIBITM_CACHEPAGE_H Index: libitm/config/generic/tls.cc =================================================================== --- libitm/config/generic/tls.cc (.../trunk) (revision 0) +++ libitm/config/generic/tls.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,76 @@ +/* Copyright (C) 2010 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +// Filter out any updates that overlap the libitm stack, as defined by +// TOP (entry point to library) and BOT (below current function). This +// definition should be fine for all stack-grows-down architectures. + +gtm_cacheline_mask __attribute__((noinline)) +gtm_mask_stack(gtm_cacheline *line, gtm_cacheline_mask mask) +{ + void *top = gtm_thr()->jb.cfa; + void *bot = __builtin_dwarf_cfa(); + + // We must have come through an entry point that set TOP. + assert (top != NULL); + + if (line + 1 < bot) + { + // Since we don't have the REAL stack boundaries for this thread, + // we cannot know if this is a dead write to a stack address below + // the current function or if it is write to another VMA. In either + // case allowing the write should not affect correctness. + } + else if (line >= top) + { + // A valid write to an address in an outer stack frame, or a write + // to another VMA. + } + else + { + uintptr_t diff = (uintptr_t)top - (uintptr_t)line; + if (diff >= CACHELINE_SIZE) + { + // The write is either fully within the proscribed area, or the tail + // of the cacheline overlaps the proscribed area. Assume that all + // stacks are at least cacheline aligned and declare the head of the + // cacheline dead. + mask = 0; + } + else + { + // The head of the cacheline is within the proscribed area, but the + // tail of the cacheline is live. Eliminate the dead writes. + mask &= (gtm_cacheline_mask)-1 << diff; + } + } + + return mask; +} + +} // namespace GTM Index: libitm/config/generic/tls.h =================================================================== --- libitm/config/generic/tls.h (.../trunk) (revision 0) +++ libitm/config/generic/tls.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,65 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_TLS_H +#define LIBITM_TLS_H 1 + +namespace GTM HIDDEN { + +#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP) +// Provides a single place to store all this libraries thread-local data. +struct gtm_thread_tls +{ +#ifndef HAVE_ARCH_GTM_THREAD + // The currently active transaction. Elided if the target provides + // some efficient mechanism for storing this. + gtm_thread *thr; +#endif +#ifndef HAVE_ARCH_GTM_THREAD_DISP + // The dispatch table for the STM implementation currently in use. Elided + // if the target provides some efficient mechanism for storing this. + abi_dispatch *disp; +#endif +}; + +extern __thread gtm_thread_tls _gtm_thr_tls; +#endif + +#ifndef HAVE_ARCH_GTM_THREAD +// If the target does not provide optimized access to the thread-local +// data, simply access the TLS variable defined above. +static inline gtm_thread *gtm_thr() { return &_gtm_thr_tls.thr; } +static inline void set_gtm_thr(gtm_thread *x) { _gtm_thr_tls.thr = x; } +#endif + +#ifndef HAVE_ARCH_GTM_THREAD_DISP +// If the target does not provide optimized access to the currently +// active dispatch table, simply access via GTM_THR. +static inline abi_dispatch * abi_disp() { return _gtm_thr_tls.disp; } +static inline void set_abi_disp(abi_dispatch *x) { _gtm_thr_tls.disp = x; } +#endif + +} // namespace GTM + +#endif // LIBITM_TLS_H Index: libitm/config/generic/unaligned.h =================================================================== --- libitm/config/generic/unaligned.h (.../trunk) (revision 0) +++ libitm/config/generic/unaligned.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,228 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_UNALIGNED_H +#define LIBITM_UNALIGNED_H 1 + +namespace GTM HIDDEN { + +#ifndef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 1 +#endif + +// A type trait for whether type T requires strict alignment. +// The generic types are assumed to all be the same; specializations +// for target-specific types should be done in config/cpu/unaligned.h. +template + struct strict_alignment + : public std::integral_constant + { }; + +// A helper template for accessing an integral type the same size as T +template + struct make_integral + : public sized_integral + { }; + +// A helper class for accessing T as an unaligned value. +template +struct __attribute__((packed)) unaligned_helper + { T x; }; + +// A helper class for view-converting T as an integer. +template +union view_convert_helper +{ + typedef T type; + typedef make_integral itype; + + type t; + itype i; +}; + +// Generate an unaligned load sequence. +// The compiler knows how to do this for any specific type. +template +inline T ALWAYS_INLINE +unaligned_load(const void *t) +{ + typedef unaligned_helper UT; + const UT *ut = reinterpret_cast(t); + return ut->x; +} + +// Generate an unaligned store sequence. +template +inline void ALWAYS_INLINE +unaligned_store(void *t, T val) +{ + typedef unaligned_helper UT; + UT *ut = reinterpret_cast(t); + ut->x = val; +} + +// Generate an unaligned load from two different cachelines. +// It is known that OFS + SIZEOF(T) > CACHELINE_SIZE. +template +inline T ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, const gtm_cacheline *c2, size_t ofs) +{ + size_t left = CACHELINE_SIZE - ofs; + T ret; + + memcpy (&ret, &c1->b[ofs], left); + memcpy ((char *)&ret + ofs, c2, sizeof(T) - left); + + return ret; +} + +// Generate an unaligned store into two different cachelines. +// It is known that OFS + SIZEOF(T) > CACHELINE_SIZE. +template +inline void ALWAYS_INLINE +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, size_t ofs, T val) +{ + size_t left = CACHELINE_SIZE - ofs; + memcpy (&c1->b[ofs], &val, left); + memcpy (c2, (char *)&val + left, sizeof(T) - left); +} + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U2 +template<> +inline uint16_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint16_t v1 = c1->b[CACHELINE_SIZE - 1]; + uint16_t v2 = c2->b[0]; + + if (WORDS_BIGENDIAN) + return v1 << 8 | v2; + else + return v2 << 8 | v1; +} +#endif + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U4 +template<> +inline uint32_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint32_t v1 = c1->u32[CACHELINE_SIZE / sizeof(uint32_t) - 1]; + uint32_t v2 = c2->u32[0]; + int s2 = (ofs & (sizeof(uint32_t) - 1)) * 8; + int s1 = sizeof(uint32_t) * 8 - s2; + + if (WORDS_BIGENDIAN) + return v1 << s2 | v2 >> s1; + else + return v2 << s2 | v1 >> s1; +} +#endif + +#ifndef HAVE_ARCH_UNALIGNED_LOAD2_U8 +template<> +inline uint64_t ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + uint64_t v1 = c1->u64[CACHELINE_SIZE / sizeof(uint64_t) - 1]; + uint64_t v2 = c2->u64[0]; + int s2 = (ofs & (sizeof(uint64_t) - 1)) * 8; + int s1 = sizeof(uint64_t) * 8 - s2; + + if (WORDS_BIGENDIAN) + return v1 << s2 | v2 >> s1; + else + return v2 << s2 | v1 >> s1; +} +#endif + +template<> +inline float ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + typedef view_convert_helper VC; VC vc; + vc.i = unaligned_load2(c1, c2, ofs); + return vc.t; +} + +template<> +inline double ALWAYS_INLINE +unaligned_load2(const gtm_cacheline *c1, + const gtm_cacheline *c2, size_t ofs) +{ + typedef view_convert_helper VC; VC vc; + vc.i = unaligned_load2(c1, c2, ofs); + return vc.t; +} + +#ifndef HAVE_ARCH_UNALIGNED_STORE2_U2 +template<> +inline void ALWAYS_INLINE +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint16_t val) +{ + uint8_t vl = val, vh = val >> 8; + + if (WORDS_BIGENDIAN) + { + c1->b[CACHELINE_SIZE - 1] = vh; + c2->b[0] = vl; + } + else + { + c1->b[CACHELINE_SIZE - 1] = vl; + c2->b[0] = vh; + } +} +#endif + +#if 0 +#ifndef HAVE_ARCH_UNALIGNED_STORE2_U4 +template<> +inline void ALWAYS_INLINE +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, uint32_t val) +{ + // ??? We could reuse the store_mask stuff here. +} +#endif + +template<> +inline void ALWAYS_INLINE +unaligned_store2(gtm_cacheline *c1, gtm_cacheline *c2, + size_t ofs, float val) +{ + typedef view_convert_helper VC; VC vc; + vc.t = val; + unaligned_store2(c1, c2, ofs, vc.i); +} +#endif + +} // namespace GTM + +#endif // LIBITM_UNALIGNED_H Index: libitm/acinclude.m4 =================================================================== --- libitm/acinclude.m4 (.../trunk) (revision 0) +++ libitm/acinclude.m4 (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,343 @@ +dnl ---------------------------------------------------------------------- +dnl This whole bit snagged from libgfortran. + +dnl Check whether the target supports __sync_*_compare_and_swap. +AC_DEFUN([LIBITM_CHECK_SYNC_BUILTINS], [ + AC_CACHE_CHECK([whether the target supports __sync_*_compare_and_swap], + libitm_cv_have_sync_builtins, [ + AC_TRY_LINK([], [int foo, bar; bar = __sync_val_compare_and_swap(&foo, 0, 1);], + libitm_cv_have_sync_builtins=yes, libitm_cv_have_sync_builtins=no)]) + if test $libitm_cv_have_sync_builtins = yes; then + AC_DEFINE(HAVE_SYNC_BUILTINS, 1, + [Define to 1 if the target supports __sync_*_compare_and_swap]) + fi]) + +dnl Check whether the target supports 64-bit __sync_*_compare_and_swap. +AC_DEFUN([LIBITM_CHECK_64BIT_SYNC_BUILTINS], [ + AC_CACHE_CHECK([whether the target supports 64-bit __sync_*_compare_and_swap], + libitm_cv_have_64bit_sync_builtins, [ + AC_TRY_LINK([#include ], + [uint64_t foo, bar; + bar = __sync_val_compare_and_swap(&foo, 0, 1);], + libitm_cv_have_64bit_sync_builtins=yes, + libitm_cv_have_64bit_sync_builtins=no)]) + if test $libitm_cv_have_64bit_sync_builtins = yes; then + AC_DEFINE(HAVE_64BIT_SYNC_BUILTINS, 1, + [Define to 1 if the target supports 64-bit __sync_*_compare_and_swap]) + fi]) + +dnl Check whether the target supports hidden visibility. +AC_DEFUN([LIBITM_CHECK_ATTRIBUTE_VISIBILITY], [ + AC_CACHE_CHECK([whether the target supports hidden visibility], + libitm_cv_have_attribute_visibility, [ + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + AC_TRY_COMPILE([void __attribute__((visibility("hidden"))) foo(void) { }], + [], libitm_cv_have_attribute_visibility=yes, + libitm_cv_have_attribute_visibility=no) + CFLAGS="$save_CFLAGS"]) + if test $libitm_cv_have_attribute_visibility = yes; then + AC_DEFINE(HAVE_ATTRIBUTE_VISIBILITY, 1, + [Define to 1 if the target supports __attribute__((visibility(...))).]) + fi]) + +dnl Check whether the target supports dllexport +AC_DEFUN([LIBITM_CHECK_ATTRIBUTE_DLLEXPORT], [ + AC_CACHE_CHECK([whether the target supports dllexport], + libitm_cv_have_attribute_dllexport, [ + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + AC_TRY_COMPILE([void __attribute__((dllexport)) foo(void) { }], + [], libitm_cv_have_attribute_dllexport=yes, + libitm_cv_have_attribute_dllexport=no) + CFLAGS="$save_CFLAGS"]) + if test $libitm_cv_have_attribute_dllexport = yes; then + AC_DEFINE(HAVE_ATTRIBUTE_DLLEXPORT, 1, + [Define to 1 if the target supports __attribute__((dllexport)).]) + fi]) + +dnl Check whether the target supports symbol aliases. +AC_DEFUN([LIBITM_CHECK_ATTRIBUTE_ALIAS], [ + AC_CACHE_CHECK([whether the target supports symbol aliases], + libitm_cv_have_attribute_alias, [ + AC_TRY_LINK([ +void foo(void) { } +extern void bar(void) __attribute__((alias("foo")));], + [bar();], libitm_cv_have_attribute_alias=yes, libitm_cv_have_attribute_alias=no)]) + if test $libitm_cv_have_attribute_alias = yes; then + AC_DEFINE(HAVE_ATTRIBUTE_ALIAS, 1, + [Define to 1 if the target supports __attribute__((alias(...))).]) + fi]) + +dnl Check how size_t is mangled. +AC_DEFUN([LIBITM_CHECK_SIZE_T_MANGLING], [ + AC_CACHE_CHECK([how size_t is mangled], + libitm_cv_size_t_mangling, [ + AC_TRY_COMPILE([], [extern __SIZE_TYPE__ x; extern unsigned long x;], + [libitm_cv_size_t_mangling=m], [ + AC_TRY_COMPILE([], [extern __SIZE_TYPE__ x; extern unsigned int x;], + [libitm_cv_size_t_mangling=j], [ + AC_TRY_COMPILE([], + [extern __SIZE_TYPE__ x; extern unsigned long long x;], + [libitm_cv_size_t_mangling=y], [ + AC_TRY_COMPILE([], + [extern __SIZE_TYPE__ x; extern unsigned short x;], + [libitm_cv_size_t_mangling=t], + [libitm_cv_size_t_mangling=x]) + ]) + ]) + ]) + ]) + if test $libitm_cv_size_t_mangling = x; then + AC_MSG_ERROR([Unknown underlying type for size_t]) + fi + AC_DEFINE_UNQUOTED(MANGLE_SIZE_T, [$libitm_cv_size_t_mangling], + [Define to the letter to which size_t is mangled.]) +]) + +sinclude(../libtool.m4) +dnl The lines below arrange for aclocal not to bring an installed +dnl libtool.m4 into aclocal.m4, while still arranging for automake to +dnl add a definition of LIBTOOL to Makefile.in. +ifelse(,,,[AC_SUBST(LIBTOOL) +AC_DEFUN([AM_PROG_LIBTOOL]) +AC_DEFUN([AC_LIBTOOL_DLOPEN]) +AC_DEFUN([AC_PROG_LD]) +]) + +dnl ---------------------------------------------------------------------- +dnl This whole bit snagged from libstdc++-v3. + +dnl +dnl LIBITM_ENABLE +dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING) +dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, permit a|b|c) +dnl (FEATURE, DEFAULT, HELP-ARG, HELP-STRING, SHELL-CODE-HANDLER) +dnl +dnl See docs/html/17_intro/configury.html#enable for documentation. +dnl +m4_define([LIBITM_ENABLE],[dnl +m4_define([_g_switch],[--enable-$1])dnl +m4_define([_g_help],[AC_HELP_STRING(_g_switch$3,[$4 @<:@default=$2@:>@])])dnl + AC_ARG_ENABLE($1,_g_help, + m4_bmatch([$5], + [^permit ], + [[ + case "$enableval" in + m4_bpatsubst([$5],[permit ])) ;; + *) AC_MSG_ERROR(Unknown argument to enable/disable $1) ;; + dnl Idea for future: generate a URL pointing to + dnl "onlinedocs/configopts.html#whatever" + esac + ]], + [^$], + [[ + case "$enableval" in + yes|no) ;; + *) AC_MSG_ERROR(Argument to enable/disable $1 must be yes or no) ;; + esac + ]], + [[$5]]), + [enable_]m4_bpatsubst([$1],-,_)[=][$2]) +m4_undefine([_g_switch])dnl +m4_undefine([_g_help])dnl +]) + + +dnl +dnl If GNU ld is in use, check to see if tricky linker opts can be used. If +dnl the native linker is in use, all variables will be defined to something +dnl safe (like an empty string). +dnl +dnl Defines: +dnl SECTION_LDFLAGS='-Wl,--gc-sections' if possible +dnl OPT_LDFLAGS='-Wl,-O1' if possible +dnl LD (as a side effect of testing) +dnl Sets: +dnl with_gnu_ld +dnl libitm_gnu_ld_version (possibly) +dnl +dnl The last will be a single integer, e.g., version 1.23.45.0.67.89 will +dnl set libitm_gnu_ld_version to 12345. Zeros cause problems. +dnl +AC_DEFUN([LIBITM_CHECK_LINKER_FEATURES], [ + # If we're not using GNU ld, then there's no point in even trying these + # tests. Check for that first. We should have already tested for gld + # by now (in libtool), but require it now just to be safe... + test -z "$SECTION_LDFLAGS" && SECTION_LDFLAGS='' + test -z "$OPT_LDFLAGS" && OPT_LDFLAGS='' + AC_REQUIRE([AC_PROG_LD]) + AC_REQUIRE([AC_PROG_AWK]) + + # The name set by libtool depends on the version of libtool. Shame on us + # for depending on an impl detail, but c'est la vie. Older versions used + # ac_cv_prog_gnu_ld, but now it's lt_cv_prog_gnu_ld, and is copied back on + # top of with_gnu_ld (which is also set by --with-gnu-ld, so that actually + # makes sense). We'll test with_gnu_ld everywhere else, so if that isn't + # set (hence we're using an older libtool), then set it. + if test x${with_gnu_ld+set} != xset; then + if test x${ac_cv_prog_gnu_ld+set} != xset; then + # We got through "ac_require(ac_prog_ld)" and still not set? Huh? + with_gnu_ld=no + else + with_gnu_ld=$ac_cv_prog_gnu_ld + fi + fi + + # Start by getting the version number. I think the libtool test already + # does some of this, but throws away the result. + changequote(,) + ldver=`$LD --version 2>/dev/null | head -1 | \ + sed -e 's/GNU ld \(version \)\{0,1\}\(([^)]*) \)\{0,1\}\([0-9.][0-9.]*\).*/\3/'` + changequote([,]) + libitm_gnu_ld_version=`echo $ldver | \ + $AWK -F. '{ if (NF<3) [$]3=0; print ([$]1*100+[$]2)*100+[$]3 }'` + + # Set --gc-sections. + if test "$with_gnu_ld" = "notbroken"; then + # GNU ld it is! Joy and bunny rabbits! + + # All these tests are for C++; save the language and the compiler flags. + # Need to do this so that g++ won't try to link in libstdc++ + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS='-x c++ -Wl,--gc-sections' + + # Check for -Wl,--gc-sections + # XXX This test is broken at the moment, as symbols required for linking + # are now in libsupc++ (not built yet). In addition, this test has + # cored on solaris in the past. In addition, --gc-sections doesn't + # really work at the moment (keeps on discarding used sections, first + # .eh_frame and now some of the glibc sections for iconv). + # Bzzzzt. Thanks for playing, maybe next time. + AC_MSG_CHECKING([for ld that supports -Wl,--gc-sections]) + AC_TRY_RUN([ + int main(void) + { + try { throw 1; } + catch (...) { }; + return 0; + } + ], [ac_sectionLDflags=yes],[ac_sectionLDflags=no], [ac_sectionLDflags=yes]) + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + # this is the suspicious part + CFLAGS='' + fi + if test "$ac_sectionLDflags" = "yes"; then + SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS" + fi + AC_MSG_RESULT($ac_sectionLDflags) + fi + + # Set linker optimization flags. + if test x"$with_gnu_ld" = x"yes"; then + OPT_LDFLAGS="-Wl,-O1 $OPT_LDFLAGS" + fi + + AC_SUBST(SECTION_LDFLAGS) + AC_SUBST(OPT_LDFLAGS) +]) + + +dnl +dnl Add version tags to symbols in shared library (or not), additionally +dnl marking other symbols as private/local (or not). +dnl +dnl --enable-symvers=style adds a version script to the linker call when +dnl creating the shared library. The choice of version script is +dnl controlled by 'style'. +dnl --disable-symvers does not. +dnl + Usage: LIBITM_ENABLE_SYMVERS[(DEFAULT)] +dnl Where DEFAULT is either 'yes' or 'no'. Passing `yes' tries to +dnl choose a default style based on linker characteristics. Passing +dnl 'no' disables versioning. +dnl +AC_DEFUN([LIBITM_ENABLE_SYMVERS], [ + +LIBITM_ENABLE(symvers,yes,[=STYLE], + [enables symbol versioning of the shared library], + [permit yes|no|gnu]) + +# If we never went through the LIBITM_CHECK_LINKER_FEATURES macro, then we +# don't know enough about $LD to do tricks... +AC_REQUIRE([LIBITM_CHECK_LINKER_FEATURES]) +# FIXME The following test is too strict, in theory. +if test $enable_shared = no || + test "x$LD" = x || + test x$libitm_gnu_ld_version = x; then + enable_symvers=no +fi + +# Check to see if libgcc_s exists, indicating that shared libgcc is possible. +if test $enable_symvers != no; then + AC_MSG_CHECKING([for shared libgcc]) + ac_save_CFLAGS="$CFLAGS" + CFLAGS=' -lgcc_s' + AC_TRY_LINK(, [return 0;], libitm_shared_libgcc=yes, libitm_shared_libgcc=no) + CFLAGS="$ac_save_CFLAGS" + if test $libitm_shared_libgcc = no; then + cat > conftest.c <&1 >/dev/null \ + | sed -n 's/^.* -lgcc_s\([^ ]*\) .*$/\1/p'` +changequote([,])dnl + rm -f conftest.c conftest.so + if test x${libitm_libgcc_s_suffix+set} = xset; then + CFLAGS=" -lgcc_s$libitm_libgcc_s_suffix" + AC_TRY_LINK(, [return 0;], libitm_shared_libgcc=yes) + CFLAGS="$ac_save_CFLAGS" + fi + fi + AC_MSG_RESULT($libitm_shared_libgcc) +fi + +# For GNU ld, we need at least this version. The format is described in +# LIBITM_CHECK_LINKER_FEATURES above. +libitm_min_gnu_ld_version=21400 +# XXXXXXXXXXX libitm_gnu_ld_version=21390 + +# Check to see if unspecified "yes" value can win, given results above. +# Change "yes" into either "no" or a style name. +if test $enable_symvers = yes; then + if test $with_gnu_ld = yes && + test $libitm_shared_libgcc = yes; + then + if test $libitm_gnu_ld_version -ge $libitm_min_gnu_ld_version ; then + enable_symvers=gnu + else + # The right tools, the right setup, but too old. Fallbacks? + AC_MSG_WARN(=== Linker version $libitm_gnu_ld_version is too old for) + AC_MSG_WARN(=== full symbol versioning support in this release of GCC.) + AC_MSG_WARN(=== You would need to upgrade your binutils to version) + AC_MSG_WARN(=== $libitm_min_gnu_ld_version or later and rebuild GCC.) + if test $libitm_gnu_ld_version -ge 21200 ; then + # Globbing fix is present, proper block support is not. + dnl AC_MSG_WARN([=== Dude, you are soooo close. Maybe we can fake it.]) + dnl enable_symvers=??? + AC_MSG_WARN([=== Symbol versioning will be disabled.]) + enable_symvers=no + else + # 2.11 or older. + AC_MSG_WARN([=== Symbol versioning will be disabled.]) + enable_symvers=no + fi + fi + else + # just fail for now + AC_MSG_WARN([=== You have requested some kind of symbol versioning, but]) + AC_MSG_WARN([=== either you are not using a supported linker, or you are]) + AC_MSG_WARN([=== not building a shared libgcc_s (which is required).]) + AC_MSG_WARN([=== Symbol versioning will be disabled.]) + enable_symvers=no + fi +fi + +AM_CONDITIONAL(LIBITM_BUILD_VERSIONED_SHLIB, test $enable_symvers != no) +AC_MSG_NOTICE(versioning on shared library symbols is $enable_symvers) +]) Index: libitm/Makefile.am =================================================================== --- libitm/Makefile.am (.../trunk) (revision 0) +++ libitm/Makefile.am (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,98 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS = -I .. -I ../config +SUBDIRS = testsuite + +## May be used by toolexeclibdir. +gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) + +abi_version = -fabi-version=4 + +config_path = @config_path@ +search_path = $(addprefix $(top_srcdir)/config/, $(config_path)) $(top_srcdir) + +fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/finclude +libsubincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include + +vpath % $(strip $(search_path)) + +AM_CPPFLAGS = $(addprefix -I, $(search_path)) +AM_CFLAGS = $(XCFLAGS) +AM_CXXFLAGS = -std=gnu++0x -funwind-tables -fno-exceptions -fno-rtti \ + $(XCFLAGS) $(abi_version) +AM_CCASFLAGS = $(XCFLAGS) +AM_LDFLAGS = $(XLDFLAGS) $(SECTION_LDFLAGS) $(OPT_LDFLAGS) + +toolexeclib_LTLIBRARIES = libitm.la +nodist_toolexeclib_HEADERS = libitm.spec + +if LIBITM_BUILD_VERSIONED_SHLIB +libitm_version_script = -Wl,--version-script,$(top_srcdir)/libitm.map +else +libitm_version_script = +endif +libitm_version_info = -version-info $(libtool_VERSION) + +# Force link with C, not C++. For now, while we're using C++ we don't +# want or need libstdc++. +libitm_la_LINK = $(LINK) +libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \ + -no-undefined + +libitm_la_SOURCES = \ + aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc barrier.cc beginend.cc \ + clone.cc cacheline.cc cachepage.cc eh_cpp.cc local.cc \ + query.cc retry.cc rwlock.cc useraction.cc util.cc \ + sjlj.S tls.cc method-serial.cc method-gl.cc + +if ARCH_X86 +libitm_la_SOURCES += x86_sse.cc x86_avx.cc +x86_sse.lo : XCFLAGS += -msse +x86_avx.lo : XCFLAGS += -mavx +endif + +if ARCH_FUTEX +libitm_la_SOURCES += futex.cc +endif + +# Automake Documentation: +# If your package has Texinfo files in many directories, you can use the +# variable TEXINFO_TEX to tell Automake where to find the canonical +# `texinfo.tex' for your package. The value of this variable should be +# the relative path from the current `Makefile.am' to `texinfo.tex'. +TEXINFO_TEX = ../gcc/doc/include/texinfo.tex + +# Defines info, dvi, pdf and html targets +MAKEINFOFLAGS = -I $(srcdir)/../gcc/doc/include +info_TEXINFOS = libitm.texi + +# AM_CONDITIONAL on configure option --generated-files-in-srcdir +if GENINSRC +STAMP_GENINSRC = stamp-geninsrc +else +STAMP_GENINSRC = +endif + +# AM_CONDITIONAL on configure check ACX_CHECK_PROG_VER([MAKEINFO]) +if BUILD_INFO +STAMP_BUILD_INFO = stamp-build-info +else +STAMP_BUILD_INFO = +endif + + +all-local: $(STAMP_GENINSRC) + +stamp-geninsrc: libitm.info + cp -p $(top_builddir)/libitm.info $(srcdir)/libitm.info + @touch $@ + +libitm.info: $(STAMP_BUILD_INFO) + +stamp-build-info: libitm.texi + $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) -o libitm.info $(srcdir)/libitm.texi + @touch $@ + + +CLEANFILES = $(STAMP_GENINSRC) $(STAMP_BUILD_INFO) libitm.info +MAINTAINERCLEANFILES = $(srcdir)/libitm.info Index: libitm/memcpy.cc =================================================================== --- libitm/memcpy.cc (.../trunk) (revision 0) +++ libitm/memcpy.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,365 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +static void +do_memcpy (uintptr_t idst, uintptr_t isrc, size_t size, + abi_dispatch::lock_type W, abi_dispatch::lock_type R) +{ + abi_dispatch *disp = abi_disp(); + // The position in the destination cacheline where *IDST starts. + uintptr_t dofs = idst & (CACHELINE_SIZE - 1); + // The position in the source cacheline where *ISRC starts. + uintptr_t sofs = isrc & (CACHELINE_SIZE - 1); + const gtm_cacheline *src + = reinterpret_cast(isrc & -CACHELINE_SIZE); + gtm_cacheline *dst + = reinterpret_cast(idst & -CACHELINE_SIZE); + const gtm_cacheline *sline; + abi_dispatch::mask_pair dpair; + + if (size == 0) + return; + + // If both SRC and DST data start at the same position in the cachelines, + // we can easily copy the data in tandem, cacheline by cacheline... + if (dofs == sofs) + { + // We copy the data in three stages: + + // (a) Copy stray bytes at the beginning that are smaller than a + // cacheline. + if (sofs != 0) + { + size_t sleft = CACHELINE_SIZE - sofs; + size_t min = (size <= sleft ? size : sleft); + + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << sofs; + memcpy (&dpair.line->b[sofs], &sline->b[sofs], min); + dst++; + src++; + size -= min; + } + + // (b) Copy subsequent cacheline sized chunks. + while (size >= CACHELINE_SIZE) + { + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask = -1; + *dpair.line = *sline; + dst++; + src++; + size -= CACHELINE_SIZE; + } + + // (c) Copy anything left over. + if (size != 0) + { + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; + memcpy (dpair.line, sline, size); + } + } + // ... otherwise, we must copy the data in disparate hunks using + // temporary storage. + else + { + gtm_cacheline c; + size_t sleft = CACHELINE_SIZE - sofs; + + sline = disp->read_lock(src, R); + + // As above, we copy the data in three stages: + + // (a) Copy stray bytes at the beginning that are smaller than a + // cacheline. + if (dofs != 0) + { + size_t dleft = CACHELINE_SIZE - dofs; + size_t min = (size <= dleft ? size : dleft); + + dpair = disp->write_lock(dst, W); + *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; + + // If what's left in the source cacheline will fit in the + // rest of the destination cacheline, straight up copy it. + if (min <= sleft) + { + memcpy (&dpair.line->b[dofs], &sline->b[sofs], min); + sofs += min; + } + // Otherwise, we need more bits from the source cacheline + // that are available. Piece together what we need from + // contiguous (source) cachelines, into temp space, and copy + // it over. + else + { + memcpy (&c, &sline->b[sofs], sleft); + sline = disp->read_lock(++src, R); + sofs = min - sleft; + memcpy (&c.b[sleft], sline, sofs); + memcpy (&dpair.line->b[dofs], &c, min); + } + sleft = CACHELINE_SIZE - sofs; + + dst++; + size -= min; + } + + // (b) Copy subsequent cacheline sized chunks. + while (size >= CACHELINE_SIZE) + { + // We have a full (destination) cacheline where to put the + // data, but to get to the corresponding cacheline sized + // chunk in the source, we have to piece together two + // contiguous source cachelines. + + memcpy (&c, &sline->b[sofs], sleft); + sline = disp->read_lock(++src, R); + memcpy (&c.b[sleft], sline, sofs); + + dpair = disp->write_lock(dst, W); + *dpair.mask = -1; + *dpair.line = c; + + dst++; + size -= CACHELINE_SIZE; + } + + // (c) Copy anything left over. + if (size != 0) + { + dpair = disp->write_lock(dst, W); + *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; + // If what's left to copy is entirely in the remaining + // source cacheline, do it. + if (size <= sleft) + memcpy (dpair.line, &sline->b[sofs], size); + // Otherwise, piece together the remaining bits, and copy. + else + { + memcpy (&c, &sline->b[sofs], sleft); + sline = disp->read_lock(++src, R); + memcpy (&c.b[sleft], sline, size - sleft); + memcpy (dpair.line, &c, size); + } + } + } +} + +static void +do_memmove (uintptr_t idst, uintptr_t isrc, size_t size, + abi_dispatch::lock_type W, abi_dispatch::lock_type R) +{ + abi_dispatch *disp = abi_disp(); + uintptr_t dleft, sleft, sofs, dofs; + const gtm_cacheline *sline; + abi_dispatch::mask_pair dpair; + + if (size == 0) + return; + + /* The co-aligned memmove below doesn't work for DST == SRC, so filter + that out. It's tempting to just return here, as this is a no-op move. + However, our caller has the right to expect the locks to be acquired + as advertized. */ + if (__builtin_expect (idst == isrc, 0)) + { + /* If the write lock is already acquired, nothing to do. */ + if (W == abi_dispatch::WaW) + return; + /* If the destination is protected, acquire a write lock. */ + if (W != abi_dispatch::NOLOCK) + R = abi_dispatch::RfW; + /* Notice serial mode, where we don't acquire locks at all. */ + if (R == abi_dispatch::NOLOCK) + return; + + idst = isrc + size; + for (isrc &= -CACHELINE_SIZE; isrc < idst; isrc += CACHELINE_SIZE) + disp->read_lock(reinterpret_cast(isrc), R); + return; + } + + /* Fall back to memcpy if the implementation above can handle it. */ + if (idst < isrc || isrc + size <= idst) + { + do_memcpy (idst, isrc, size, W, R); + return; + } + + /* What remains requires a backward copy from the end of the blocks. */ + idst += size; + isrc += size; + dofs = idst & (CACHELINE_SIZE - 1); + sofs = isrc & (CACHELINE_SIZE - 1); + dleft = CACHELINE_SIZE - dofs; + sleft = CACHELINE_SIZE - sofs; + + gtm_cacheline *dst + = reinterpret_cast(idst & -CACHELINE_SIZE); + const gtm_cacheline *src + = reinterpret_cast(isrc & -CACHELINE_SIZE); + if (dofs == 0) + dst--; + if (sofs == 0) + src--; + + if (dofs == sofs) + { + /* Since DST and SRC are co-aligned, and we didn't use the memcpy + optimization above, that implies that SIZE > CACHELINE_SIZE. */ + if (sofs != 0) + { + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask |= ((gtm_cacheline_mask)1 << sleft) - 1; + memcpy (dpair.line, sline, sleft); + dst--; + src--; + size -= sleft; + } + + while (size >= CACHELINE_SIZE) + { + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask = -1; + *dpair.line = *sline; + dst--; + src--; + size -= CACHELINE_SIZE; + } + + if (size != 0) + { + size_t ofs = CACHELINE_SIZE - size; + dpair = disp->write_lock(dst, W); + sline = disp->read_lock(src, R); + *dpair.mask |= (((gtm_cacheline_mask)1 << size) - 1) << ofs; + memcpy (&dpair.line->b[ofs], &sline->b[ofs], size); + } + } + else + { + gtm_cacheline c; + + sline = disp->read_lock(src, R); + if (dofs != 0) + { + size_t min = (size <= dofs ? size : dofs); + + if (min <= sofs) + { + sofs -= min; + memcpy (&c, &sline->b[sofs], min); + } + else + { + size_t min_ofs = min - sofs; + memcpy (&c.b[min_ofs], sline, sofs); + sline = disp->read_lock(--src, R); + sofs = CACHELINE_SIZE - min_ofs; + memcpy (&c, &sline->b[sofs], min_ofs); + } + + dofs = dleft - min; + dpair = disp->write_lock(dst, W); + *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; + memcpy (&dpair.line->b[dofs], &c, min); + + sleft = CACHELINE_SIZE - sofs; + dst--; + size -= min; + } + + while (size >= CACHELINE_SIZE) + { + memcpy (&c.b[sleft], sline, sofs); + sline = disp->read_lock(--src, R); + memcpy (&c, &sline->b[sofs], sleft); + + dpair = disp->write_lock(dst, W); + *dpair.mask = -1; + *dpair.line = c; + + dst--; + size -= CACHELINE_SIZE; + } + + if (size != 0) + { + dofs = CACHELINE_SIZE - size; + + memcpy (&c.b[sleft], sline, sofs); + if (sleft > dofs) + { + sline = disp->read_lock(--src, R); + memcpy (&c, &sline->b[sofs], sleft); + } + + dpair = disp->write_lock(dst, W); + *dpair.mask |= (gtm_cacheline_mask)-1 << dofs; + memcpy (&dpair.line->b[dofs], &c.b[dofs], size); + } + } +} + +#define ITM_MEM_DEF(NAME, READ, WRITE) \ +void ITM_REGPARM _ITM_memcpy##NAME(void *dst, const void *src, size_t size) \ +{ \ + do_memcpy ((uintptr_t)dst, (uintptr_t)src, size, \ + abi_dispatch::WRITE, abi_dispatch::READ); \ +} \ +void ITM_REGPARM _ITM_memmove##NAME(void *dst, const void *src, size_t size) \ +{ \ + do_memmove ((uintptr_t)dst, (uintptr_t)src, size, \ + abi_dispatch::WRITE, abi_dispatch::READ); \ +} + +ITM_MEM_DEF(RnWt, NOLOCK, W) +ITM_MEM_DEF(RnWtaR, NOLOCK, WaR) +ITM_MEM_DEF(RnWtaW, NOLOCK, WaW) + +ITM_MEM_DEF(RtWn, R, NOLOCK) +ITM_MEM_DEF(RtWt, R, W) +ITM_MEM_DEF(RtWtaR, R, WaR) +ITM_MEM_DEF(RtWtaW, R, WaW) + +ITM_MEM_DEF(RtaRWn, RaR, NOLOCK) +ITM_MEM_DEF(RtaRWt, RaR, W) +ITM_MEM_DEF(RtaRWtaR, RaR, WaR) +ITM_MEM_DEF(RtaRWtaW, RaR, WaW) + +ITM_MEM_DEF(RtaWWn, RaW, NOLOCK) +ITM_MEM_DEF(RtaWWt, RaW, W) +ITM_MEM_DEF(RtaWWtaR, RaW, WaR) +ITM_MEM_DEF(RtaWWtaW, RaW, WaW) Index: libitm/local.cc =================================================================== --- libitm/local.cc (.../trunk) (revision 0) +++ libitm/local.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,129 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +struct gtm_undolog_entry +{ + void *addr; + size_t len; + char saved[]; +}; + + +void +gtm_thread::commit_undolog () +{ + size_t i, n = undolog.size(); + + if (n > 0) + { + for (i = 0; i < n; ++i) + free (undolog[i]); + this->undolog.clear(); + } +} + +void +gtm_thread::rollback_undolog (size_t until_size) +{ + size_t i, n = undolog.size(); + + if (n > 0) + { + for (i = n; i-- > until_size; ) + { + gtm_undolog_entry *u = *undolog.pop(); + if (u) + { + memcpy (u->addr, u->saved, u->len); + free (u); + } + } + } +} + +/* Forget any references to PTR in the local log. */ + +void +gtm_thread::drop_references_undolog (const void *ptr, size_t len) +{ + size_t i, n = undolog.size(); + + if (n > 0) + { + for (i = n; i > 0; i--) + { + gtm_undolog_entry *u = undolog[i]; + /* ?? Do we need such granularity, or can we get away with + just comparing PTR and LEN. ?? */ + if ((const char *)u->addr >= (const char *)ptr + && ((const char *)u->addr + u->len <= (const char *)ptr + len)) + { + free (u); + undolog[i] = NULL; + } + } + } +} + +void ITM_REGPARM +GTM_LB (const void *ptr, size_t len) +{ + gtm_thread *tx = gtm_thr(); + gtm_undolog_entry *undo; + + undo = (gtm_undolog_entry *) + xmalloc (sizeof (struct gtm_undolog_entry) + len); + undo->addr = (void *) ptr; + undo->len = len; + + tx->undolog.push()[0] = undo; + + memcpy (undo->saved, ptr, len); +} + +} // namespace GTM + +using namespace GTM; + +void _ITM_LB (const void *ptr, size_t len) ITM_REGPARM + __attribute__((alias("GTM_LB"))); + +#define ITM_LOG_DEF(T) \ +void ITM_REGPARM _ITM_L##T (const _ITM_TYPE_##T *ptr) \ +{ GTM_LB (ptr, sizeof (*ptr)); } + +ITM_LOG_DEF(U1) +ITM_LOG_DEF(U2) +ITM_LOG_DEF(U4) +ITM_LOG_DEF(U8) +ITM_LOG_DEF(F) +ITM_LOG_DEF(D) +ITM_LOG_DEF(E) +ITM_LOG_DEF(CF) +ITM_LOG_DEF(CD) +ITM_LOG_DEF(CE) Index: libitm/libitm_i.h =================================================================== --- libitm/libitm_i.h (.../trunk) (revision 0) +++ libitm/libitm_i.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,302 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* The following are internal implementation functions and definitions. + To distinguish them from those defined by the Intel ABI, they all + begin with GTM/gtm. */ + +#ifndef LIBITM_I_H +#define LIBITM_I_H 1 + +#include "libitm.h" +#include "config.h" + +#include +#include +#include +#include +#include + +#include "common.h" + +namespace GTM HIDDEN { + +using namespace std; + +// A helper template for accessing an unsigned integral of SIZE bytes. +template struct sized_integral { }; +template<> struct sized_integral<1> { typedef uint8_t type; }; +template<> struct sized_integral<2> { typedef uint16_t type; }; +template<> struct sized_integral<4> { typedef uint32_t type; }; +template<> struct sized_integral<8> { typedef uint64_t type; }; + +typedef unsigned int gtm_word __attribute__((mode (word))); + +// These values are given to GTM_restart_transaction and indicate the +// reason for the restart. The reason is used to decide what STM +// implementation should be used during the next iteration. +enum gtm_restart_reason +{ + RESTART_REALLOCATE, + RESTART_LOCKED_READ, + RESTART_LOCKED_WRITE, + RESTART_VALIDATE_READ, + RESTART_VALIDATE_WRITE, + RESTART_VALIDATE_COMMIT, + RESTART_SERIAL_IRR, + RESTART_NOT_READONLY, + RESTART_CLOSED_NESTING, + RESTART_INIT_METHOD_GROUP, + NUM_RESTARTS, + NO_RESTART = NUM_RESTARTS +}; + +} // namespace GTM + +#include "target.h" +#include "rwlock.h" +#include "aatree.h" +#include "cacheline.h" +#include "cachepage.h" +#include "stmlock.h" +#include "dispatch.h" +#include "containers.h" + +namespace GTM HIDDEN { + +// This type is private to alloc.c, but needs to be defined so that +// the template used inside gtm_thread can instantiate. +struct gtm_alloc_action +{ + void (*free_fn)(void *); + bool allocated; +}; + +// This type is private to local.c. +struct gtm_undolog_entry; + +struct gtm_thread; + +// A transaction checkpoint: data that has to saved and restored when doing +// closed nesting. +struct gtm_transaction_cp +{ + gtm_jmpbuf jb; + size_t undolog_size; + aa_tree alloc_actions; + size_t user_actions_size; + _ITM_transactionId_t id; + uint32_t prop; + uint32_t cxa_catch_count; + void *cxa_unthrown; + // We might want to use a different but compatible dispatch method for + // a nested transaction. + abi_dispatch *disp; + // Nesting level of this checkpoint (1 means that this is a checkpoint of + // the outermost transaction). + uint32_t nesting; + + void save(gtm_thread* tx); + void commit(gtm_thread* tx); +}; + +// Contains all thread-specific data required by the entire library. +// This includes all data relevant to a single transaction. Because most +// thread-specific data is about the current transaction, we also refer to +// the transaction-specific parts of gtm_thread as "the transaction" (the +// same applies to names of variables and arguments). +// All but the shared part of this data structure are thread-local data. +// gtm_thread could be split into transaction-specific structures and other +// per-thread data (with those parts then nested in gtm_thread), but this +// would make it harder to later rearrange individual members to optimize data +// accesses. Thus, for now we keep one flat object, and will only split it if +// the code gets too messy. +struct gtm_thread +{ + + struct user_action + { + _ITM_userCommitFunction fn; + void *arg; + bool on_commit; + _ITM_transactionId_t resuming_id; + }; + + // The jump buffer by which GTM_longjmp restarts the transaction. + // This field *must* be at the beginning of the transaction. + gtm_jmpbuf jb; + + // Data used by local.c for the undo log for both local and shared memory. + vector undolog; + + // Data used by alloc.c for the malloc/free undo log. + aa_tree alloc_actions; + + // Data used by useraction.c for the user-defined commit/abort handlers. + vector user_actions; + + // A numerical identifier for this transaction. + _ITM_transactionId_t id; + + // The _ITM_codeProperties of this transaction as given by the compiler. + uint32_t prop; + + // The nesting depth for subsequently started transactions. This variable + // will be set to 1 when starting an outermost transaction. + uint32_t nesting; + + // Set if this transaction owns the serial write lock. + // Can be reset only when restarting the outermost transaction. + static const uint32_t STATE_SERIAL = 0x0001; + // Set if the serial-irrevocable dispatch table is installed. + // Implies that no logging is being done, and abort is not possible. + // Can be reset only when restarting the outermost transaction. + static const uint32_t STATE_IRREVOCABLE = 0x0002; + + // A bitmask of the above. + uint32_t state; + + // In order to reduce cacheline contention on global_tid during + // beginTransaction, we allocate a block of 2**N ids to the thread + // all at once. This number is the next value to be allocated from + // the block, or 0 % 2**N if no such block is allocated. + _ITM_transactionId_t local_tid; + + // Data used by eh_cpp.c for managing exceptions within the transaction. + uint32_t cxa_catch_count; + void *cxa_unthrown; + void *eh_in_flight; + + // Checkpoints for closed nesting. + vector parent_txns; + + // Data used by retry.c for deciding what STM implementation should + // be used for the next iteration of the transaction. + // Only restart_total is reset to zero when the transaction commits, the + // other counters are total values for all previously executed transactions. + uint32_t restart_reason[NUM_RESTARTS]; + uint32_t restart_total; + + // *** The shared part of gtm_thread starts here. *** + // Shared state is on separate cachelines to avoid false sharing with + // thread-local parts of gtm_thread. + + // Points to the next thread in the list of all threads. + gtm_thread *next_thread __attribute__((__aligned__(HW_CACHELINE_SIZE))); + + // If this transaction is inactive, shared_state is ~0. Otherwise, this is + // an active or serial transaction. + gtm_word shared_state; + + // The lock that provides access to serial mode. Non-serialized + // transactions acquire read locks; a serialized transaction aquires + // a write lock. + static gtm_rwlock serial_lock; + + // The head of the list of all threads' transactions. + static gtm_thread *list_of_threads; + // The number of all registered threads. + static unsigned number_of_threads; + + // In alloc.cc + void commit_allocations (bool, aa_tree*); + void record_allocation (void *, void (*)(void *)); + void forget_allocation (void *, void (*)(void *)); + void drop_references_allocations (const void *ptr) + { + this->alloc_actions.erase((uintptr_t) ptr); + } + + // In beginend.cc + void rollback (gtm_transaction_cp *cp = 0, bool aborting = false); + bool trycommit (); + void restart (gtm_restart_reason) ITM_NORETURN; + + gtm_thread(); + ~gtm_thread(); + + static void *operator new(size_t); + static void operator delete(void *); + + // Invoked from assembly language, thus the "asm" specifier on + // the name, avoiding complex name mangling. + static uint32_t begin_transaction(uint32_t, const gtm_jmpbuf *) + __asm__("GTM_begin_transaction") ITM_REGPARM; + + // In eh_cpp.cc + void revert_cpp_exceptions (gtm_transaction_cp *cp = 0); + + // In local.cc + void commit_undolog (void); + void rollback_undolog (size_t until_size = 0); + void drop_references_undolog (const void *, size_t); + + // In retry.cc + // Must be called outside of transactions (i.e., after rollback). + void decide_retry_strategy (gtm_restart_reason); + abi_dispatch* decide_begin_dispatch (uint32_t prop); + void number_of_threads_changed(unsigned previous, unsigned now); + // Must be called from serial mode. Does not call set_abi_disp(). + void set_default_dispatch(abi_dispatch* disp); + + // In method-serial.cc + void serialirr_mode (); + + // In useraction.cc + void rollback_user_actions (size_t until_size = 0); + void commit_user_actions (); +}; + +} // namespace GTM + +#include "tls.h" + +namespace GTM HIDDEN { + +// An unscaled count of the number of times we should spin attempting to +// acquire locks before we block the current thread and defer to the OS. +// This variable isn't used when the standard POSIX lock implementations +// are used. +extern uint64_t gtm_spin_count_var; + +extern "C" uint32_t GTM_longjmp (const gtm_jmpbuf *, uint32_t, uint32_t) + ITM_NORETURN ITM_REGPARM; + +extern "C" void GTM_LB (const void *, size_t) ITM_REGPARM; + +extern void GTM_error (const char *fmt, ...) + __attribute__((format (printf, 1, 2))); +extern void GTM_fatal (const char *fmt, ...) + __attribute__((noreturn, format (printf, 1, 2))); + +extern abi_dispatch *dispatch_serial(); +extern abi_dispatch *dispatch_serialirr(); +extern abi_dispatch *dispatch_serialirr_onwrite(); +extern abi_dispatch *dispatch_gl_wt(); + +extern gtm_cacheline_mask gtm_mask_stack(gtm_cacheline *, gtm_cacheline_mask); + +} // namespace GTM + +#endif // LIBITM_I_H Index: libitm/common.h =================================================================== --- libitm/common.h (.../trunk) (revision 0) +++ libitm/common.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,63 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* The following are internal implementation functions and definitions. + To distinguish them from those defined by the Intel ABI, they all + begin with GTM/gtm. */ + +#ifndef COMMON_H +#define COMMON_H 1 + +#define UNUSED __attribute__((unused)) +#define ALWAYS_INLINE __attribute__((always_inline)) +#ifdef HAVE_ATTRIBUTE_VISIBILITY +# define HIDDEN __attribute__((visibility("hidden"))) +#else +# define HIDDEN +#endif + +#define likely(X) __builtin_expect((X) != 0, 1) +#define unlikely(X) __builtin_expect((X), 0) + +namespace GTM HIDDEN { + +// Locally defined protected allocation functions. +// +// To avoid dependency on libstdc++ new/delete, as well as to not +// interfere with the wrapping of the global new/delete we wrap for +// the user in alloc_cpp.cc, use class-local versions that defer +// to malloc/free. Recall that operator new/delete does not go through +// normal lookup and so we cannot simply inject a version into the +// GTM namespace. +// If separate_cl is true, the allocator will try to return memory that is on +// cache lines that are not shared with any object used by another thread. +extern void * xmalloc (size_t s, bool separate_cl = false) + __attribute__((malloc, nothrow)); +extern void * xrealloc (void *p, size_t s, bool separate_cl = false) + __attribute__((malloc, nothrow)); + +} // namespace GTM + + +#endif // COMMON_H Index: libitm/testsuite/libitm.c/clone-1.c =================================================================== --- libitm/testsuite/libitm.c/clone-1.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/clone-1.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,28 @@ +/* Verify that we can look up tm clone of transaction_callable + and transaction_pure. */ + +#include +#include + +static int x; + +int __attribute__((transaction_pure)) pure(int i) +{ + return i+2; +} + +int __attribute__((transaction_callable)) callable(void) +{ + return ++x; +} + +int main() +{ + if (_ITM_getTMCloneSafe (&pure) != &pure) + abort (); + + if (_ITM_getTMCloneSafe (&callable) == NULL) + abort (); + + return 0; +} Index: libitm/testsuite/libitm.c/dropref-2.c =================================================================== --- libitm/testsuite/libitm.c/dropref-2.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/dropref-2.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,36 @@ +/* { dg-xfail-run-if "unsupported" { *-*-* } } */ +#include +#include + +/* Test that _ITM_dropReferences() forces a commit of given chunk. */ + +unsigned char pp[100]; + +int main() +{ + int i; + + for(i=0; i < 100; ++i) + pp[i]=0x22; + + __transaction_atomic { + for(i=0; i < 100; ++i) + pp[i]=0x33; + + /* This should write-through pp[0..49]... */ + _ITM_dropReferences (pp, 50); + + /* ...while this should revert everything but pp[0..49]. */ + __transaction_cancel; + } + + for(i=0; i < 50; ++i) + if (pp[i] != 0x33) + abort(); + + for(i=50; i < 100; ++i) + if (pp[i] != 0x22) + abort(); + + return 0; +} Index: libitm/testsuite/libitm.c/dropref.c =================================================================== --- libitm/testsuite/libitm.c/dropref.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/dropref.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,12 @@ +/* { dg-xfail-run-if "unsupported" { *-*-* } } */ +#include + +char *pp; + +int main() +{ + __transaction_atomic { + _ITM_dropReferences (pp, 555); + } + return 0; +} Index: libitm/testsuite/libitm.c/reentrant.c =================================================================== --- libitm/testsuite/libitm.c/reentrant.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/reentrant.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,64 @@ +/* Tests that new transactions can be started from both transaction_pure and + transaction_unsafe code. This also requires proper handling of reentrant + nesting in the serial_lock implementation. */ + +#include +#include +#include + +int x = 0; + +int __attribute__((transaction_pure)) pure(int i) +{ + __transaction_atomic { + x++; + } + if (_ITM_inTransaction() == outsideTransaction) + abort(); + return i+1; +} + +int __attribute__((transaction_unsafe)) unsafe(int i) +{ + if (_ITM_inTransaction() != inIrrevocableTransaction) + abort(); + __transaction_atomic { + x++; + } + if (_ITM_inTransaction() != inIrrevocableTransaction) + abort(); + return i+1; +} + +static void *thread (void *dummy __attribute__((unused))) +{ + __transaction_atomic { + pure(1); + } + __transaction_relaxed { + unsafe(1); + } + return 0; +} + +int main() +{ + pthread_t pt; + int r = 0; + + __transaction_atomic { + r += pure(1) + x; + } + __transaction_relaxed { + r += unsafe(1) + x; + } + if (r != 7) + abort(); + + // Spawn a new thread to check that the serial lock is not held. + pthread_create(&pt, NULL, thread, NULL); + pthread_join(pt, NULL); + if (x != 4) + abort(); + return 0; +} Index: libitm/testsuite/libitm.c/cancel.c =================================================================== --- libitm/testsuite/libitm.c/cancel.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/cancel.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,55 @@ +#include +#include + +unsigned char pp[100]; + +void __attribute((transaction_may_cancel_outer,noinline)) cancel1() +{ + __transaction_cancel [[outer]]; +} + +int a, b; + +int main() +{ + a = b = 0; + + __transaction_atomic { + a = 1; + __transaction_atomic { + b = 1; + __transaction_cancel; + } + } + if (a != 1 || b != 0) + abort(); + if (_ITM_inTransaction() != outsideTransaction) + abort(); + + __transaction_atomic [[outer]] { + a = 2; + __transaction_atomic { + b = 2; + __transaction_cancel [[outer]]; + } + } + if (a != 1 || b != 0) + abort(); + if (_ITM_inTransaction() != outsideTransaction) + abort(); + + __transaction_atomic [[outer]] { + a = 2; + __transaction_atomic { + b = 2; + __transaction_cancel [[outer]]; + cancel1(); + } + } + if (a != 1 || b != 0) + abort(); + if (_ITM_inTransaction() != outsideTransaction) + abort(); + + return 0; +} Index: libitm/testsuite/libitm.c/simple-1.c =================================================================== --- libitm/testsuite/libitm.c/simple-1.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/simple-1.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,24 @@ +/* Verify that two sequential runs of a transaction will complete and + produce correct results. An early test of the library did in fact + leave things in an inconsistent state following the commit of the + first transaction. */ + +#include + +static int x; + +static void start (void) +{ + __transaction_atomic { x++; } +} + +int main() +{ + start (); + start (); + + if (x != 2) + abort (); + + return 0; +} Index: libitm/testsuite/libitm.c/memcpy-1.c =================================================================== --- libitm/testsuite/libitm.c/memcpy-1.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/memcpy-1.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,139 @@ +/* Verify memcpy operation. */ + +#include +#include +#include +#include +#include + +#define BEG_TRANSACTION \ + _ITM_beginTransaction (pr_instrumentedCode | pr_hasNoAbort \ + | pr_hasNoIrrevocable) +#define END_TRANSACTION \ + _ITM_commitTransaction () + +#define MEMCPY _ITM_memcpyRtWt + +static unsigned char *buf1, *buf2; +static size_t bufsize, page_size; +static int fail; + +static void +do_test (size_t align1, size_t align2, size_t len) +{ + size_t i, j; + unsigned char *s1, *s2; + unsigned char c1, c2; + + if (align1 + len >= bufsize) + return; + if (align2 + len >= bufsize) + return; + + c1 = random () >> 8; + c2 = random () >> 8; + memset (buf1, c1, bufsize); + memset (buf2, c2, bufsize); + + s1 = buf1 + align1; + s2 = buf2 + align2; + + for (i = 0, j = 1; i < len; i++, j += 23) + s1[i] = (j == c1 ? j + 1 : j); + + BEG_TRANSACTION; + MEMCPY (s2, s1, len); + END_TRANSACTION; + + if (memcmp (s1, s2, len) != 0) + { + printf ("Wrong result: dalign %zd salign %zd len %zd\n", + align2, align1, len); + fail = 1; + return; + } + + for (i = (align2 > 64 ? align2 - 64 : 0); i < align2; ++i) + if (buf2[i] != c2) + { + printf ("Garbage before: ofs %zd\n", i); + fail = 1; + break; + } + for (i = align2 + len, j = i+64 < bufsize ? i+64 : bufsize; i < j; ++i) + if (buf2[i] != c2) + { + printf ("Garbage after: ofs %zd\n", i); + fail = 1; + break; + } +} + +int main() +{ + size_t i, j; + + page_size = getpagesize (); + bufsize = 2 * page_size; + + buf1 = mmap (NULL, bufsize + 2*page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buf1 == MAP_FAILED) + return 1; + buf2 = mmap (NULL, bufsize + 2*page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buf2 == MAP_FAILED) + return 1; + + if (mprotect (buf1, page_size, PROT_NONE)) + return 1; + buf1 += page_size; + if (mprotect (buf1 + bufsize, page_size, PROT_NONE)) + return 1; + + if (mprotect (buf2, page_size, PROT_NONE)) + return 1; + buf2 += page_size; + if (mprotect (buf2 + bufsize, page_size, PROT_NONE)) + return 1; + + for (i = 0; i < 18; ++i) + { + size_t len = 1 << i; + + do_test (0, 0, len); + do_test (i, 0, len); + do_test (0, i, len); + do_test (i, i, len); + + do_test (0, bufsize - len, len); + do_test (bufsize - len, 0, len); + do_test (i, bufsize - len, len); + do_test (bufsize - len, i, len); + } + + for (i = 0; i < 32; ++i) + { + do_test (i, 0, i); + do_test (0, i, i); + do_test (i, i, i); + + for (j = 0; j < 32; ++j) + { + do_test (i, bufsize - i - j, i); + do_test (bufsize - i - j, i, i); + } + } + + for (i = 3; i < 32; ++i) + { + if ((i & (i - 1)) == 0) + continue; + do_test (0, 0, 16 * i); + do_test (i, 0, 16 * i); + do_test (0, i, 16 * i); + do_test (i, i, 16 * i); + } + + return fail; +} Index: libitm/testsuite/libitm.c/memset-1.c =================================================================== --- libitm/testsuite/libitm.c/memset-1.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/memset-1.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,102 @@ +/* Verify memcpy operation. */ + +#include +#include +#include +#include +#include + +#define BEG_TRANSACTION \ + _ITM_beginTransaction (pr_instrumentedCode | pr_hasNoAbort \ + | pr_hasNoIrrevocable) +#define END_TRANSACTION \ + _ITM_commitTransaction () + +#define MEMSET _ITM_memsetW + +static unsigned char *buf; +static size_t bufsize, page_size; +static int fail; + +static void +do_test (size_t align, size_t len) +{ + size_t i, j; + unsigned char c1, c2; + + if (align + len >= bufsize) + return; + + c1 = random () >> 8; + c2 = random () >> 8; + if (c1 == c2) + c1++; + memset (buf, c1, bufsize); + + BEG_TRANSACTION; + MEMSET (buf + align, c2, len); + END_TRANSACTION; + + i = (align > 64 ? align - 64 : 0); + for (; i < align; ++i) + if (buf[i] != c1) + { + printf ("Garbage before: ofs %zd\n", i); + fail = 1; + break; + } + for (; i < align + len; ++i) + if (buf[i] != c2) + { + printf ("Wrong result: ofs %zd\n", i); + fail = 1; + break; + } + for (j = i + 64 < bufsize ? i + 64 : bufsize; i < j; ++i) + if (buf[i] != c1) + { + printf ("Garbage after: ofs %zd\n", i); + fail = 1; + break; + } +} + +int main() +{ + size_t i, j; + + page_size = getpagesize (); + bufsize = 2 * page_size; + + buf = mmap (NULL, bufsize + 2*page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buf == MAP_FAILED) + return 1; + + if (mprotect (buf, page_size, PROT_NONE)) + return 1; + buf += page_size; + if (mprotect (buf + bufsize, page_size, PROT_NONE)) + return 1; + + for (i = 0; i < 18; ++i) + { + size_t len = 1 << i; + do_test (0, len); + do_test (bufsize - len, len); + } + + for (i = 0; i < 32; ++i) + for (j = 0; j < 32; ++j) + do_test (j, i); + + for (i = 3; i < 32; ++i) + { + if ((i & (i - 1)) == 0) + continue; + do_test (0, 16 * i); + do_test (i, 16 * i); + } + + return fail; +} Index: libitm/testsuite/libitm.c/notx.c =================================================================== --- libitm/testsuite/libitm.c/notx.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/notx.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,33 @@ +/* These tests all check whether initialization happens properly even if no + transaction has been used in the current thread yet. */ +#include +#include +#include + +static void *test1 (void *dummy __attribute__((unused))) +{ + if (_ITM_inTransaction() != outsideTransaction) + abort(); + return NULL; +} + +static void *test2 (void *dummy __attribute__((unused))) +{ + if (_ITM_getTransactionId() != _ITM_noTransactionId) + abort(); + return NULL; +} + + +int main() +{ + pthread_t thread; + + pthread_create(&thread, NULL, test1, NULL); + pthread_join(thread, NULL); + + pthread_create(&thread, NULL, test2, NULL); + pthread_join(thread, NULL); + + return 0; +} Index: libitm/testsuite/libitm.c/simple-2.c =================================================================== --- libitm/testsuite/libitm.c/simple-2.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/simple-2.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,29 @@ +/* Simplest test involving real threads. Verify we get the correct answer. */ + +#include +#include + +static int x; + +static void *start (void *dummy __attribute__((unused))) +{ + __transaction_atomic { x++; } + return NULL; +} + +int main() +{ + pthread_t p[10]; + int i; + + for (i = 0; i < 10; ++i) + pthread_create (p+i, NULL, start, NULL); + + for (i = 0; i < 10; ++i) + pthread_join (p[i], NULL); + + if (x != 10) + abort (); + + return 0; +} Index: libitm/testsuite/libitm.c/c.exp =================================================================== --- libitm/testsuite/libitm.c/c.exp (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/c.exp (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,30 @@ +if [info exists lang_library_path] then { + unset lang_library_path + unset lang_link_flags +} +if [info exists lang_test_file] then { + unset lang_test_file +} + +load_lib libitm-dg.exp + +# If a testcase doesn't have special options, use these. +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS "-O2" +} + +# Initialize dg. +dg-init + +# Gather a list of all tests. +set tests [lsort [find $srcdir/$subdir *.c]] + +set ld_library_path $always_ld_library_path +append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST] +set_ld_library_path_env_vars + +# Main loop. +dg-runtest $tests "" $DEFAULT_CFLAGS + +# All done. +dg-finish Index: libitm/testsuite/libitm.c/txrelease.c =================================================================== --- libitm/testsuite/libitm.c/txrelease.c (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c/txrelease.c (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,47 @@ +/* This test triggers execution of the code that releases per-thread + transaction data when a thread exists, potentially repeatedly. However, + we currently cannot check whether the data has indeed been released. */ + +#include +#include +#include + +static int round = 0; +static pthread_key_t key; + +static void +thread_exit_handler(void *dummy __attribute__((unused))) +{ + if (round == 0) + abort(); + if (round == 1) + { + // ??? It would be good if we could check here that the transaction has + // indeed been released. + __transaction_atomic { round++; } + if (pthread_setspecific(key, &round)) + abort(); + } + // ??? It would be good if we could check here that the transaction has + // indeed been released (again). +} + +static void *thread (void *dummy __attribute__((unused))) +{ + if (pthread_key_create(&key, thread_exit_handler)) + abort(); + if (pthread_setspecific(key, &round)) + abort(); + __transaction_atomic { round++; } + return NULL; +} + +int main() +{ + pthread_t pt; + pthread_create(&pt, NULL, thread, NULL); + pthread_join(pt, NULL); + if (round != 2) + abort(); + return 0; +} Index: libitm/testsuite/Makefile.in =================================================================== --- libitm/testsuite/Makefile.in (.../trunk) (revision 0) +++ libitm/testsuite/Makefile.in (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,441 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = testsuite +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ + $(top_srcdir)/../config/depstand.m4 \ + $(top_srcdir)/../config/enable.m4 \ + $(top_srcdir)/../config/futex.m4 \ + $(top_srcdir)/../config/lead-dot.m4 \ + $(top_srcdir)/../config/mmap.m4 \ + $(top_srcdir)/../config/multi.m4 \ + $(top_srcdir)/../config/override.m4 \ + $(top_srcdir)/../config/stdint.m4 \ + $(top_srcdir)/../config/tls.m4 $(top_srcdir)/../ltoptions.m4 \ + $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ + $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +DEJATOOL = $(PACKAGE) +RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FC = @FC@ +FCFLAGS = @FCFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPT_LDFLAGS = @OPT_LDFLAGS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +SECTION_LDFLAGS = @SECTION_LDFLAGS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +XCFLAGS = @XCFLAGS@ +XLDFLAGS = @XLDFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_FC = @ac_ct_FC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +config_path = @config_path@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_shared = @enable_shared@ +enable_static = @enable_static@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libtool_VERSION = @libtool_VERSION@ +link_itm = @link_itm@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +multi_basedir = @multi_basedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +toolexecdir = @toolexecdir@ +toolexeclibdir = @toolexeclibdir@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign dejagnu + +# May be used by various substitution variables. +gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) +EXPECT = $(shell if test -f $(top_builddir)/../expect/expect; then \ + echo $(top_builddir)/../expect/expect; else echo expect; fi) + +_RUNTEST = $(shell if test -f $(top_srcdir)/../dejagnu/runtest; then \ + echo $(top_srcdir)/../dejagnu/runtest; else echo runtest; fi) + +RUNTEST = "$(_RUNTEST) $(AM_RUNTESTFLAGS)" +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign testsuite/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +check-DEJAGNU: site.exp + srcdir=`$(am__cd) $(srcdir) && pwd`; export srcdir; \ + EXPECT=$(EXPECT); export EXPECT; \ + runtest=$(RUNTEST); \ + if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \ + exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \ + if $$runtest $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \ + then :; else exit_status=1; fi; \ + done; \ + else echo "WARNING: could not find \`runtest'" 1>&2; :;\ + fi; \ + exit $$exit_status +site.exp: Makefile + @echo 'Making a new site.exp file...' + @echo '## these variables are automatically generated by make ##' >site.tmp + @echo '# Do not edit here. If you wish to override these values' >>site.tmp + @echo '# edit the last section' >>site.tmp + @echo 'set srcdir $(srcdir)' >>site.tmp + @echo "set objdir `pwd`" >>site.tmp + @echo 'set build_alias "$(build_alias)"' >>site.tmp + @echo 'set build_triplet $(build_triplet)' >>site.tmp + @echo 'set host_alias "$(host_alias)"' >>site.tmp + @echo 'set host_triplet $(host_triplet)' >>site.tmp + @echo 'set target_alias "$(target_alias)"' >>site.tmp + @echo 'set target_triplet $(target_triplet)' >>site.tmp + @echo '## All variables above are generated by configure. Do Not Edit ##' >>site.tmp + @test ! -f site.exp || \ + sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp + @-rm -f site.bak + @test ! -f site.exp || mv site.exp site.bak + @mv site.tmp site.exp + +distclean-DEJAGNU: + -rm -f site.exp site.bak + -l='$(DEJATOOL)'; for tool in $$l; do \ + rm -f $$tool.sum $$tool.log; \ + done + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-DEJAGNU distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: all all-am check check-DEJAGNU check-am clean clean-generic \ + clean-libtool distclean distclean-DEJAGNU distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: libitm/testsuite/config/default.exp =================================================================== --- libitm/testsuite/config/default.exp (.../trunk) (revision 0) +++ libitm/testsuite/config/default.exp (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,17 @@ +# Copyright (C) 1997 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +load_lib "standard.exp" Index: libitm/testsuite/lib/libitm-dg.exp =================================================================== --- libitm/testsuite/lib/libitm-dg.exp (.../trunk) (revision 0) +++ libitm/testsuite/lib/libitm-dg.exp (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,7 @@ +proc libitm-dg-test { prog do_what extra_tool_flags } { + return [gcc-dg-test-1 libitm_target_compile $prog $do_what $extra_tool_flags] +} + +proc libitm-dg-prune { system text } { + return [gcc-dg-prune $system $text] +} Index: libitm/testsuite/lib/libitm.exp =================================================================== --- libitm/testsuite/lib/libitm.exp (.../trunk) (revision 0) +++ libitm/testsuite/lib/libitm.exp (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,216 @@ +# Damn dejagnu for not having proper library search paths for load_lib. +# We have to explicitly load everything that gcc-dg.exp wants to load. + +proc load_gcc_lib { filename } { + global srcdir loaded_libs + + load_file $srcdir/../../gcc/testsuite/lib/$filename + set loaded_libs($filename) "" +} + +load_lib dg.exp +load_gcc_lib file-format.exp +load_gcc_lib target-supports.exp +load_gcc_lib target-supports-dg.exp +load_gcc_lib scanasm.exp +load_gcc_lib scandump.exp +load_gcc_lib scanrtl.exp +load_gcc_lib scantree.exp +load_gcc_lib scanipa.exp +load_gcc_lib prune.exp +load_gcc_lib target-libpath.exp +load_gcc_lib wrapper.exp +load_gcc_lib gcc-defs.exp +load_gcc_lib torture-options.exp +load_gcc_lib timeout.exp +load_gcc_lib timeout-dg.exp +load_gcc_lib gcc-dg.exp +load_gcc_lib gfortran-dg.exp + +set dg-do-what-default run + +# +# GCC_UNDER_TEST is the compiler under test. +# + +set libitm_compile_options "" + +# +# libitm_init +# + +if [info exists TOOL_OPTIONS] { + set multilibs [get_multilibs $TOOL_OPTIONS] +} else { + set multilibs [get_multilibs] +} + +proc libitm_init { args } { + global srcdir blddir objdir tool_root_dir + global libitm_initialized + global tmpdir + global blddir + global gluefile wrap_flags + global ALWAYS_CFLAGS + global CFLAGS + global TOOL_EXECUTABLE TOOL_OPTIONS + global GCC_UNDER_TEST + global TESTING_IN_BUILD_TREE + global target_triplet + global always_ld_library_path + + set blddir [lookfor_file [get_multilibs] libitm] + + # We set LC_ALL and LANG to C so that we get the same error + # messages as expected. + setenv LC_ALL C + setenv LANG C + + if ![info exists GCC_UNDER_TEST] then { + if [info exists TOOL_EXECUTABLE] { + set GCC_UNDER_TEST $TOOL_EXECUTABLE + } else { + set GCC_UNDER_TEST "[find_gcc]" + } + } + + if ![info exists tmpdir] { + set tmpdir "/tmp" + } + + if [info exists gluefile] { + unset gluefile + } + + if {![info exists CFLAGS]} { + set CFLAGS "" + } + + # Locate libgcc.a so we don't need to account for different values of + # SHLIB_EXT on different platforms + set gccdir [lookfor_file $tool_root_dir gcc/libgcc.a] + if {$gccdir != ""} { + set gccdir [file dirname $gccdir] + } + + # Compute what needs to be put into LD_LIBRARY_PATH + set always_ld_library_path ".:${blddir}/.libs" + + # Compute what needs to be added to the existing LD_LIBRARY_PATH. + if {$gccdir != ""} { + # Add AIX pthread directory first. + if { [llength [glob -nocomplain ${gccdir}/pthread/libgcc_s*.a]] >= 1 } { + append always_ld_library_path ":${gccdir}/pthread" + } + append always_ld_library_path ":${gccdir}" + set compiler [lindex $GCC_UNDER_TEST 0] + + if { [is_remote host] == 0 && [which $compiler] != 0 } { + foreach i "[exec $compiler --print-multi-lib]" { + set mldir "" + regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir + set mldir [string trimright $mldir "\;@"] + if { "$mldir" == "." } { + continue + } + if { [llength [glob -nocomplain ${gccdir}/${mldir}/libgcc_s*.so.*]] >= 1 } { + append always_ld_library_path ":${gccdir}/${mldir}" + } + } + } + } + + set ALWAYS_CFLAGS "" + if { $blddir != "" } { + lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/" + lappend ALWAYS_CFLAGS "additional_flags=-I${blddir}" + lappend ALWAYS_CFLAGS "ldflags=-L${blddir}/.libs" + } + lappend ALWAYS_CFLAGS "additional_flags=-I${srcdir}/.." + lappend ALWAYS_CFLAGS "ldflags=-litm" + + # We use atomic operations in the testcases to validate results. + if { ([istarget i?86-*-*] || [istarget x86_64-*-*]) + && [check_effective_target_ilp32] } { + lappend ALWAYS_CFLAGS "additional_flags=-march=i486" + } + + if [istarget *-*-darwin*] { + lappend ALWAYS_CFLAGS "additional_flags=-shared-libgcc" + } + + if [istarget sparc*-*-*] { + lappend ALWAYS_CFLAGS "additional_flags=-mcpu=v9" + } + + if [info exists TOOL_OPTIONS] { + lappend ALWAYS_CFLAGS "additional_flags=$TOOL_OPTIONS" + } + + # Make sure that lines are not wrapped. That can confuse the + # error-message parsing machinery. + lappend ALWAYS_CFLAGS "additional_flags=-fmessage-length=0" + + # Turn on transactional memory support. + lappend ALWAYS_CFLAGS "additional_flags=-fgnu-tm" +} + +# +# libitm_target_compile -- compile a source file +# + +proc libitm_target_compile { source dest type options } { + global blddir + global libitm_compile_options + global gluefile wrap_flags + global ALWAYS_CFLAGS + global GCC_UNDER_TEST + global lang_test_file + global lang_library_path + global lang_link_flags + + if { [info exists lang_test_file] } { + if { $blddir != "" } { + lappend options "ldflags=-L${blddir}/${lang_library_path}" + } + lappend options "ldflags=${lang_link_flags}" + } + + if { [target_info needs_status_wrapper] != "" && [info exists gluefile] } { + lappend options "libs=${gluefile}" + lappend options "ldflags=${wrap_flags}" + } + + lappend options "additional_flags=[libio_include_flags]" + lappend options "timeout=[timeout_value]" + lappend options "compiler=$GCC_UNDER_TEST" + + set options [concat $libitm_compile_options $options] + + if [info exists ALWAYS_CFLAGS] { + set options [concat "$ALWAYS_CFLAGS" $options] + } + + set options [dg-additional-files-options $options $source] + + set result [target_compile $source $dest $type $options] + + return $result +} + +proc libitm_option_help { } { + send_user " --additional_options,OPTIONS\t\tUse OPTIONS to compile the testcase files. OPTIONS should be comma-separated.\n" +} + +proc libitm_option_proc { option } { + if [regexp "^--additional_options," $option] { + global libitm_compile_options + regsub "--additional_options," $option "" option + foreach x [split $option ","] { + lappend libitm_compile_options "additional_flags=$x" + } + return 1 + } else { + return 0 + } +} Index: libitm/testsuite/libitm.c++/static_ctor.C =================================================================== --- libitm/testsuite/libitm.c++/static_ctor.C (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c++/static_ctor.C (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,38 @@ +// { dg-do run } +/* Tests static constructors inside of transactional code. */ + +#include +#include + +int f(int x) __attribute__((noinline,transaction_safe)); +int f(int x) +{ + static int y = x; + return y*x; +} + +static void *thread (void *) +{ + int bar; + __transaction_atomic { bar = f(10); } + if (bar != 100) + abort(); + return 0; +} + +int main() +{ + int bar; + + // First, initialize y in another thread. + pthread_t pt; + pthread_create(&pt, NULL, thread, NULL); + pthread_join(pt, NULL); + + // Now y should already be initialized. + __transaction_atomic { bar = f(20); } + if (bar != 200) + abort(); + + return 0; +} Index: libitm/testsuite/libitm.c++/dropref.C =================================================================== --- libitm/testsuite/libitm.c++/dropref.C (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c++/dropref.C (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,12 @@ +/* { dg-xfail-run-if "unsupported" { *-*-* } } */ +#include + +char *pp; + +int main() +{ + __transaction_atomic { + _ITM_dropReferences (pp, 555); + } + return 0; +} Index: libitm/testsuite/libitm.c++/c++.exp =================================================================== --- libitm/testsuite/libitm.c++/c++.exp (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c++/c++.exp (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,60 @@ +load_lib libitm-dg.exp + +global shlib_ext + +set shlib_ext [get_shlib_extension] +set lang_link_flags "-lstdc++" +set lang_test_file_found 0 +set lang_library_path "../libstdc++-v3/src/.libs" + +# Initialize dg. +dg-init + +set blddir [lookfor_file [get_multilibs] libgomp] + + +if { $blddir != "" } { + # Look for a static libstdc++ first. + if [file exists "${blddir}/${lang_library_path}/libstdc++.a"] { + set lang_test_file "${lang_library_path}/libstdc++.a" + set lang_test_file_found 1 + # We may have a shared only build, so look for a shared libstdc++. + } elseif [file exists "${blddir}/${lang_library_path}/libstdc++.${shlib_ext}"] { + set lang_test_file "${lang_library_path}/libstdc++.${shlib_ext}" + set lang_test_file_found 1 + } else { + puts "No libstdc++ library found, will not execute c++ tests" + } +} elseif { [info exists GXX_UNDER_TEST] } { + set lang_test_file_found 1 + # Needs to exist for libgomp.exp. + set lang_test_file "" +} else { + puts "GXX_UNDER_TEST not defined, will not execute c++ tests" +} + +if { $lang_test_file_found } { + # Gather a list of all tests. + set tests [lsort [glob -nocomplain $srcdir/$subdir/*.C]] + + if { $blddir != "" } { + set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}" + } else { + set ld_library_path "$always_ld_library_path" + } + append ld_library_path [gcc-set-multilib-library-path $GCC_UNDER_TEST] + set_ld_library_path_env_vars + + set flags_file "${blddir}/../libstdc++-v3/scripts/testsuite_flags" + if { [file exists $flags_file] } { + set libstdcxx_includes [exec sh $flags_file --build-includes] + } else { + set libstdcxx_includes "" + } + + # Main loop. + gfortran-dg-runtest $tests $libstdcxx_includes +} + +# All done. +dg-finish Index: libitm/testsuite/libitm.c++/eh-1.C =================================================================== --- libitm/testsuite/libitm.c++/eh-1.C (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c++/eh-1.C (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,36 @@ +// { dg-do run } + +extern "C" void abort (); + +int dothrow; +int g; + +static void f1() +{ + g++; + if (dothrow) + throw 1; +} + +static void f2() +{ + __transaction_atomic { + f1(); + } +} + +int main() +{ + dothrow = 0; + f2(); + + dothrow = 1; + try { + f2(); + } catch (...) { + } + + if (g != 2) + abort (); + return 0; +} Index: libitm/testsuite/libitm.c++/throwdown.C =================================================================== --- libitm/testsuite/libitm.c++/throwdown.C (.../trunk) (revision 0) +++ libitm/testsuite/libitm.c++/throwdown.C (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,13 @@ +// { dg-do compile } + +#include + +static void throwit() { + throw 1; +} + +void tranfunc() { + __transaction_atomic { + throwit(); + } +} Index: libitm/testsuite/Makefile.am =================================================================== --- libitm/testsuite/Makefile.am (.../trunk) (revision 0) +++ libitm/testsuite/Makefile.am (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,13 @@ +## Process this file with automake to produce Makefile.in. + +AUTOMAKE_OPTIONS = foreign dejagnu + +# May be used by various substitution variables. +gcc_version := $(shell cat $(top_srcdir)/../gcc/BASE-VER) + +EXPECT = $(shell if test -f $(top_builddir)/../expect/expect; then \ + echo $(top_builddir)/../expect/expect; else echo expect; fi) + +_RUNTEST = $(shell if test -f $(top_srcdir)/../dejagnu/runtest; then \ + echo $(top_srcdir)/../dejagnu/runtest; else echo runtest; fi) +RUNTEST = "$(_RUNTEST) $(AM_RUNTESTFLAGS)"