Hi, I'd like to summarize the current state of support for the TM TS, and outline the current plan for the work that remains to complete the support.
I'm aware we're at the end of stage 1, but I'm confident we can still finish this work and hope to include it in GCC 6 because: (1) most of the support is already in GCC, and we have a big head start in the space of TM so it would be unfortunate to not waste that by not delivering support for the TM TS, (2) this is a TS and support for it is considered experimental, (3) most of the affected code is in libitm or the compiler's TM passes, which has to be enabled explicitly by the user. Currently, we have complete support for the syntax and all necessary instrumentation except the exception handling bits listed below. libitm has a good set of STM and HTM-based algorithms. What is missing on the compiler side is essentially a change of how we support atomic_noexcept and atomic_cancel, in particular exception handling. Instead of just using a finally block as done currently, the compiler need to build a catch clause so that it can actively intercept exceptions that escape an atomic_noexcept or atomic_cancel. For atomic_noexcept, the compiler needs to include a call to abort() in the catch clause. For atomic_cancel, it needs to call ITM_commitTransactionEH in the catch clause, and use NULL as exception argument. This can then be used by libitm to look at the currently being handled exception and (a) check whether the type support transaction cancellation as specified by the TS and (b) pick out the allocations that belong to this exception and roll back everything else before rethrowing this exception. For (a), it's probably best to place this check into libstdc++ (specifically, libsupc++ I suppose) because support for transaction cancellation is a property that library parts of the standard (or the TS) require, and that has to match the implementation in libstdc++. Attached is a patch by Jason that implements this check. This adds one symbol, which should be okay we hope. For (b), our plan is to track the additional allocations that happen when during construction of the exception types that support cancellation (eg, creating the what() string for logic_error). There are several ways to do that, one of that being that we create custom transactional clones of those constructors that tell libitm that either such a constructor is currently running or explicitly list the allocations that have been made by the constructor; eventually, we would always (copy) construct into memory returned by cxa_allocate_exception, which then makes available the necessary undo information when such an exception is handled in libitm. The other big piece of missing support is making sure that the functions that are specified in the TS as transaction_safe are indeed that. I believe we do not need to actually add such annotations to any libstdc++ functions that are already transaction-safe and completely defined in headers -- those functions are implicitly transaction-safe, and we can thus let the compiler isntrument them at the point of use inside of a transaction. If a supposedly transaction-safe function is not defined in a header, we'd need a transaction_safe annotation at the declaration. Jason has implemented the TM TS feature test macro, so we can only add the annotation if the user has enabled support for the TM TS in the respective compilation process. We also need ensure that there is a transaction clode of the function. This will add symbols to libstdc++, but these all have their own special prefix in the mangled name. I'd like to get feedback on how to best trigger the insturmentation and make it a part of a libstdc++ build. (If that would show to be too problematic, we could still fall back to writing transacitonal clones manually.) For the clones of the constructors of the types that support cancellation, I suppose manually written clones might be easier than automatic instrumentation. I've not yet created tests for the full list of functions specified as transaction-safe in the TS, but my understanding is that this list was created after someone from the ISO C++ TM study group looked at libstdc ++'s implementation and investigated which functions might be feasible to be declared transaction-safe in it. I'm looking forward to your feedback. Thanks, Torvald
// -*- C++ -*- GNU C++ atomic_cancel support. // Copyright (C) 2015 Free Software Foundation, Inc. // // This file is part of GCC. // // GCC 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, or (at your option) // any later version. // // GCC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. #include <bits/c++config.h> #include <cstdlib> #include <cxxabi.h> #include <exception> #include <stdexcept> #include <new> #include <typeinfo> #include <string.h> bool __cxxabiv1::__cxa_exception_supports_tx_cancel() { const std::type_info *tinfo = __cxa_current_exception_type(); if (!dynamic_cast <const __class_type_info*>(tinfo)) // All scalar types support transaction cancellation. return true; // But only specific classes support tx cancel. const char *name = tinfo->name(); // First check for std:: if (name[0] != 'S' || name[1] != 't') return false; name += 2; const char txe[] = "12tx_exceptionI"; if (!strncmp (name, txe, strlen(txe)) || !strcmp (name, "8bad_cast") || !strcmp (name, "9bad_alloc") || !strcmp (name, "10bad_typeid") || !strcmp (name, "11logic_error") || !strcmp (name, "11range_error") || !strcmp (name, "12domain_error") || !strcmp (name, "12length_error") || !strcmp (name, "12out_of_range") || !strcmp (name, "13bad_exception") || !strcmp (name, "13runtime_error") || !strcmp (name, "14overflow_error") || !strcmp (name, "15underflow_error") || !strcmp (name, "16invalid_argument") || !strcmp (name, "20bad_array_new_length")) return true; return false; }