commit e81080a01ab0daf2949a400c1a2d5077d37ba515
Author: Torvald Riegel <triegel@redhat.com>
Date: Fri Nov 13 01:00:52 2015 +0100
libstdc++: Make certain exceptions transaction_safe.
@@ -1876,6 +1876,12 @@ GLIBCXX_3.4.22 {
_ZNSt6thread6_StateD[012]Ev;
_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE;
+ # Support for the Transactional Memory TS (N4514)
+ _ZGTtNSt11logic_errorC1EPKc;
+ _ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE;
+ _ZGTtNKSt11logic_error4whatEv;
+ _ZGTtNSt11logic_errorD1Ev;
+
} GLIBCXX_3.4.21;
# Symbols in the support library (libsupc++) have their own tag.
@@ -2107,6 +2113,12 @@ CXXABI_1.3.9 {
# operator delete[](void*, std::size_t)
_ZdaPv[jmy];
+ # Support for the Transactional Memory TS (N4514)
+ _ZGTtNKSt9exceptionD1Ev;
+ _ZGTtNKSt9exception4whatEv;
+ _ZGTtNKSt13bad_exceptionD1Ev;
+ _ZGTtNKSt13bad_exception4whatEv;
+
} CXXABI_1.3.8;
# Symbols in the support library (libsupc++) supporting transactional memory.
@@ -4904,6 +4904,18 @@ _GLIBCXX_END_NAMESPACE_CXX11
int
compare(size_type __pos, size_type __n1, const _CharT* __s,
size_type __n2) const;
+
+# ifdef _GLIBCXX_TM_TS_INTERNAL
+ friend void
+ ::_txnal_cow_string_C1_for_exceptions(void* that, const char* s,
+ void* exc);
+ friend const char*
+ ::_txnal_cow_string_c_str(const void *that);
+ friend void
+ ::_txnal_cow_string_D1(void *that);
+ friend void
+ ::_txnal_cow_string_D1_commit(void *that);
+# endif
};
#endif // !_GLIBCXX_USE_CXX11_ABI
@@ -481,6 +481,17 @@ namespace std
# define _GLIBCXX_BEGIN_EXTERN_C extern "C" {
# define _GLIBCXX_END_EXTERN_C }
+// Conditionally enable annotations for the Transactional Memory TS on C++11.
+#if __cplusplus >= 201103L && \
+ _GLIBCXX_USE_CXX11_ABI && _GLIBCXX_USE_DUAL_ABI && \
+ defined(__cpp_transactional_memory) && __cpp_transactional_memory >= 201505L
+#define _GLIBCXX_TXN_SAFE transaction_safe
+#define _GLIBCXX_TXN_SAFE_DYN transaction_safe_dynamic
+#else
+#define _GLIBCXX_TXN_SAFE
+#define _GLIBCXX_TXN_SAFE_DYN
+#endif
+
#else // !__cplusplus
# define _GLIBCXX_BEGIN_EXTERN_C
# define _GLIBCXX_END_EXTERN_C
@@ -117,11 +117,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
public:
/** Takes a character string describing the error. */
explicit
- logic_error(const string& __arg);
+ logic_error(const string& __arg) _GLIBCXX_TXN_SAFE;
#if __cplusplus >= 201103L
explicit
- logic_error(const char*);
+ logic_error(const char*) _GLIBCXX_TXN_SAFE;
#endif
#if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS
@@ -129,12 +129,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
logic_error& operator=(const logic_error&) _GLIBCXX_USE_NOEXCEPT;
#endif
- virtual ~logic_error() _GLIBCXX_USE_NOEXCEPT;
+ virtual ~logic_error() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
/** Returns a C-style character string describing the general cause of
* the current error (the same string passed to the ctor). */
virtual const char*
- what() const _GLIBCXX_USE_NOEXCEPT;
+ what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
+# ifdef _GLIBCXX_TM_TS_INTERNAL
+ friend void*
+ ::_txnal_logic_error_get_msg(void* e);
+# endif
};
/** Thrown by the library, or by you, to report domain errors (domain in
@@ -26,16 +26,18 @@
#include "exception"
#include <cxxabi.h>
-std::exception::~exception() _GLIBCXX_USE_NOEXCEPT { }
+std::exception::~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT { }
-std::bad_exception::~bad_exception() _GLIBCXX_USE_NOEXCEPT { }
+std::bad_exception::~bad_exception() _GLIBCXX_TXN_SAFE_DYN
+ _GLIBCXX_USE_NOEXCEPT
+{ }
abi::__forced_unwind::~__forced_unwind() throw() { }
abi::__foreign_exception::~__foreign_exception() throw() { }
const char*
-std::exception::what() const _GLIBCXX_USE_NOEXCEPT
+std::exception::what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT
{
// NB: Another elegant option would be returning typeid(*this).name()
// and not overriding what() in bad_exception, bad_alloc, etc. In
@@ -44,7 +46,36 @@ std::exception::what() const _GLIBCXX_USE_NOEXCEPT
}
const char*
-std::bad_exception::what() const _GLIBCXX_USE_NOEXCEPT
+std::bad_exception::what() const _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT
{
return "std::bad_exception";
}
+
+// Transactional clones for the destructors and what().
+// what() is effectively transaction_pure, but we do not want to annotate it
+// as such; thus, we call exactly the respective nontransactional function.
+extern "C" {
+
+void
+_ZGTtNKSt9exceptionD1Ev(const std::exception*)
+{ }
+
+const char*
+_ZGTtNKSt9exception4whatEv(const std::exception* that)
+{
+ return that->std::exception::what();
+}
+
+void
+_ZGTtNKSt13bad_exceptionD1Ev(
+ const std::bad_exception*)
+{ }
+
+const char*
+_ZGTtNKSt13bad_exception4whatEv(
+ const std::bad_exception* that)
+{
+ return that->std::bad_exception::what();
+}
+
+}
@@ -61,11 +61,12 @@ namespace std
{
public:
exception() _GLIBCXX_USE_NOEXCEPT { }
- virtual ~exception() _GLIBCXX_USE_NOEXCEPT;
+ virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
/** Returns a C-style character string describing the general cause
* of the current error. */
- virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
+ virtual const char* what() const _GLIBCXX_TXN_SAFE_DYN
+ _GLIBCXX_USE_NOEXCEPT;
};
/** If an %exception is thrown which is not listed in a function's
@@ -77,10 +78,11 @@ namespace std
// This declaration is not useless:
// http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118
- virtual ~bad_exception() _GLIBCXX_USE_NOEXCEPT;
+ virtual ~bad_exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT;
// See comment in eh_exception.cc.
- virtual const char* what() const _GLIBCXX_USE_NOEXCEPT;
+ virtual const char* what() const _GLIBCXX_TXN_SAFE_DYN
+ _GLIBCXX_USE_NOEXCEPT;
};
/// If you write a replacement %terminate handler, it must be of this type.
@@ -26,6 +26,19 @@
// ISO C++ 14882: 19.1 Exception classes
//
+// Enable hooks for support for the Transactional Memory TS (N4514).
+#define _GLIBCXX_TM_TS_INTERNAL
+void
+_txnal_cow_string_C1_for_exceptions(void* that, const char* s, void *exc);
+const char*
+_txnal_cow_string_c_str(const void *that);
+void
+_txnal_cow_string_D1(void *that);
+void
+_txnal_cow_string_D1_commit(void *that);
+void*
+_txnal_logic_error_get_msg(void* e);
+
// All exception classes still use the classic COW std::string.
#define _GLIBCXX_USE_CXX11_ABI 0
#define _GLIBCXX_DEFINE_STDEXCEPT_COPY_OPS 1
@@ -151,3 +164,220 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
+
+// Support for the Transactional Memory TS (N4514).
+//
+// logic_error and runtime_error both carry a message in the form of a COW
+// string. This COW string is never made visible to users of the exception
+// because what() returns a C string. The COW string can be constructed as
+// either a copy of a COW string of another logic_error/runtime_error, or
+// using a C string or SSO string; thus, the COW string's _Rep is only
+// accessed by logic_error operations. We control all txnal clones of those
+// operations and thus can ensure that _Rep is never accessed transactionally.
+// Furthermore, _Rep will always have been allocated or deallocated via
+// global new or delete, so nontransactional writes we do to _Rep cannot
+// interfere with transactional accesses.
+extern "C" {
+
+// Declare all libitm symbols we rely on, but make them weak so that we do
+// not depend on libitm.
+#define WEAK __attribute__((weak))
+
+// FIXME copy over libitm's configury for MANGLE_SIZE_T?
+#define MANGLE_SIZE_T m
+#define CONCAT1(x,y) x##y
+#define CONCAT(x,y) CONCAT1(x,y)
+#define _ZGTtnaX CONCAT(_ZGTtna,MANGLE_SIZE_T)
+
+#ifdef __i386__
+/* Only for 32-bit x86. */
+# define ITM_REGPARM __attribute__((regparm(2)))
+#else
+# define ITM_REGPARM
+#endif
+
+extern void *_ZGTtnaX (size_t sz)
+ _GLIBCXX_WEAK_DEFINITION;
+extern uint8_t _ITM_RU1(const uint8_t *p)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+extern uint32_t _ITM_RU4(const uint32_t *p)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+extern uint64_t _ITM_RU8(const uint64_t *p)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+extern void _ITM_memcpyRtWn(void *, const void *, size_t)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+extern void _ITM_memcpyRnWt(void *, const void *, size_t)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+extern void _ITM_addUserCommitAction(void (*)(void *), uint64_t, void *)
+ ITM_REGPARM _GLIBCXX_WEAK_DEFINITION;
+
+// If there is no support for weak, create dummies.
+// FIXME really needed for libstdc++?
+//#if !defined (HAVE_ELF_STYLE_WEAKREF)
+//void *_ZGTtnaX (size_t) { return NULL; }
+//uint8_t _ITM_RU1(const uint8_t *) { return 0; }
+//uint32_t _ITM_RU4(const uint32_t *) { return 0; }
+//uint64_t _ITM_RU8(const uint64_t *) { return 0; }
+//void _ITM_memcpyRtWn(void *, const void *, size_t) { }
+//void _ITM_memcpyRnWt(void *, const void *, size_t) { }
+//void _ITM_addUserCommitAction(void (*)(void *), uint64_t, void *) { };
+//#endif
+
+}
+
+// A transactional version of basic_string::basic_string(const char *s)
+// that also notifies the TM runtime about allocations belonging to this
+// exception.
+void
+_txnal_cow_string_C1_for_exceptions(void* that, const char* s, void *exc)
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type *bs = (bs_type*) that;
+
+ // First, do a transactional strlen, but including the trailing zero.
+ bs_type::size_type len = 1;
+ for (const char *ss = s; _ITM_RU1((const uint8_t*) ss) != 0; ss++, len++);
+
+
+ // Allocate memory for the string and the refcount. We use the
+ // transactional clone of global new[]; if this throws, it will do so in a
+ // transaction-compatible way.
+ // The allocation belongs to this exception, so tell the runtime about it.
+ // TODO associate exception
+// void *prev = _ITM_setAssociatedException(exc);
+ bs_type::_Rep *rep;
+ try
+ {
+ rep = (bs_type::_Rep*) _ZGTtnaX (len + sizeof (bs_type::_Rep));
+ }
+ catch (...)
+ {
+ // Pop the association with this exception.
+// _ITM_setAssociatedException(prev);
+ // We do not need to instrument a rethrow.
+ throw;
+ }
+ // Pop the association with this exception.
+// _ITM_setAssociatedException(prev);
+
+ // Now initialize the rest of the string and copy the C string. The memory
+ // will be freshly allocated, so nontransactional accesses are sufficient,
+ // including the writes when copying the string (see above).
+ rep->_M_set_sharable();
+ rep->_M_length = rep->_M_capacity = len - 1;
+ _ITM_memcpyRtWn(rep->_M_refdata(), s, len);
+ new (&bs->_M_dataplus) bs_type::_Alloc_hider(rep->_M_refdata(),
+ bs_type::allocator_type());
+}
+
+static void* txnal_read_ptr(void* const * ptr)
+{
+ static_assert(sizeof(uint64_t) == sizeof(void*)
+ || sizeof(uint32_t) == sizeof(void*));
+ // FIXME make a true compile-time choice to prevent warnings.
+ if (sizeof(uint64_t)== sizeof(void*))
+ return (void*)_ITM_RU8((const uint64_t*)ptr);
+ else
+ return (void*)_ITM_RU4((const uint32_t*)ptr);
+}
+
+// We must access the data pointer in the COW string transactionally because
+// another transaction can delete the string and reuse the memory.
+const char*
+_txnal_cow_string_c_str(const void *that)
+{
+ typedef std::basic_string<char> bs_type;
+ const bs_type *bs = (const bs_type*) that;
+
+ return (const char*) txnal_read_ptr((void**)&bs->_M_dataplus._M_p);
+}
+
+const char*
+_txnal_sso_string_c_str(const void *that)
+{
+ return (const char*) txnal_read_ptr(
+ (void* const*)const_cast<char* const*>(
+ &((const std::__sso_string*) that)->_M_s._M_p));
+}
+
+void
+_txnal_cow_string_D1_commit(void *data)
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type::_Rep *rep = (bs_type::_Rep*) data;
+ rep->_M_dispose(bs_type::allocator_type());
+}
+
+void
+_txnal_cow_string_D1(void *that)
+{
+ typedef std::basic_string<char> bs_type;
+ bs_type::_Rep *rep = reinterpret_cast<bs_type::_Rep*>(
+ const_cast<char*>(_txnal_cow_string_c_str(that))) - 1;
+
+ // The string can be shared, in which case we would need to decrement the
+ // reference count. We cannot undo that because we might loose the string
+ // otherwise. Therefore, we register a commit action that will dispose of
+ // the string's _Rep.
+ enum {_ITM_noTransactionId = 1};
+ _ITM_addUserCommitAction(_txnal_cow_string_D1_commit, _ITM_noTransactionId,
+ rep);
+}
+
+void*
+_txnal_logic_error_get_msg(void* e)
+{
+ std::logic_error* le = (std::logic_error*) e;
+ return &le->_M_msg;
+}
+
+extern "C" {
+
+void
+_ZGTtNSt11logic_errorC1EPKc (std::logic_error *that, const char* s)
+{
+ // This will use the singleton _Rep for an empty string and just point
+ // to it instead of allocating memory. Thus, we can use it as source, copy
+ // it into the object we are constructing, and then construct the COW string
+ // in the latter manually.
+ std::logic_error le("");
+ _ITM_memcpyRnWt(that, &le, sizeof(std::logic_error));
+ _txnal_cow_string_C1_for_exceptions(_txnal_logic_error_get_msg(that),
+ s, that);
+}
+// TODO C2 and C3?
+
+void
+_ZGTtNSt11logic_errorC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE(
+ std::logic_error *that, const std::__sso_string& s)
+{
+ std::logic_error le("");
+ _ITM_memcpyRnWt(that, &le, sizeof(std::logic_error));
+ // This constructor is only declared transaction-safe if the C++11 ABI is
+ // used for std::string yet logic_error used a COW string internally. A
+ // user must not call this constructor otherwise; although we can still
+ // compile and provide it, calling it would result in undefined behavior,
+ // which is in this case not initializing the message.
+#if _GLIBCXX_USE_DUAL_ABI
+ // Get the C string from the SSO string.
+ _txnal_cow_string_C1_for_exceptions(_txnal_logic_error_get_msg(that),
+ _txnal_sso_string_c_str(&s), that);
+#endif
+}
+// TODO C2 and C3?
+
+const char*
+_ZGTtNKSt11logic_error4whatEv(const std::logic_error* that)
+{
+ return _txnal_cow_string_c_str(_txnal_logic_error_get_msg(
+ const_cast<std::logic_error*>(that)));
+}
+
+void
+_ZGTtNSt11logic_errorD1Ev(std::logic_error *that)
+{
+ _txnal_cow_string_D1(_txnal_logic_error_get_msg(that));
+}
+// TODO D0 and D2?
+
+}