This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] 4/n: trans-mem: runtime


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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include "libitm_i.h"
+#include <stdarg.h>
+#include <stdio.h>
+
+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 <pthread.h>
+ 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 <pthread.h>
+ 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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+/* 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 <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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<uintptr_t, gtm_alloc_action>* 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<commit_cb_data *>(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<uintptr_t, gtm_alloc_action>* 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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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<gtm_cacheline *>(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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <typename V> static V load(const V* addr, ls_modifier mod)
+ {
+ return *addr;
+ }
+ template <typename V> 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 <typename V> static V load(const V* addr, ls_modifier mod)
+ {
+ return *addr;
+ }
+ template <typename V> 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 <typename V> 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<serialirr_dispatch *>(&o_serialirr_dispatch);
+}
+
+abi_dispatch *
+GTM::dispatch_serial ()
+{
+ return const_cast<serial_dispatch *>(&o_serial_dispatch);
+}
+
+abi_dispatch *
+GTM::dispatch_serialirr_onwrite ()
+{
+ return
+ const_cast<serialirr_onwrite_dispatch *>(&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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include "unaligned.h"
+
+namespace {
+
+using namespace GTM;
+
+template<typename T>
+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<uintptr_t>(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<const gtm_cacheline *>(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<const T *>(&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<T>::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<T>::value
+ && iofs + sizeof(T) <= CACHELINE_SIZE, 1))
+ {
+ do_unaligned_load:
+ return unaligned_load<T>(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<T>::value)
+ goto do_normal_load;
+ else
+ goto do_unaligned_load;
+ }
+ else
+ {
+ // Otherwise, ask the backend to load from two different
+ // cachelines.
+ return unaligned_load2<T>(line, line2, iofs);
+ }
+ }
+}
+
+template<typename T>
+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<uintptr_t>(ptr);
+ uintptr_t iline = iptr & -CACHELINE_SIZE;
+ uintptr_t iofs = iptr & (CACHELINE_SIZE - 1);
+ gtm_cacheline *pline = reinterpret_cast<gtm_cacheline *>(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<T *>(&pair.line->b[iofs]);
+
+ if (__builtin_expect (strict_alignment<T>::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<T>::value
+ && iofs + sizeof(val) <= CACHELINE_SIZE, 1))
+ {
+ *pair.mask |= m << iofs;
+ do_unaligned_store:
+ unaligned_store<T>(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<T>::value)
+ goto do_normal_store;
+ else
+ goto do_unaligned_store;
+ }
+ else
+ unaligned_store2<T>(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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#include "libitm_i.h"
+#include <pthread.h>
+
+
+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<uintptr_t, gtm_alloc_action>();
+
+ // 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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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<user_action>::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 <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <malloc.h> 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 <memory.h> 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 <semaphore.h> header file. */
+#undef HAVE_SEMAPHORE_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> 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 <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> 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 <unistd.h> 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 <string.h> and <strings.h>. */
+#undef STRING_WITH_STRINGS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#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 <rth@redhat.com>.
+
+ 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
+ <http://www.gnu.org/licenses/>. */
+
+#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 (&gtm_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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]