From patchwork Thu Nov 3 17:50:48 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 123477 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id BD831B6F67 for ; Fri, 4 Nov 2011 04:51:39 +1100 (EST) Received: (qmail 3592 invoked by alias); 3 Nov 2011 17:51:34 -0000 Received: (qmail 3543 invoked by uid 22791); 3 Nov 2011 17:51:18 -0000 X-SWARE-Spam-Status: No, hits=-2.7 required=5.0 tests=AWL, BAYES_50, KAM_STOCKTIP, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS, TW_CX, TW_FN, TW_GJ, TW_LR, TW_TN, TW_VF X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 03 Nov 2011 17:50:49 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id pA3HonWm018765 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Thu, 3 Nov 2011 13:50:49 -0400 Received: from houston.quesejoda.com (vpn-236-154.phx2.redhat.com [10.3.236.154]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id pA3HomSp018382 for ; Thu, 3 Nov 2011 13:50:48 -0400 Message-ID: <4EB2D478.2080208@redhat.com> Date: Thu, 03 Nov 2011 12:50:48 -0500 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:7.0) Gecko/20110927 Thunderbird/7.0 MIME-Version: 1.0 To: gcc-patches Subject: [patch] 4/n: trans-mem: runtime Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org + +#endif // LIBITM_STMLOCK_H Index: libitm/util.cc =================================================================== --- libitm/util.cc (.../trunk) (revision 0) +++ libitm/util.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,85 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include +#include + +namespace GTM HIDDEN { + +static void +gtm_verror (const char *fmt, va_list list) +{ + fputs ("\nlibitm: ", stderr); + vfprintf (stderr, fmt, list); + fputc ('\n', stderr); +} + +void +GTM_error (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); +} + +void +GTM_fatal (const char *fmt, ...) +{ + va_list list; + + va_start (list, fmt); + gtm_verror (fmt, list); + va_end (list); + + exit (EXIT_FAILURE); +} + +void * +xmalloc (size_t size, bool separate_cl) +{ + // TODO Use posix_memalign if separate_cl is true, or some other allocation + // method that will avoid sharing cache lines with data used by other + // threads. + void *r = malloc (size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +void * +xrealloc (void *old, size_t size, bool separate_cl) +{ + // TODO Use posix_memalign if separate_cl is true, or some other allocation + // method that will avoid sharing cache lines with data used by other + // threads. + void *r = realloc (old, size); + if (r == 0) + GTM_fatal ("Out of memory allocating %lu bytes", (unsigned long) size); + return r; +} + +} // namespace GTM Index: libitm/configure.ac =================================================================== --- libitm/configure.ac (.../trunk) (revision 0) +++ libitm/configure.ac (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,262 @@ +# Process this file with autoreconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([GNU TM Runtime Library], 1.0,,[libitm]) +AC_CONFIG_HEADER(config.h) + +# ------- +# Options +# ------- + +AC_MSG_CHECKING([for --enable-version-specific-runtime-libs]) +LIBITM_ENABLE(version-specific-runtime-libs, no, , + [Specify that runtime libraries should be installed in a compiler-specific directory], + permit yes|no) +AC_MSG_RESULT($enable_version_specific_runtime_libs) + +# We would like our source tree to be readonly. However when releases or +# pre-releases are generated, the flex/bison generated files as well as the +# various formats of manuals need to be included along with the rest of the +# sources. Therefore we have --enable-generated-files-in-srcdir to do +# just that. +AC_MSG_CHECKING([for --enable-generated-files-in-srcdir]) +LIBITM_ENABLE(generated-files-in-srcdir, no, , + [put copies of generated files in source dir intended for creating source + tarballs for users without texinfo bison or flex.], + permit yes|no) +AC_MSG_RESULT($enable_generated_files_in_srcdir) +AM_CONDITIONAL(GENINSRC, test "$enable_generated_files_in_srcdir" = yes) + + +# ------- +# ------- + +# Gets build, host, target, *_vendor, *_cpu, *_os, etc. +# +# You will slowly go insane if you do not grok the following fact: when +# building this library, the top-level /target/ becomes the library's /host/. +# +# configure then causes --target to default to --host, exactly like any +# other package using autoconf. Therefore, 'target' and 'host' will +# always be the same. This makes sense both for native and cross compilers +# just think about it for a little while. :-) +# +# Also, if this library is being configured as part of a cross compiler, the +# top-level configure script will pass the "real" host as $with_cross_host. +# +# Do not delete or change the following two lines. For why, see +# http://gcc.gnu.org/ml/libstdc++/2003-07/msg00451.html +AC_CANONICAL_SYSTEM +target_alias=${target_alias-$host_alias} + +# Sets up automake. Must come after AC_CANONICAL_SYSTEM. Each of the +# following is magically included in AUTOMAKE_OPTIONS in each Makefile.am. +# 1.9.0: minimum required version +# no-define: PACKAGE and VERSION will not be #define'd in config.h (a bunch +# of other PACKAGE_* variables will, however, and there's nothing +# we can do about that; they come from AC_INIT). +# foreign: we don't follow the normal rules for GNU packages (no COPYING +# file in the top srcdir, etc, etc), so stop complaining. +# -Wall: turns on all automake warnings... +# -Wno-portability: ...except this one, since GNU make is required. +# -Wno-override: ... and this one, since we do want this in testsuite. +AM_INIT_AUTOMAKE([1.9.0 foreign -Wall -Wno-portability -Wno-override]) +AM_ENABLE_MULTILIB(, ..) + +# Calculate toolexeclibdir +# Also toolexecdir, though it's only used in toolexeclibdir +case ${enable_version_specific_runtime_libs} in + yes) + # Need the gcc compiler version to know where to install libraries + # and header files if --enable-version-specific-runtime-libs option + # is selected. + toolexecdir='$(libdir)/gcc/$(target_alias)' + toolexeclibdir='$(toolexecdir)/$(gcc_version)$(MULTISUBDIR)' + ;; + no) + if test -n "$with_cross_host" && + test x"$with_cross_host" != x"no"; then + # Install a library built with a cross compiler in tooldir, not libdir. + toolexecdir='$(exec_prefix)/$(target_alias)' + toolexeclibdir='$(toolexecdir)/lib' + else + toolexecdir='$(libdir)/gcc-lib/$(target_alias)' + toolexeclibdir='$(libdir)' + fi + multi_os_directory=`$CC -print-multi-os-directory` + case $multi_os_directory in + .) ;; # Avoid trailing /. + *) toolexeclibdir=$toolexeclibdir/$multi_os_directory ;; + esac + ;; +esac +AC_SUBST(toolexecdir) +AC_SUBST(toolexeclibdir) + +# Check the compiler. +# The same as in boehm-gc and libstdc++. Have to borrow it from there. +# We must force CC to /not/ be precious variables; otherwise +# the wrong, non-multilib-adjusted value will be used in multilibs. +# As a side effect, we have to subst CFLAGS ourselves. + +m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +AC_PROG_CC +AC_PROG_CXX +AM_PROG_AS +m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +AC_SUBST(CFLAGS) + +# In order to override CFLAGS_FOR_TARGET, all of our special flags go +# in XCFLAGS. But we need them in CFLAGS during configury. So put them +# in both places for now and restore CFLAGS at the end of config. +save_CFLAGS="$CFLAGS" + +# Find other programs we need. +AC_CHECK_TOOL(AR, ar) +AC_CHECK_TOOL(NM, nm) +AC_CHECK_TOOL(RANLIB, ranlib, ranlib-not-found-in-path-error) +AC_PATH_PROG(PERL, perl, perl-not-found-in-path-error) +AC_PROG_MAKE_SET +AC_PROG_INSTALL + +# See if makeinfo has been installed and is modern enough +# that we can use it. +ACX_CHECK_PROG_VER([MAKEINFO], [makeinfo], [--version], + [GNU texinfo.* \([0-9][0-9.]*\)], + [4.[4-9]*|4.[1-9][0-9]*|[5-9]*|[1-9][0-9]*]) +AM_CONDITIONAL(BUILD_INFO, test $gcc_cv_prog_makeinfo_modern = "yes") + + +# Configure libtool +AM_PROG_LIBTOOL +AC_SUBST(enable_shared) +AC_SUBST(enable_static) + +AM_MAINTAINER_MODE + +# We need gfortran to compile parts of the library +# We can't use AC_PROG_FC because it expects a fully working gfortran. +#AC_PROG_FC(gfortran) +FC="$GFORTRAN" +AC_PROG_FC(gfortran) +FCFLAGS="$FCFLAGS -Wall" + +# For libtool versioning info, format is CURRENT:REVISION:AGE +libtool_VERSION=1:0:0 +AC_SUBST(libtool_VERSION) + +# Check header files. +AC_STDC_HEADERS +AC_HEADER_TIME +ACX_HEADER_STRING +AC_CHECK_HEADERS(unistd.h semaphore.h sys/time.h malloc.h) + +GCC_HEADER_STDINT(gstdint.h) + +GCC_AC_FUNC_MMAP_BLACKLIST + +AC_C_BIGENDIAN +# I don't like the default behaviour of WORDS_BIGENDIAN undefined for LE. +AH_BOTTOM( +[#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif]) + +# Check to see if -pthread or -lpthread is needed. Prefer the former. +# In case the pthread.h system header is not found, this test will fail. +XPCFLAGS="" +CFLAGS="$CFLAGS -pthread" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include + void *g(void *d) { return NULL; }], + [pthread_t t; pthread_create(&t,NULL,g,NULL);])], + [XPCFLAGS=" -Wc,-pthread"], + [CFLAGS="$save_CFLAGS" LIBS="-lpthread $LIBS" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include + void *g(void *d) { return NULL; }], + [pthread_t t; pthread_create(&t,NULL,g,NULL);])], + [], + [AC_MSG_ERROR([Pthreads are required to build libitm])])]) + +# Check for functions needed. +AC_CHECK_FUNCS(strtoull memalign posix_memalign) + +# Check for broken semaphore implementation on darwin. +# sem_init returns: sem_init error: Function not implemented. +case "$host" in + *-darwin*) + AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1, + Define if the POSIX Semaphores do not work on your system.) + ;; +esac + +GCC_LINUX_FUTEX(:) + +# See if we support thread-local storage. +GCC_CHECK_TLS + +# See what sort of export controls are availible. +LIBITM_CHECK_ATTRIBUTE_VISIBILITY +LIBITM_CHECK_ATTRIBUTE_DLLEXPORT +LIBITM_CHECK_ATTRIBUTE_ALIAS +LIBITM_ENABLE_SYMVERS + +if test $enable_symvers = gnu; then + AC_DEFINE(LIBITM_GNU_SYMBOL_VERSIONING, 1, + [Define to 1 if GNU symbol versioning is used for libitm.]) +fi + +# Determine the proper ABI type for size_t. +LIBITM_CHECK_SIZE_T_MANGLING + +# Get target configury. +. ${srcdir}/configure.tgt +CFLAGS="$save_CFLAGS $XCFLAGS" + +# Check for __sync_val_compare_and_swap, but only after the target has +# had a chance to set XCFLAGS. +LIBITM_CHECK_SYNC_BUILTINS +LIBITM_CHECK_64BIT_SYNC_BUILTINS + +# Cleanup and exit. +CFLAGS="$save_CFLAGS" +AC_CACHE_SAVE + +# Add -Wall -Werror if we are using GCC. +if test "x$GCC" = "xyes"; then + XCFLAGS="$XCFLAGS -Wall -Werror" +fi + +XCFLAGS="$XCFLAGS $XPCFLAGS" + +AC_SUBST(config_path) +AC_SUBST(XCFLAGS) +AC_SUBST(XLDFLAGS) + +if test ${multilib} = yes; then + multilib_arg="--enable-multilib" +else + multilib_arg= +fi + +# Set up the set of libraries that we need to link against for libitm. +# Note that the GOMP_SELF_SPEC in gcc.c will force -pthread for -fopenmp, +# which will force linkage against -lpthread (or equivalent for the system). +# That's not 100% ideal, but about the best we can do easily. +if test $enable_shared = yes; then + link_itm="-litm %{static: $LIBS}" +else + link_itm="-litm $LIBS" +fi +AC_SUBST(link_itm) + +AM_CONDITIONAL([ARCH_X86], [test "$ARCH" = x86]) +AM_CONDITIONAL([ARCH_FUTEX], [test $enable_linux_futex = yes]) + +AC_CONFIG_FILES(Makefile testsuite/Makefile libitm.spec) +AC_OUTPUT Index: libitm/libitm.h =================================================================== --- libitm/libitm.h (.../trunk) (revision 0) +++ libitm/libitm.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,288 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* The external interface of this library follows the specification described + in version 1 of http://www.intel.com/some/path/here.pdf. */ + +#ifndef LIBITM_H +#define LIBITM_H 1 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __i386__ +/* Only for 32-bit x86. */ +# define ITM_REGPARM __attribute__((regparm(2))) +#else +# define ITM_REGPARM +#endif + +#define ITM_NORETURN __attribute__((noreturn)) +#define ITM_PURE __attribute__((transaction_pure)) + +/* The following are externally visible definitions and functions, though + only very few of these should be called by user code. */ + +/* Values used as arguments to abort. */ +typedef enum { + userAbort = 1, + userRetry = 2, + TMConflict= 4, + exceptionBlockAbort = 8, + outerAbort = 16 +} _ITM_abortReason; + +/* Arguments to changeTransactionMode */ +typedef enum +{ + modeSerialIrrevocable, +} _ITM_transactionState; + +/* Results from inTransaction */ +typedef enum +{ + outsideTransaction = 0, /* So "if (inTransaction(td))" works */ + inRetryableTransaction, + inIrrevocableTransaction +} _ITM_howExecuting; + +/* Values to describe properties of code, passed in to beginTransaction */ +typedef enum +{ + pr_instrumentedCode = 0x0001, + pr_uninstrumentedCode = 0x0002, + pr_multiwayCode = pr_instrumentedCode | pr_uninstrumentedCode, + /* Called pr_hasNoXMMUpdate in the Intel document, used for + avoiding vector register save/restore for any target. */ + pr_hasNoVectorUpdate = 0x0004, + pr_hasNoAbort = 0x0008, + /* Not present in the Intel document, used for avoiding + floating point register save/restore for any target. */ + pr_hasNoFloatUpdate = 0x0010, + pr_hasNoIrrevocable = 0x0020, + pr_doesGoIrrevocable = 0x0040, + pr_aWBarriersOmitted = 0x0100, + pr_RaRBarriersOmitted = 0x0200, + pr_undoLogCode = 0x0400, + pr_preferUninstrumented = 0x0800, + /* Exception blocks are not used nor supported. */ + pr_exceptionBlock = 0x1000, + pr_hasElse = 0x2000, + pr_readOnly = 0x4000, + pr_hasNoSimpleReads = 0x400000 +} _ITM_codeProperties; + +/* Result from startTransaction that describes what actions to take. */ +typedef enum +{ + a_runInstrumentedCode = 0x01, + a_runUninstrumentedCode = 0x02, + a_saveLiveVariables = 0x04, + a_restoreLiveVariables = 0x08, + a_abortTransaction = 0x10, +} _ITM_actions; + +typedef struct +{ + uint32_t reserved_1; + uint32_t flags; + uint32_t reserved_2; + uint32_t reserved_3; + const char *psource; +} _ITM_srcLocation; + +typedef void (* _ITM_userUndoFunction)(void *); +typedef void (* _ITM_userCommitFunction) (void *); + +#define _ITM_VERSION "0.90 (Feb 29 2008)" +#define _ITM_VERSION_NO 90 + +extern int _ITM_versionCompatible (int) ITM_REGPARM; +extern const char * _ITM_libraryVersion (void) ITM_REGPARM; + +void _ITM_error(const _ITM_srcLocation *, int errorCode) + ITM_REGPARM ITM_NORETURN; + +extern _ITM_howExecuting _ITM_inTransaction(void) ITM_REGPARM; + +typedef uint64_t _ITM_transactionId_t; /* Transaction identifier */ +#define _ITM_noTransactionId 1 /* Id for non-transactional code. */ + +extern _ITM_transactionId_t _ITM_getTransactionId(void) ITM_REGPARM; + +extern uint32_t _ITM_beginTransaction(uint32_t, ...) ITM_REGPARM; + +extern void _ITM_abortTransaction(_ITM_abortReason) ITM_REGPARM ITM_NORETURN; + +extern void _ITM_commitTransaction (void) ITM_REGPARM; + +extern void _ITM_changeTransactionMode (_ITM_transactionState) ITM_REGPARM; + +extern void _ITM_addUserCommitAction(_ITM_userCommitFunction, + _ITM_transactionId_t, void *) ITM_REGPARM; + +extern void _ITM_addUserUndoAction(_ITM_userUndoFunction, void *) ITM_REGPARM; + +extern int _ITM_getThreadnum(void) ITM_REGPARM; + +extern void _ITM_dropReferences (void *, size_t) ITM_REGPARM ITM_PURE; + +extern void *_ITM_malloc (size_t) + __attribute__((__malloc__)) ITM_PURE; + +extern void *_ITM_calloc (size_t, size_t) + __attribute__((__malloc__)) ITM_PURE; + +extern void _ITM_free (void *) ITM_PURE; + + +/* The following typedefs exist to make the macro expansions below work + properly. They are not part of any API. */ +typedef uint8_t _ITM_TYPE_U1; +typedef uint16_t _ITM_TYPE_U2; +typedef uint32_t _ITM_TYPE_U4; +typedef uint64_t _ITM_TYPE_U8; +typedef float _ITM_TYPE_F; +typedef double _ITM_TYPE_D; +typedef long double _ITM_TYPE_E; +typedef float _Complex _ITM_TYPE_CF; +typedef double _Complex _ITM_TYPE_CD; +typedef long double _Complex _ITM_TYPE_CE; + +#define ITM_BARRIERS(T) \ + extern _ITM_TYPE_##T _ITM_R##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RaR##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RaW##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern _ITM_TYPE_##T _ITM_RfW##T(const _ITM_TYPE_##T *) ITM_REGPARM; \ + extern void _ITM_W##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; \ + extern void _ITM_WaR##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; \ + extern void _ITM_WaW##T (_ITM_TYPE_##T *, _ITM_TYPE_##T) ITM_REGPARM; + +ITM_BARRIERS(U1) +ITM_BARRIERS(U2) +ITM_BARRIERS(U4) +ITM_BARRIERS(U8) +ITM_BARRIERS(F) +ITM_BARRIERS(D) +ITM_BARRIERS(E) +ITM_BARRIERS(CF) +ITM_BARRIERS(CD) +ITM_BARRIERS(CE) + +#define ITM_LOG(T) \ + extern void _ITM_L##T (const _ITM_TYPE_##T *) ITM_REGPARM; + +ITM_LOG(U1) +ITM_LOG(U2) +ITM_LOG(U4) +ITM_LOG(U8) +ITM_LOG(F) +ITM_LOG(D) +ITM_LOG(E) +ITM_LOG(CF) +ITM_LOG(CD) +ITM_LOG(CE) + +#if defined(__i386__) || defined(__x86_64__) +# ifdef __MMX__ + typedef int _ITM_TYPE_M64 __attribute__((vector_size(8), may_alias)); + ITM_BARRIERS(M64) + ITM_LOG(M64) +# endif +# ifdef __SSE__ + typedef float _ITM_TYPE_M128 __attribute__((vector_size(16), may_alias)); + ITM_BARRIERS(M128) + ITM_LOG(M128) +# endif +# ifdef __AVX__ + typedef float _ITM_TYPE_M256 __attribute__((vector_size(32), may_alias)); + ITM_BARRIERS(M256) + ITM_LOG(M256) +# endif +#endif /* i386 */ + +#undef ITM_BARRIERS +#undef ITM_LOG + +extern void _ITM_LB (const void *, size_t) ITM_REGPARM; + +extern void _ITM_memcpyRnWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRnWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRnWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaRWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memcpyRtaWWtaW(void *, const void *, size_t) ITM_REGPARM; + +extern void _ITM_memmoveRnWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRnWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRnWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaRWtaW(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWn(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWt(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWtaR(void *, const void *, size_t) ITM_REGPARM; +extern void _ITM_memmoveRtaWWtaW(void *, const void *, size_t) ITM_REGPARM; + +extern void _ITM_memsetW(void *, int, size_t) ITM_REGPARM; +extern void _ITM_memsetWaR(void *, int, size_t) ITM_REGPARM; +extern void _ITM_memsetWaW(void *, int, size_t) ITM_REGPARM; + +// ??? These are not yet in the official spec; still work-in-progress. + +extern void *_ITM_getTMCloneOrIrrevocable (void *) ITM_REGPARM; +extern void *_ITM_getTMCloneSafe (void *) ITM_REGPARM; +extern void _ITM_registerTMCloneTable (void *, size_t); +extern void _ITM_deregisterTMCloneTable (void *); + +extern void *_ITM_cxa_allocate_exception (size_t); +extern void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +extern void *_ITM_cxa_begin_catch (void *exc_ptr); +extern void _ITM_cxa_end_catch (void); +extern void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LIBITM_H */ Index: libitm/barrier.cc =================================================================== --- libitm/barrier.cc (.../trunk) (revision 0) +++ libitm/barrier.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,44 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +bool abi_dispatch::memmove_overlap_check(void *dst, const void *src, + size_t size, ls_modifier dst_mod, ls_modifier src_mod) +{ + if (dst_mod == NONTXNAL || src_mod == NONTXNAL) + { + if (((uintptr_t)dst <= (uintptr_t)src ? + (uintptr_t)dst + size > (uintptr_t)src : + (uintptr_t)src + size > (uintptr_t)dst)) + GTM::GTM_fatal("_ITM_memmove overlapping and t/nt is not allowed"); + return false; + } + return true; +} + +CREATE_DISPATCH_FUNCTIONS(GTM::abi_disp()->, ) + Index: libitm/alloc.cc =================================================================== --- libitm/alloc.cc (.../trunk) (revision 0) +++ libitm/alloc.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,129 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +void +gtm_thread::record_allocation (void *ptr, void (*free_fn)(void *)) +{ + uintptr_t iptr = (uintptr_t) ptr; + + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); + + a->free_fn = free_fn; + a->allocated = true; +} + +void +gtm_thread::forget_allocation (void *ptr, void (*free_fn)(void *)) +{ + uintptr_t iptr = (uintptr_t) ptr; + + gtm_alloc_action *a = this->alloc_actions.find(iptr); + if (a == 0) + a = this->alloc_actions.insert(iptr); + + a->free_fn = free_fn; + a->allocated = false; +} + +namespace { +struct commit_cb_data { + aa_tree* parent; + bool revert_p; +}; +} + +static void +commit_allocations_2 (uintptr_t key, gtm_alloc_action *a, void *data) +{ + void *ptr = (void *)key; + commit_cb_data *cb_data = static_cast(data); + + if (cb_data->revert_p) + { + // Roll back nested allocations. + if (a->allocated) + a->free_fn (ptr); + } + else + { + if (a->allocated) + { + // Add nested allocations to parent transaction. + gtm_alloc_action* a_parent = cb_data->parent->insert(key); + *a_parent = *a; + } + else + { + // ??? We could eliminate a parent allocation that matches this + // memory release, if we had support for removing all accesses + // to this allocation from the transaction's undo and redo logs + // (otherwise, the parent transaction's undo or redo might write to + // data that is already shared again because of calling free()). + // We don't have this support currently, and the benefit of this + // optimization is unknown, so just add it to the parent. + gtm_alloc_action* a_parent; + a_parent = cb_data->parent->insert(key); + *a_parent = *a; + } + } +} + +static void +commit_allocations_1 (uintptr_t key, gtm_alloc_action *a, void *cb_data) +{ + void *ptr = (void *)key; + uintptr_t revert_p = (uintptr_t) cb_data; + + if (a->allocated == revert_p) + a->free_fn (ptr); +} + +/* Permanently commit allocated memory during transaction. + + REVERT_P is true if instead of committing the allocations, we want + to roll them back (and vice versa). */ +void +gtm_thread::commit_allocations (bool revert_p, + aa_tree* parent) +{ + if (parent) + { + commit_cb_data cb_data; + cb_data.parent = parent; + cb_data.revert_p = revert_p; + this->alloc_actions.traverse (commit_allocations_2, &cb_data); + } + else + this->alloc_actions.traverse (commit_allocations_1, + (void *)(uintptr_t)revert_p); + this->alloc_actions.clear (); +} + +} // namespace GTM Index: libitm/configure.tgt =================================================================== --- libitm/configure.tgt (.../trunk) (revision 0) +++ libitm/configure.tgt (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,115 @@ +# -*- shell-script -*- +# This is the target specific configuration file. This is invoked by the +# autoconf generated configure script. Putting it in a separate shell file +# lets us skip running autoconf when modifying target specific information. + +# This file switches on the shell variable ${target}, and sets the +# following shell variables: +# config_path An ordered list of directories to search for +# sources and headers. This is relative to the +# config subdirectory of the source tree. +# XCFLAGS Add extra compile flags to use. +# XLDFLAGS Add extra link flags to use. + +# Optimize TLS usage by avoiding the overhead of dynamic allocation. +if test $gcc_cv_have_tls = yes ; then + case "${target}" in + + # For x86, we use slots in the TCB head for most of our TLS. + # The setup of those slots in beginTransaction can afford to + # use the global-dynamic model. + i[456]86-*-linux* | x86_64-*-linux*) + ;; + + *-*-linux*) + XCFLAGS="${XCFLAGS} -ftls-model=initial-exec" + ;; + esac +fi + +# Map the target cpu to an ARCH sub-directory. At the same time, +# work out any special compilation flags as necessary. +case "${target_cpu}" in + alpha*) ARCH=alpha ;; + ia64*) ARCH=ia64 ;; + mips*) ARCH=mips ;; + powerpc*) ARCH=powerpc ;; + s390*) ARCH=s390 ;; + + i[456]86) + case " ${CC} ${CFLAGS} " in + *" -m64 "*) + ;; + *) + if test -z "$with_arch"; then + XCFLAGS="${XCFLAGS} -march=i486 -mtune=${target_cpu}" + XCFLAGS="${XCFLAGS} -fomit-frame-pointer" + fi + esac + ARCH=x86 + ;; + + x86_64) + case " ${CC} ${CFLAGS} " in + *" -m32 "*) + XCFLAGS="${XCFLAGS} -march=i486 -mtune=i686" + XCFLAGS="${XCFLAGS} -fomit-frame-pointer" + ;; + esac + ARCH=x86 + ;; + + sparcv9 | sparc64) + # Note that sparcv7 and sparcv8 is not included here. We need cas. + echo "int i;" > conftestx.c + if ${CC} ${CFLAGS} -c -o conftestx.o conftestx.c > /dev/null 2>&1; then + case "`/usr/bin/file conftestx.o`" in + *32-bit*) + case " ${CC} ${CFLAGS}" in + *" -mcpu=ultrasparc"*) + ;; + *) + XCFLAGS="${XCFLAGS} -mcpu=v9" + ;; + esac + ;; + esac + fi + rm -f conftestx.c conftestx.o + ARCH=sparc + ;; + + *) + ARCH="${target_cpu}" + ;; +esac + +# Since we require POSIX threads, assume a POSIX system by default. +config_path="$ARCH posix generic" + +# Other system configury +case "${target}" in + *-*-linux*) + if test $enable_linux_futex = yes; then + config_path="linux/$ARCH linux $config_path" + fi + ;; + + *-*-hpux11*) + # HPUX v11.x requires -lrt to resolve sem_init in libgomp.la + XLDFLAGS="${XLDFLAGS} -lrt" + ;; + + *-*-mingw32*) + config_path="$ARCH mingw32 posix generic" + ;; + + *-*-solaris2.[56]*) + config_path="$ARCH posix95 posix generic" + XLDFLAGS="${XLDFLAGS} -lposix4" + ;; + + *-*-darwin*) + config_path="$ARCH bsd posix generic" + ;; +esac Index: libitm/libitm.spec.in =================================================================== --- libitm/libitm.spec.in (.../trunk) (revision 0) +++ libitm/libitm.spec.in (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,3 @@ +# This spec file is read by gcc when linking. It is used to specify the +# standard libraries we need in order to link with -fgnu-tm +*link_itm: @link_itm@ Index: libitm/memset.cc =================================================================== --- libitm/memset.cc (.../trunk) (revision 0) +++ libitm/memset.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,78 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +static void +do_memset(uintptr_t idst, int c, size_t size, abi_dispatch::lock_type W) +{ + abi_dispatch *disp = abi_disp(); + uintptr_t dofs = idst & (CACHELINE_SIZE - 1); + abi_dispatch::mask_pair dpair; + gtm_cacheline *dst + = reinterpret_cast(idst & -CACHELINE_SIZE); + + if (size == 0) + return; + + if (dofs != 0) + { + size_t dleft = CACHELINE_SIZE - dofs; + size_t min = (size <= dleft ? size : dleft); + + dpair = disp->write_lock(dst, W); + *dpair.mask |= (((gtm_cacheline_mask)1 << min) - 1) << dofs; + memset (&dpair.line->b[dofs], c, min); + dst++; + size -= min; + } + + while (size >= CACHELINE_SIZE) + { + dpair = disp->write_lock(dst, W); + *dpair.mask = -1; + memset (dpair.line, c, CACHELINE_SIZE); + dst++; + size -= CACHELINE_SIZE; + } + + if (size != 0) + { + dpair = disp->write_lock(dst, W); + *dpair.mask |= ((gtm_cacheline_mask)1 << size) - 1; + memset (dpair.line, c, size); + } +} + +#define ITM_MEM_DEF(WRITE) \ +void ITM_REGPARM _ITM_memset##WRITE(void *dst, int c, size_t size) \ +{ \ + do_memset ((uintptr_t)dst, c, size, abi_dispatch::WRITE); \ +} + +ITM_MEM_DEF(W) +ITM_MEM_DEF(WaR) +ITM_MEM_DEF(WaW) Index: libitm/alloc_cpp.cc =================================================================== --- libitm/alloc_cpp.cc (.../trunk) (revision 0) +++ libitm/alloc_cpp.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,152 @@ +/* Copyright (C) 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +/* Mangling the names by hand requires that we know how size_t is handled. + We've gotten the letter from autoconf, now substitute it into the names. + Everything below uses X as a placeholder for clarity. */ + +#define S1(x,y) x##y +#define S(x,y) S1(x,y) + +#define _ZnwX S(_Znw,MANGLE_SIZE_T) +#define _ZnaX S(_Zna,MANGLE_SIZE_T) +#define _ZnwXRKSt9nothrow_t S(S(_Znw,MANGLE_SIZE_T),RKSt9nothrow_t) +#define _ZnaXRKSt9nothrow_t S(S(_Zna,MANGLE_SIZE_T),RKSt9nothrow_t) + +#define _ZGTtnwX S(_ZGTtnw,MANGLE_SIZE_T) +#define _ZGTtnaX S(_ZGTtna,MANGLE_SIZE_T) +#define _ZGTtnwXRKSt9nothrow_t S(S(_ZGTtnw,MANGLE_SIZE_T),RKSt9nothrow_t) +#define _ZGTtnaXRKSt9nothrow_t S(S(_ZGTtna,MANGLE_SIZE_T),RKSt9nothrow_t) + +/* Everything from libstdc++ is weak, to avoid requiring that library + to be linked into plain C applications using libitm.so. */ + +extern "C" { + +extern void *_ZnwX (size_t) __attribute__((weak)); +extern void _ZdlPv (void *) __attribute__((weak)); +extern void *_ZnaX (size_t) __attribute__((weak)); +extern void _ZdaPv (void *) __attribute__((weak)); + +typedef const struct nothrow_t { } *c_nothrow_p; + +extern void *_ZnwXRKSt9nothrow_t (size_t, c_nothrow_p) __attribute__((weak)); +extern void _ZdlPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak)); +extern void *_ZnaXRKSt9nothrow_t (size_t, c_nothrow_p) __attribute__((weak)); +extern void _ZdaPvRKSt9nothrow_t (void *, c_nothrow_p) __attribute__((weak)); + +/* Wrap the delete nothrow symbols for usage with a single argument. + Perhaps should have a configure type check for this, because the + std::nothrow_t reference argument is unused (empty class), and most + targets don't actually need that second argument. So we _could_ + invoke these functions as if they were a single argument free. */ +static void +del_opnt (void *ptr) +{ + _ZdlPvRKSt9nothrow_t (ptr, NULL); +} + +static void +del_opvnt (void *ptr) +{ + _ZdaPvRKSt9nothrow_t (ptr, NULL); +} + +/* Wrap: operator new (std::size_t sz) */ +void * +_ZGTtnwX (size_t sz) +{ + void *r = _ZnwX (sz); + if (r) + gtm_thr()->record_allocation (r, _ZdlPv); + return r; +} + +/* Wrap: operator new (std::size_t sz, const std::nothrow_t&) */ +void * +_ZGTtnwXRKSt9nothrow_t (size_t sz, c_nothrow_p nt) +{ + void *r = _ZnwXRKSt9nothrow_t (sz, nt); + if (r) + gtm_thr()->record_allocation (r, del_opnt); + return r; +} + +/* Wrap: operator new[] (std::size_t sz) */ +void * +_ZGTtnaX (size_t sz) +{ + void *r = _ZnaX (sz); + if (r) + gtm_thr()->record_allocation (r, _ZdaPv); + return r; +} + +/* Wrap: operator new[] (std::size_t sz, const std::nothrow_t& nothrow) */ +void * +_ZGTtnaXRKSt9nothrow_t (size_t sz, c_nothrow_p nt) +{ + void *r = _ZnaXRKSt9nothrow_t (sz, nt); + if (r) + gtm_thr()->record_allocation (r, del_opvnt); + return r; +} + +/* Wrap: operator delete(void* ptr) */ +void +_ZGTtdlPv (void *ptr) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, _ZdlPv); +} + +/* Wrap: operator delete (void *ptr, const std::nothrow_t&) */ +void +_ZGTtdlPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, del_opnt); +} + +/* Wrap: operator delete[] (void *ptr) */ +void +_ZGTtdaPv (void *ptr) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, _ZdaPv); +} + +/* Wrap: operator delete[] (void *ptr, const std::nothrow_t&) */ +void +_ZGTtdaPvRKSt9nothrow_t (void *ptr, c_nothrow_p nt UNUSED) +{ + if (ptr) + gtm_thr()->forget_allocation (ptr, del_opvnt); +} + +} // extern "C" Index: libitm/method-serial.cc =================================================================== --- libitm/method-serial.cc (.../trunk) (revision 0) +++ libitm/method-serial.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,285 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +// Avoid a dependency on libstdc++ for the pure virtuals in abi_dispatch. +extern "C" void HIDDEN +__cxa_pure_virtual () +{ + abort (); +} + +using namespace GTM; + +namespace { + +// This group consists of the serial, serialirr, and serialirr_onwrite +// methods, which all need no global state (except what is already provided +// by the serial mode implementation). +struct serial_mg : public method_group +{ + virtual void init() { } + virtual void fini() { } +}; + +static serial_mg o_serial_mg; + + +class serialirr_dispatch : public abi_dispatch +{ + public: + serialirr_dispatch() : abi_dispatch(false, true, true, false, &o_serial_mg) + { } + + protected: + serialirr_dispatch(bool ro, bool wt, bool uninstrumented, + bool closed_nesting, method_group* mg) : + abi_dispatch(ro, wt, uninstrumented, closed_nesting, mg) { } + + // Transactional loads and stores simply access memory directly. + // These methods are static to avoid indirect calls, and will be used by the + // virtual ABI dispatch methods or by static direct-access methods created + // below. + template static V load(const V* addr, ls_modifier mod) + { + return *addr; + } + template static void store(V* addr, const V value, + ls_modifier mod) + { + *addr = value; + } + + public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + if (!may_overlap) + ::memcpy(dst, src, size); + else + ::memmove(dst, src, size); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + ::memset(dst, c, size); + } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; } + virtual bool trycommit(gtm_word& priv_time) { return true; } + virtual void rollback(gtm_transaction_cp *cp) { abort(); } + + virtual abi_dispatch* closed_nesting_alternative() + { + // For nested transactions with an instrumented code path, we can do + // undo logging. + return GTM::dispatch_serial(); + } +}; + +class serial_dispatch : public abi_dispatch +{ +protected: + static void log(const void *addr, size_t len) + { + // TODO Ensure that this gets inlined: Use internal log interface and LTO. + GTM_LB(addr, len); + } + + template static V load(const V* addr, ls_modifier mod) + { + return *addr; + } + template static void store(V* addr, const V value, + ls_modifier mod) + { + if (mod != WaW) + log(addr, sizeof(V)); + *addr = value; + } + +public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + if (dst_mod != WaW && dst_mod != NONTXNAL) + log(dst, size); + if (!may_overlap) + ::memcpy(dst, src, size); + else + ::memmove(dst, src, size); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + if (mod != WaW) + log(dst, size); + ::memset(dst, c, size); + } + + virtual gtm_restart_reason begin_or_restart() { return NO_RESTART; } + virtual bool trycommit(gtm_word& priv_time) { return true; } + // Local undo will handle this. + // trydropreference() need not be changed either. + virtual void rollback(gtm_transaction_cp *cp) { } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + serial_dispatch() : abi_dispatch(false, true, false, true, &o_serial_mg) { } +}; + + +// Like serialirr_dispatch but does not requests serial-irrevocable mode until +// the first write in the transaction. Can be useful for read-mostly workloads +// and testing, but is likely too simple to be of general purpose. +class serialirr_onwrite_dispatch : public serialirr_dispatch +{ + public: + serialirr_onwrite_dispatch() : + serialirr_dispatch(false, true, false, false, &o_serial_mg) { } + + protected: + static void pre_write() + { + gtm_thread *tx = gtm_thr(); + if (!(tx->state & (gtm_thread::STATE_SERIAL + | gtm_thread::STATE_IRREVOCABLE))) + tx->serialirr_mode(); + } + + // Transactional loads access memory directly. + // Transactional stores switch to serial mode first. + template static void store(V* addr, const V value, + ls_modifier mod) + { + pre_write(); + serialirr_dispatch::store(addr, value, mod); + } + + public: + static void memtransfer_static(void *dst, const void* src, size_t size, + bool may_overlap, ls_modifier dst_mod, ls_modifier src_mod) + { + pre_write(); + serialirr_dispatch::memtransfer_static(dst, src, size, may_overlap, + dst_mod, src_mod); + } + + static void memset_static(void *dst, int c, size_t size, ls_modifier mod) + { + pre_write(); + serialirr_dispatch::memset_static(dst, c, size, mod); + } + + CREATE_DISPATCH_METHODS(virtual, ) + CREATE_DISPATCH_METHODS_MEM() + + virtual void rollback(gtm_transaction_cp *cp) + { + gtm_thread *tx = gtm_thr(); + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + abort(); + } +}; + +} // anon namespace + +static const serialirr_dispatch o_serialirr_dispatch; +static const serial_dispatch o_serial_dispatch; +static const serialirr_onwrite_dispatch o_serialirr_onwrite_dispatch; + +abi_dispatch * +GTM::dispatch_serialirr () +{ + return const_cast(&o_serialirr_dispatch); +} + +abi_dispatch * +GTM::dispatch_serial () +{ + return const_cast(&o_serial_dispatch); +} + +abi_dispatch * +GTM::dispatch_serialirr_onwrite () +{ + return + const_cast(&o_serialirr_onwrite_dispatch); +} + +// Put the transaction into serial-irrevocable mode. + +void +GTM::gtm_thread::serialirr_mode () +{ + struct abi_dispatch *disp = abi_disp (); + bool need_restart = true; + + if (this->state & STATE_SERIAL) + { + if (this->state & STATE_IRREVOCABLE) + return; + + // Try to commit the dispatch-specific part of the transaction, as we + // would do for an outermost commit. + // We're already serial, so we don't need to ensure privatization safety + // for other transactions here. + gtm_word priv_time = 0; + bool ok = disp->trycommit (priv_time); + // Given that we're already serial, the trycommit better work. + assert (ok); + need_restart = false; + } + else if (serial_lock.write_upgrade (this)) + { + this->state |= STATE_SERIAL; + // Try to commit the dispatch-specific part of the transaction, as we + // would do for an outermost commit. + // We have successfully upgraded to serial mode, so we don't need to + // ensure privatization safety for other transactions here. + gtm_word priv_time = 0; + if (disp->trycommit (priv_time)) + need_restart = false; + } + + if (need_restart) + restart (RESTART_SERIAL_IRR); + else + { + this->state |= (STATE_SERIAL | STATE_IRREVOCABLE); + set_abi_disp (dispatch_serialirr ()); + } +} + +void ITM_REGPARM +_ITM_changeTransactionMode (_ITM_transactionState state) +{ + assert (state == modeSerialIrrevocable); + gtm_thr()->serialirr_mode (); +} Index: libitm/eh_cpp.cc =================================================================== --- libitm/eh_cpp.cc (.../trunk) (revision 0) +++ libitm/eh_cpp.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,108 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +/* Everything from libstdc++ is weak, to avoid requiring that library + to be linked into plain C applications using libitm.so. */ + +#define WEAK __attribute__((weak)) + +extern "C" { + +extern void *__cxa_allocate_exception (size_t) WEAK; +extern void __cxa_throw (void *, void *, void *) WEAK; +extern void *__cxa_begin_catch (void *) WEAK; +extern void *__cxa_end_catch (void) WEAK; +extern void __cxa_tm_cleanup (void *, void *, unsigned int) WEAK; + +} + + +void * +_ITM_cxa_allocate_exception (size_t size) +{ + void *r = __cxa_allocate_exception (size); + gtm_thr()->cxa_unthrown = r; + return r; +} + +void +_ITM_cxa_throw (void *obj, void *tinfo, void *dest) +{ + gtm_thr()->cxa_unthrown = NULL; + __cxa_throw (obj, tinfo, dest); +} + +void * +_ITM_cxa_begin_catch (void *exc_ptr) +{ + gtm_thr()->cxa_catch_count++; + return __cxa_begin_catch (exc_ptr); +} + +void +_ITM_cxa_end_catch (void) +{ + gtm_thr()->cxa_catch_count--; + __cxa_end_catch (); +} + +void +GTM::gtm_thread::revert_cpp_exceptions (gtm_transaction_cp *cp) +{ + if (cp) + { + // If rolling back a nested transaction, only clean up unthrown + // exceptions since the last checkpoint. Always reset eh_in_flight + // because it just contains the argument provided to + // _ITM_commitTransactionEH + void *unthrown = + (cxa_unthrown != cp->cxa_unthrown ? cxa_unthrown : NULL); + assert (cxa_catch_count >= cp->cxa_catch_count); + uint32_t catch_count = cxa_catch_count - cp->cxa_catch_count; + if (unthrown || catch_count) + { + __cxa_tm_cleanup (unthrown, this->eh_in_flight, catch_count); + cxa_catch_count = cp->cxa_catch_count; + cxa_unthrown = cp->cxa_unthrown; + this->eh_in_flight = NULL; + } + } + else + { + // Both cxa_catch_count and cxa_unthrown are maximal because EH regions + // and transactions are properly nested. + if (this->cxa_unthrown || this->cxa_catch_count) + { + __cxa_tm_cleanup (this->cxa_unthrown, this->eh_in_flight, + this->cxa_catch_count); + this->cxa_catch_count = 0; + this->cxa_unthrown = NULL; + this->eh_in_flight = NULL; + } + } +} Index: libitm/barrier.tpl =================================================================== --- libitm/barrier.tpl (.../trunk) (revision 0) +++ libitm/barrier.tpl (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,170 @@ +/* -*- c++ -*- */ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "unaligned.h" + +namespace { + +using namespace GTM; + +template +T do_read (const T *ptr, abi_dispatch::lock_type lock) +{ + // + // Find the cacheline that holds the current value of *PTR. + // + abi_dispatch *disp = abi_disp(); + uintptr_t iptr = reinterpret_cast(ptr); + // Normalize PTR by chopping off the bottom bits so we can search + // for PTR in the cacheline hash. + uintptr_t iline = iptr & -CACHELINE_SIZE; + // The position in the resulting cacheline where *PTR is actually stored. + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + const gtm_cacheline *pline = reinterpret_cast(iline); + // Search for the actual cacheline that holds the current value of *PTR. + const gtm_cacheline *line = disp->read_lock(pline, lock); + + // Point to the position in the cacheline where *PTR is stored. + ptr = reinterpret_cast(&line->b[iofs]); + + // Straight up loads, because we're either aligned, or we don't care + // about alignment. + // + // If we require alignment on type T, do a straight load if we're + // aligned. Otherwise do a straight load IFF the load fits entirely + // in this cacheline. That is, it won't span multiple cachelines. + if (__builtin_expect (strict_alignment::value + ? (iofs & (sizeof (T) - 1)) == 0 + : iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_normal_load: + return *ptr; + } + // If alignment on T is necessary, but we're unaligned, yet we fit + // entirely in this cacheline... do the unaligned load dance. + else if (__builtin_expect (strict_alignment::value + && iofs + sizeof(T) <= CACHELINE_SIZE, 1)) + { + do_unaligned_load: + return unaligned_load(ptr); + } + // Otherwise, this load will span multiple cachelines. + else + { + // Get the following cacheline for the rest of the data. + const gtm_cacheline *line2 = disp->read_lock(pline + 1, lock); + + // If the two cachelines are adjacent, just load it all in one + // swoop. + if (line2 == line + 1) + { + if (!strict_alignment::value) + goto do_normal_load; + else + goto do_unaligned_load; + } + else + { + // Otherwise, ask the backend to load from two different + // cachelines. + return unaligned_load2(line, line2, iofs); + } + } +} + +template +void do_write (T *ptr, T val, abi_dispatch::lock_type lock) +{ + // Note: See comments for do_read() above for hints on this + // function. Ideally we should abstract out a lot out of these two + // functions, and avoid all this duplication. + + abi_dispatch *disp = abi_disp(); + uintptr_t iptr = reinterpret_cast(ptr); + uintptr_t iline = iptr & -CACHELINE_SIZE; + uintptr_t iofs = iptr & (CACHELINE_SIZE - 1); + gtm_cacheline *pline = reinterpret_cast(iline); + gtm_cacheline_mask m = ((gtm_cacheline_mask)2 << (sizeof(T) - 1)) - 1; + abi_dispatch::mask_pair pair = disp->write_lock(pline, lock); + + ptr = reinterpret_cast(&pair.line->b[iofs]); + + if (__builtin_expect (strict_alignment::value + ? (iofs & (sizeof (val) - 1)) == 0 + : iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_normal_store: + *ptr = val; + } + else if (__builtin_expect (strict_alignment::value + && iofs + sizeof(val) <= CACHELINE_SIZE, 1)) + { + *pair.mask |= m << iofs; + do_unaligned_store: + unaligned_store(ptr, val); + } + else + { + *pair.mask |= m << iofs; + abi_dispatch::mask_pair pair2 = disp->write_lock(pline + 1, lock); + + uintptr_t ileft = CACHELINE_SIZE - iofs; + *pair2.mask |= m >> ileft; + + if (pair2.line == pair.line + 1) + { + if (!strict_alignment::value) + goto do_normal_store; + else + goto do_unaligned_store; + } + else + unaligned_store2(pair.line, pair2.line, iofs, val); + } +} + +} /* anonymous namespace */ + +#define ITM_READ(T, LOCK) \ + _ITM_TYPE_##T ITM_REGPARM _ITM_##LOCK##T (const _ITM_TYPE_##T *ptr) \ + { \ + return do_read (ptr, abi_dispatch::LOCK); \ + } + +#define ITM_WRITE(T, LOCK) \ + void ITM_REGPARM _ITM_##LOCK##T (_ITM_TYPE_##T *ptr, _ITM_TYPE_##T val) \ + { \ + do_write (ptr, val, abi_dispatch::LOCK); \ + } + +#define ITM_BARRIERS(T) \ + ITM_READ(T, R) \ + ITM_READ(T, RaR) \ + ITM_READ(T, RaW) \ + ITM_READ(T, RfW) \ + ITM_WRITE(T, W) \ + ITM_WRITE(T, WaR) \ + ITM_WRITE(T, WaW) Index: libitm/retry.cc =================================================================== --- libitm/retry.cc (.../trunk) (revision 0) +++ libitm/retry.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,265 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include +#include +#include +#include "libitm_i.h" + +// The default TM method used when starting a new transaction. +static GTM::abi_dispatch* default_dispatch = 0; +// The default TM method as requested by the user, if any. +static GTM::abi_dispatch* default_dispatch_user = 0; + +void +GTM::gtm_thread::decide_retry_strategy (gtm_restart_reason r) +{ + struct abi_dispatch *disp = abi_disp (); + + this->restart_reason[r]++; + this->restart_total++; + + if (r == RESTART_INIT_METHOD_GROUP) + { + // A re-initializations of the method group has been requested. Switch + // to serial mode, initialize, and resume normal operation. + if ((state & STATE_SERIAL) == 0) + { + // We have to eventually re-init the method group. Therefore, + // we cannot just upgrade to a write lock here because this could + // fail forever when other transactions execute in serial mode. + // However, giving up the read lock then means that a change of the + // method group could happen in-between, so check that we're not + // re-initializing without a need. + // ??? Note that we can still re-initialize too often, but avoiding + // that would increase code complexity, which seems unnecessary + // given that re-inits should be very infrequent. + serial_lock.read_unlock(this); + serial_lock.write_lock(); + if (disp->get_method_group() == default_dispatch->get_method_group()) + { + // Still the same method group. + disp->get_method_group()->fini(); + disp->get_method_group()->init(); + } + serial_lock.write_unlock(); + serial_lock.read_lock(this); + if (disp->get_method_group() != default_dispatch->get_method_group()) + { + disp = default_dispatch; + set_abi_disp(disp); + } + } + else + { + // We are a serial transaction already, which makes things simple. + disp->get_method_group()->fini(); + disp->get_method_group()->init(); + } + } + + bool retry_irr = (r == RESTART_SERIAL_IRR); + bool retry_serial = (retry_irr || this->restart_total > 100); + + // We assume closed nesting to be infrequently required, so just use + // dispatch_serial (with undo logging) if required. + if (r == RESTART_CLOSED_NESTING) + retry_serial = true; + + if (retry_serial) + { + // In serialirr_mode we can succeed with the upgrade to + // write-lock but fail the trycommit. In any case, if the + // write lock is not yet held, grab it. Don't do this with + // an upgrade, since we've no need to preserve the state we + // acquired with the read. + // Note that we will be restarting with either dispatch_serial or + // dispatch_serialirr, which are compatible with all TM methods; if + // we would retry with a different method, we would have to first check + // whether the default dispatch or the method group have changed. Also, + // the caller must have rolled back the previous transaction, so we + // don't have to worry about things such as privatization. + if ((this->state & STATE_SERIAL) == 0) + { + this->state |= STATE_SERIAL; + serial_lock.read_unlock (this); + serial_lock.write_lock (); + } + + // We can retry with dispatch_serialirr if the transaction + // doesn't contain an abort and if we don't need closed nesting. + if ((this->prop & pr_hasNoAbort) && (r != RESTART_CLOSED_NESTING)) + retry_irr = true; + } + + // Note that we can just use serial mode here without having to switch + // TM method sets because serial mode is compatible with all of them. + if (retry_irr) + { + this->state = (STATE_SERIAL | STATE_IRREVOCABLE); + disp = dispatch_serialirr (); + set_abi_disp (disp); + } + else if (retry_serial) + { + disp = dispatch_serial(); + set_abi_disp (disp); + } +} + + +// Decides which TM method should be used on the first attempt to run this +// transaction. +GTM::abi_dispatch* +GTM::gtm_thread::decide_begin_dispatch (uint32_t prop) +{ + // TODO Pay more attention to prop flags (eg, *omitted) when selecting + // dispatch. + if ((prop & pr_doesGoIrrevocable) || !(prop & pr_instrumentedCode)) + return dispatch_serialirr(); + + // If we might need closed nesting and the default dispatch has an + // alternative that supports closed nesting, use it. + // ??? We could choose another TM method that we know supports closed + // nesting but isn't the default (e.g., dispatch_serial()). However, we + // assume that aborts that need closed nesting are infrequent, so don't + // choose a non-default method until we have to actually restart the + // transaction. + if (!(prop & pr_hasNoAbort) && !default_dispatch->closed_nesting() + && default_dispatch->closed_nesting_alternative()) + return default_dispatch->closed_nesting_alternative(); + + // No special case, just use the default dispatch. + return default_dispatch; +} + + +void +GTM::gtm_thread::set_default_dispatch(GTM::abi_dispatch* disp) +{ + if (default_dispatch == disp) + return; + if (default_dispatch) + { + // If we are switching method groups, initialize and shut down properly. + if (default_dispatch->get_method_group() != disp->get_method_group()) + { + default_dispatch->get_method_group()->fini(); + disp->get_method_group()->init(); + } + } + else + disp->get_method_group()->init(); + default_dispatch = disp; +} + + +static GTM::abi_dispatch* +parse_default_method() +{ + const char *env = getenv("ITM_DEFAULT_METHOD"); + GTM::abi_dispatch* disp = 0; + if (env == NULL) + return 0; + + while (isspace((unsigned char) *env)) + ++env; + if (strncmp(env, "serialirr_onwrite", 17) == 0) + { + disp = GTM::dispatch_serialirr_onwrite(); + env += 17; + } + else if (strncmp(env, "serialirr", 9) == 0) + { + disp = GTM::dispatch_serialirr(); + env += 9; + } + else if (strncmp(env, "serial", 6) == 0) + { + disp = GTM::dispatch_serial(); + env += 6; + } + else if (strncmp(env, "gl_wt", 5) == 0) + { + disp = GTM::dispatch_gl_wt(); + env += 5; + } + else + goto unknown; + + while (isspace((unsigned char) *env)) + ++env; + if (*env == '\0') + return disp; + + unknown: + GTM::GTM_error("Unknown TM method in environment variable " + "ITM_DEFAULT_METHOD\n"); + return 0; +} + +// Gets notifications when the number of registered threads changes. This is +// used to initialize the method set choice and trigger straightforward choice +// adaption. +// This must be called only by serial threads. +void +GTM::gtm_thread::number_of_threads_changed(unsigned previous, unsigned now) +{ + if (previous == 0) + { + // No registered threads before, so initialize. + static bool initialized = false; + if (!initialized) + { + initialized = true; + // Check for user preferences here. + default_dispatch_user = parse_default_method(); + } + } + else if (now == 0) + { + // No registered threads anymore. The dispatch based on serial mode do + // not have any global state, so this effectively shuts down properly. + set_default_dispatch(dispatch_serialirr()); + } + + if (now == 1) + { + // Only one thread, so use a serializing method. + // ??? If we don't have a fast serial mode implementation, it might be + // better to use the global lock method set here. + if (default_dispatch_user) + set_default_dispatch(default_dispatch_user); + else + set_default_dispatch(dispatch_serialirr()); + } + else if (now > 1 && previous <= 1) + { + // More than one thread, use the default method. + if (default_dispatch_user) + set_default_dispatch(default_dispatch_user); + else + set_default_dispatch(dispatch_serialirr_onwrite()); + } +} Index: libitm/query.cc =================================================================== --- libitm/query.cc (.../trunk) (revision 0) +++ libitm/query.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,70 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +using namespace GTM; + +int ITM_REGPARM +_ITM_versionCompatible (int version) +{ + return version == _ITM_VERSION_NO; +} + + +const char * ITM_REGPARM +_ITM_libraryVersion (void) +{ + return "GNU libitm " _ITM_VERSION; +} + + +_ITM_howExecuting ITM_REGPARM +_ITM_inTransaction (void) +{ + struct gtm_thread *tx = gtm_thr(); + if (tx && (tx->nesting > 0)) + { + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + return inIrrevocableTransaction; + else + return inRetryableTransaction; + } + return outsideTransaction; +} + + +_ITM_transactionId_t ITM_REGPARM +_ITM_getTransactionId (void) +{ + struct gtm_thread *tx = gtm_thr(); + return (tx && (tx->nesting > 0)) ? tx->id : _ITM_noTransactionId; +} + + +void ITM_REGPARM ITM_NORETURN +_ITM_error (const _ITM_srcLocation * loc UNUSED, int errorCode UNUSED) +{ + abort (); +} Index: libitm/beginend.cc =================================================================== --- libitm/beginend.cc (.../trunk) (revision 0) +++ libitm/beginend.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,536 @@ +/* Copyright (C) 2008, 2009, 2011 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" +#include + + +using namespace GTM; + +#if !defined(HAVE_ARCH_GTM_THREAD) || !defined(HAVE_ARCH_GTM_THREAD_DISP) +extern __thread gtm_thread_tls _gtm_thr_tls; +#endif + +gtm_rwlock GTM::gtm_thread::serial_lock; +gtm_thread *GTM::gtm_thread::list_of_threads = 0; +unsigned GTM::gtm_thread::number_of_threads = 0; + +gtm_stmlock GTM::gtm_stmlock_array[LOCK_ARRAY_SIZE]; +gtm_version GTM::gtm_clock; + +/* ??? Move elsewhere when we figure out library initialization. */ +uint64_t GTM::gtm_spin_count_var = 1000; + +static _ITM_transactionId_t global_tid; + +// Provides a on-thread-exit callback used to release per-thread data. +static pthread_key_t thr_release_key; +static pthread_once_t thr_release_once = PTHREAD_ONCE_INIT; + + +/* Allocate a transaction structure. */ +void * +GTM::gtm_thread::operator new (size_t s) +{ + void *tx; + + assert(s == sizeof(gtm_thread)); + + tx = xmalloc (sizeof (gtm_thread), true); + memset (tx, 0, sizeof (gtm_thread)); + + return tx; +} + +/* Free the given transaction. Raises an error if the transaction is still + in use. */ +void +GTM::gtm_thread::operator delete(void *tx) +{ + free(tx); +} + +static void +thread_exit_handler(void *) +{ + gtm_thread *thr = gtm_thr(); + if (thr) + delete thr; + set_gtm_thr(0); +} + +static void +thread_exit_init() +{ + if (pthread_key_create(&thr_release_key, thread_exit_handler)) + GTM_fatal("Creating thread release TLS key failed."); +} + + +GTM::gtm_thread::~gtm_thread() +{ + if (nesting > 0) + GTM_fatal("Thread exit while a transaction is still active."); + + // Deregister this transaction. + serial_lock.write_lock (); + gtm_thread **prev = &list_of_threads; + for (; *prev; prev = &(*prev)->next_thread) + { + if (*prev == this) + { + *prev = (*prev)->next_thread; + break; + } + } + number_of_threads--; + number_of_threads_changed(number_of_threads + 1, number_of_threads); + serial_lock.write_unlock (); +} + +GTM::gtm_thread::gtm_thread () +{ + // This object's memory has been set to zero by operator new, so no need + // to initialize any of the other primitive-type members that do not have + // constructors. + shared_state = ~(typeof shared_state)0; + + // Register this transaction with the list of all threads' transactions. + serial_lock.write_lock (); + next_thread = list_of_threads; + list_of_threads = this; + number_of_threads++; + number_of_threads_changed(number_of_threads - 1, number_of_threads); + serial_lock.write_unlock (); + + if (pthread_once(&thr_release_once, thread_exit_init)) + GTM_fatal("Initializing thread release TLS key failed."); + // Any non-null value is sufficient to trigger destruction of this + // transaction when the current thread terminates. + if (pthread_setspecific(thr_release_key, this)) + GTM_fatal("Setting thread release TLS key failed."); +} + + + +#ifndef HAVE_64BIT_SYNC_BUILTINS +static pthread_mutex_t global_tid_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + +static inline uint32_t choose_code_path(uint32_t prop, abi_dispatch *disp) +{ + if ((prop & pr_uninstrumentedCode) && disp->can_run_uninstrumented_code()) + return a_runUninstrumentedCode; + else + return a_runInstrumentedCode; +} + +uint32_t +GTM::gtm_thread::begin_transaction (uint32_t prop, const gtm_jmpbuf *jb) +{ + static const _ITM_transactionId_t tid_block_size = 1 << 16; + + gtm_thread *tx; + abi_dispatch *disp; + uint32_t ret; + + // ??? pr_undoLogCode is not properly defined in the ABI. Are barriers + // omitted because they are not necessary (e.g., a transaction on thread- + // local data) or because the compiler thinks that some kind of global + // synchronization might perform better? + if (unlikely(prop & pr_undoLogCode)) + GTM_fatal("pr_undoLogCode not supported"); + + tx = gtm_thr(); + if (unlikely(tx == NULL)) + { + // Create the thread object. The constructor will also set up automatic + // deletion on thread termination. + tx = new gtm_thread(); + set_gtm_thr(tx); + } + + if (tx->nesting > 0) + { + // This is a nested transaction. + // Check prop compatibility: + // The ABI requires pr_hasNoFloatUpdate, pr_hasNoVectorUpdate, + // pr_hasNoIrrevocable, pr_aWBarriersOmitted, pr_RaRBarriersOmitted, and + // pr_hasNoSimpleReads to hold for the full dynamic scope of a + // transaction. We could check that these are set for the nested + // transaction if they are also set for the parent transaction, but the + // ABI does not require these flags to be set if they could be set, + // so the check could be too strict. + // ??? For pr_readOnly, lexical or dynamic scope is unspecified. + + if (prop & pr_hasNoAbort) + { + // We can use flat nesting, so elide this transaction. + if (!(prop & pr_instrumentedCode)) + { + if (!(tx->state & STATE_SERIAL) || + !(tx->state & STATE_IRREVOCABLE)) + tx->serialirr_mode(); + } + // Increment nesting level after checking that we have a method that + // allows us to continue. + tx->nesting++; + return choose_code_path(prop, abi_disp()); + } + + // The transaction might abort, so use closed nesting if possible. + // pr_hasNoAbort has lexical scope, so the compiler should really have + // generated an instrumented code path. + assert(prop & pr_instrumentedCode); + + // Create a checkpoint of the current transaction. + gtm_transaction_cp *cp = tx->parent_txns.push(); + cp->save(tx); + new (&tx->alloc_actions) aa_tree(); + + // Check whether the current method actually supports closed nesting. + // If we can switch to another one, do so. + // If not, we assume that actual aborts are infrequent, and rather + // restart in _ITM_abortTransaction when we really have to. + disp = abi_disp(); + if (!disp->closed_nesting()) + { + // ??? Should we elide the transaction if there is no alternative + // method that supports closed nesting? If we do, we need to set + // some flag to prevent _ITM_abortTransaction from aborting the + // wrong transaction (i.e., some parent transaction). + abi_dispatch *cn_disp = disp->closed_nesting_alternative(); + if (cn_disp) + { + disp = cn_disp; + set_abi_disp(disp); + } + } + } + else + { + // Outermost transaction + disp = tx->decide_begin_dispatch (prop); + if (disp == dispatch_serialirr() || disp == dispatch_serial()) + { + tx->state = STATE_SERIAL; + if (disp == dispatch_serialirr()) + tx->state |= STATE_IRREVOCABLE; + serial_lock.write_lock (); + } + else + serial_lock.read_lock (tx); + + set_abi_disp (disp); + } + + // Initialization that is common for outermost and nested transactions. + tx->prop = prop; + tx->nesting++; + + tx->jb = *jb; + + // As long as we have not exhausted a previously allocated block of TIDs, + // we can avoid an atomic operation on a shared cacheline. + if (tx->local_tid & (tid_block_size - 1)) + tx->id = tx->local_tid++; + else + { +#ifdef HAVE_64BIT_SYNC_BUILTINS + tx->id = __sync_add_and_fetch (&global_tid, tid_block_size); + tx->local_tid = tx->id + 1; +#else + pthread_mutex_lock (&global_tid_lock); + global_tid += tid_block_size; + tx->id = global_tid; + tx->local_tid = tx->id + 1; + pthread_mutex_unlock (&global_tid_lock); +#endif + } + + // Run dispatch-specific restart code. Retry until we succeed. + GTM::gtm_restart_reason rr; + while ((rr = disp->begin_or_restart()) != NO_RESTART) + { + tx->decide_retry_strategy(rr); + disp = abi_disp(); + } + + // Determine the code path to run. Only irrevocable transactions cannot be + // restarted, so all other transactions need to save live variables. + ret = choose_code_path(prop, disp); + if (!(tx->state & STATE_IRREVOCABLE)) + ret |= a_saveLiveVariables; + return ret; +} + + +void +GTM::gtm_transaction_cp::save(gtm_thread* tx) +{ + // Save everything that we might have to restore on restarts or aborts. + jb = tx->jb; + undolog_size = tx->undolog.size(); + memcpy(&alloc_actions, &tx->alloc_actions, sizeof(alloc_actions)); + user_actions_size = tx->user_actions.size(); + id = tx->id; + prop = tx->prop; + cxa_catch_count = tx->cxa_catch_count; + cxa_unthrown = tx->cxa_unthrown; + disp = abi_disp(); + nesting = tx->nesting; +} + +void +GTM::gtm_transaction_cp::commit(gtm_thread* tx) +{ + // Restore state that is not persistent across commits. Exception handling, + // information, nesting level, and any logs do not need to be restored on + // commits of nested transactions. Allocation actions must be committed + // before committing the snapshot. + tx->jb = jb; + memcpy(&tx->alloc_actions, &alloc_actions, sizeof(alloc_actions)); + tx->id = id; + tx->prop = prop; +} + + +void +GTM::gtm_thread::rollback (gtm_transaction_cp *cp, bool aborting) +{ + // The undo log is special in that it used for both thread-local and shared + // data. Because of the latter, we have to roll it back before any + // dispatch-specific rollback (which handles synchronization with other + // transactions). + rollback_undolog (cp ? cp->undolog_size : 0); + + // Perform dispatch-specific rollback. + abi_disp()->rollback (cp); + + // Roll back all actions that are supposed to happen around the transaction. + rollback_user_actions (cp ? cp->user_actions_size : 0); + commit_allocations (true, (cp ? &cp->alloc_actions : 0)); + revert_cpp_exceptions (cp); + + if (cp) + { + // We do not yet handle restarts of nested transactions. To do that, we + // would have to restore some state (jb, id, prop, nesting) not to the + // checkpoint but to the transaction that was started from this + // checkpoint (e.g., nesting = cp->nesting + 1); + assert(aborting); + // Roll back the rest of the state to the checkpoint. + jb = cp->jb; + id = cp->id; + prop = cp->prop; + if (cp->disp != abi_disp()) + set_abi_disp(cp->disp); + memcpy(&alloc_actions, &cp->alloc_actions, sizeof(alloc_actions)); + nesting = cp->nesting; + } + else + { + // Roll back to the outermost transaction. + // Restore the jump buffer and transaction properties, which we will + // need for the longjmp used to restart or abort the transaction. + if (parent_txns.size() > 0) + { + jb = parent_txns[0].jb; + id = parent_txns[0].id; + prop = parent_txns[0].prop; + } + // Reset the transaction. Do not reset this->state, which is handled by + // the callers. Note that if we are not aborting, we reset the + // transaction to the point after having executed begin_transaction + // (we will return from it), so the nesting level must be one, not zero. + nesting = (aborting ? 0 : 1); + parent_txns.clear(); + } + + if (this->eh_in_flight) + { + _Unwind_DeleteException ((_Unwind_Exception *) this->eh_in_flight); + this->eh_in_flight = NULL; + } +} + +void ITM_REGPARM +_ITM_abortTransaction (_ITM_abortReason reason) +{ + gtm_thread *tx = gtm_thr(); + + assert (reason == userAbort || reason == (userAbort | outerAbort)); + assert ((tx->prop & pr_hasNoAbort) == 0); + + if (tx->state & gtm_thread::STATE_IRREVOCABLE) + abort (); + + // Roll back to innermost transaction. + if (tx->parent_txns.size() > 0 && !(reason & outerAbort)) + { + // If the current method does not support closed nesting but we are + // nested and must only roll back the innermost transaction, then + // restart with a method that supports closed nesting. + abi_dispatch *disp = abi_disp(); + if (!disp->closed_nesting()) + tx->restart(RESTART_CLOSED_NESTING); + + // The innermost transaction is a closed nested transaction. + gtm_transaction_cp *cp = tx->parent_txns.pop(); + uint32_t longjmp_prop = tx->prop; + gtm_jmpbuf longjmp_jb = tx->jb; + + tx->rollback (cp, true); + + // Jump to nested transaction (use the saved jump buffer). + GTM_longjmp (&longjmp_jb, a_abortTransaction | a_restoreLiveVariables, + longjmp_prop); + } + else + { + // There is no nested transaction or an abort of the outermost + // transaction was requested, so roll back to the outermost transaction. + tx->rollback (0, true); + + // Aborting an outermost transaction finishes execution of the whole + // transaction. Therefore, reset transaction state. + if (tx->state & gtm_thread::STATE_SERIAL) + gtm_thread::serial_lock.write_unlock (); + else + gtm_thread::serial_lock.read_unlock (tx); + tx->state = 0; + + GTM_longjmp (&tx->jb, a_abortTransaction | a_restoreLiveVariables, + tx->prop); + } +} + +bool +GTM::gtm_thread::trycommit () +{ + nesting--; + + // Skip any real commit for elided transactions. + if (nesting > 0 && (parent_txns.size() == 0 || + nesting > parent_txns[parent_txns.size() - 1].nesting)) + return true; + + if (nesting > 0) + { + // Commit of a closed-nested transaction. Remove one checkpoint and add + // any effects of this transaction to the parent transaction. + gtm_transaction_cp *cp = parent_txns.pop(); + commit_allocations(false, &cp->alloc_actions); + cp->commit(this); + return true; + } + + // Commit of an outermost transaction. + gtm_word priv_time = 0; + if (abi_disp()->trycommit (priv_time)) + { + // The transaction is now inactive. Everything that we still have to do + // will not synchronize with other transactions anymore. + if (state & gtm_thread::STATE_SERIAL) + gtm_thread::serial_lock.write_unlock (); + else + gtm_thread::serial_lock.read_unlock (this); + state = 0; + + // We can commit the undo log after dispatch-specific commit and after + // making the transaction inactive because we only have to reset + // gtm_thread state. + commit_undolog (); + // Reset further transaction state. + cxa_catch_count = 0; + cxa_unthrown = NULL; + restart_total = 0; + + // Ensure privatization safety, if necessary. + if (priv_time) + { + // TODO Don't just spin but also block using cond vars / futexes + // here. Should probably be integrated with the serial lock code. + // TODO For C++0x atomics, the loads of other threads' shared_state + // should have acquire semantics (together with releases for the + // respective updates). But is this unnecessary overhead because + // weaker barriers are sufficient? + for (gtm_thread *it = gtm_thread::list_of_threads; it != 0; + it = it->next_thread) + { + if (it == this) continue; + while (it->shared_state < priv_time) + cpu_relax(); + } + } + + // After ensuring privatization safety, we execute potentially + // privatizing actions (e.g., calling free()). User actions are first. + commit_user_actions (); + commit_allocations (false, 0); + + return true; + } + return false; +} + +void ITM_NORETURN +GTM::gtm_thread::restart (gtm_restart_reason r) +{ + // Roll back to outermost transaction. Do not reset transaction state because + // we will continue executing this transaction. + rollback (); + decide_retry_strategy (r); + + // Run dispatch-specific restart code. Retry until we succeed. + abi_dispatch* disp = abi_disp(); + GTM::gtm_restart_reason rr; + while ((rr = disp->begin_or_restart()) != NO_RESTART) + { + decide_retry_strategy(rr); + disp = abi_disp(); + } + + GTM_longjmp (&jb, + choose_code_path(prop, disp) | a_restoreLiveVariables, prop); +} + +void ITM_REGPARM +_ITM_commitTransaction(void) +{ + gtm_thread *tx = gtm_thr(); + if (!tx->trycommit ()) + tx->restart (RESTART_VALIDATE_COMMIT); +} + +void ITM_REGPARM +_ITM_commitTransactionEH(void *exc_ptr) +{ + gtm_thread *tx = gtm_thr(); + if (!tx->trycommit ()) + { + tx->eh_in_flight = exc_ptr; + tx->restart (RESTART_VALIDATE_COMMIT); + } +} Index: libitm/useraction.cc =================================================================== --- libitm/useraction.cc (.../trunk) (revision 0) +++ libitm/useraction.cc (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,81 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#include "libitm_i.h" + +namespace GTM HIDDEN { + +void +gtm_thread::rollback_user_actions(size_t until_size) +{ + for (size_t s = user_actions.size(); s > until_size; s--) + { + user_action *a = user_actions.pop(); + if (!a->on_commit) + a->fn (a->arg); + } +} + + +void +gtm_thread::commit_user_actions() +{ + for (vector::iterator i = user_actions.begin(), + ie = user_actions.end(); i != ie; i++) + { + if (i->on_commit) + i->fn (i->arg); + } + user_actions.clear(); +} + +} // namespace GTM + +using namespace GTM; + +void ITM_REGPARM +_ITM_addUserCommitAction(_ITM_userCommitFunction fn, + _ITM_transactionId_t tid, void *arg) +{ + gtm_thread *tx = gtm_thr(); + if (tid != _ITM_noTransactionId) + GTM_fatal("resumingTransactionId in _ITM_addUserCommitAction must be " + "_ITM_noTransactionId"); + gtm_thread::user_action *a = tx->user_actions.push(); + a->fn = fn; + a->arg = arg; + a->on_commit = true; + a->resuming_id = tid; +} + + +void ITM_REGPARM +_ITM_addUserUndoAction(_ITM_userUndoFunction fn, void * arg) +{ + gtm_thread *tx = gtm_thr(); + gtm_thread::user_action *a = tx->user_actions.push(); + a->fn = fn; + a->arg = arg; + a->on_commit = false; +} Index: libitm/config.h.in =================================================================== --- libitm/config.h.in (.../trunk) (revision 0) +++ libitm/config.h.in (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,159 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if the target supports 64-bit __sync_*_compare_and_swap */ +#undef HAVE_64BIT_SYNC_BUILTINS + +/* Define to 1 if the target supports __attribute__((alias(...))). */ +#undef HAVE_ATTRIBUTE_ALIAS + +/* Define to 1 if the target supports __attribute__((dllexport)). */ +#undef HAVE_ATTRIBUTE_DLLEXPORT + +/* Define to 1 if the target supports __attribute__((visibility(...))). */ +#undef HAVE_ATTRIBUTE_VISIBILITY + +/* Define if the POSIX Semaphores do not work on your system. */ +#undef HAVE_BROKEN_POSIX_SEMAPHORES + +/* Define to 1 if the target assembler supports thread-local storage. */ +#undef HAVE_CC_TLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memalign' function. */ +#undef HAVE_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +#undef HAVE_MMAP_ANON + +/* Define if mmap of /dev/zero works. */ +#undef HAVE_MMAP_DEV_ZERO + +/* Define if read-only mmap of a plain file works. */ +#undef HAVE_MMAP_FILE + +/* Define to 1 if you have the `posix_memalign' function. */ +#undef HAVE_POSIX_MEMALIGN + +/* Define to 1 if you have the header file. */ +#undef HAVE_SEMAPHORE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + +/* Define to 1 if the target supports __sync_*_compare_and_swap */ +#undef HAVE_SYNC_BUILTINS + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if the target supports thread-local storage. */ +#undef HAVE_TLS + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if GNU symbol versioning is used for libitm. */ +#undef LIBITM_GNU_SYMBOL_VERSIONING + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to the letter to which size_t is mangled. */ +#undef MANGLE_SIZE_T + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of `char', as computed by sizeof. */ +#undef SIZEOF_CHAR + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `void *', as computed by sizeof. */ +#undef SIZEOF_VOID_P + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both and . */ +#undef STRING_WITH_STRINGS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN 0 +#endif Index: libitm/stmlock.h =================================================================== --- libitm/stmlock.h (.../trunk) (revision 0) +++ libitm/stmlock.h (.../branches/transactional-memory) (revision 180773) @@ -0,0 +1,123 @@ +/* Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Richard Henderson . + + This file is part of the GNU Transactional Memory Library (libitm). + + Libitm is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + Libitm is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef LIBITM_STMLOCK_H +#define LIBITM_STMLOCK_H 1 + +namespace GTM HIDDEN { + +/* A versioned write lock on a cacheline. This must be wide enough to + store a pointer, and preferably wide enough to avoid overflowing the + version counter. Thus we use a "word", which should be 64-bits on + 64-bit systems even when their pointer size is forced smaller. */ +typedef gtm_word gtm_stmlock; + +/* This has to be the same size as gtm_stmlock, we just use this name + for documentation purposes. */ +typedef gtm_word gtm_version; + +/* The maximum value a version number can have. This is a consequence + of having the low bit of gtm_stmlock reserved for the owned bit. */ +#define GTM_VERSION_MAX (~(gtm_version)0 >> 1) + +/* A value that may be used to indicate "uninitialized" for a version. */ +#define GTM_VERSION_INVALID (~(gtm_version)0) + +/* This bit is set when the write lock is held. When set, the balance of + the bits in the lock is a pointer that references STM backend specific + data; it is up to the STM backend to determine if this thread holds the + lock. If this bit is clear, the balance of the bits are the last + version number committed to the cacheline. */ +static inline bool +gtm_stmlock_owned_p (gtm_stmlock lock) +{ + return lock & 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_owned (void *data) +{ + return (gtm_stmlock)(uintptr_t)data | 1; +} + +static inline void * +gtm_stmlock_get_addr (gtm_stmlock lock) +{ + return (void *)((uintptr_t)lock & ~(uintptr_t)1); +} + +static inline gtm_version +gtm_stmlock_get_version (gtm_stmlock lock) +{ + return lock >> 1; +} + +static inline gtm_stmlock +gtm_stmlock_set_version (gtm_version ver) +{ + return ver << 1; +} + +/* We use a fixed set of locks for all memory, hashed into the + following table. */ +#define LOCK_ARRAY_SIZE (1024 * 1024) +extern gtm_stmlock gtm_stmlock_array[LOCK_ARRAY_SIZE]; + +static inline gtm_stmlock * +gtm_get_stmlock (const gtm_cacheline *addr) +{ + size_t idx = ((uintptr_t) addr / CACHELINE_SIZE) % LOCK_ARRAY_SIZE; + return gtm_stmlock_array + idx; +} + +/* The current global version number. */ +extern gtm_version gtm_clock; + +static inline gtm_version +gtm_get_clock (void) +{ + gtm_version r; + + __sync_synchronize (); + r = gtm_clock; + atomic_read_barrier (); + + return r; +} + +static inline gtm_version +gtm_inc_clock (void) +{ + gtm_version r = __sync_add_and_fetch (>m_clock, 1); + + /* ??? Ought to handle wraparound for 32-bit. */ + if (sizeof(r) < 8 && r > GTM_VERSION_MAX) + abort (); + + return r; +} + +} // namespace GTM