The "transaction_wrap" attribute allows you to specify that function w() should be called in place of o() whenever o() is called from within a transaction. The syntax is not too cumbersome, but there are a few gotchas. Here's an example to show how it all works:
// This is a quick demonstration of how to use transaction_wrap in GCC #include <iostream> using namespace std; // We have a function called orig(), which we assume is implemented in a // manner that is not transaction-safe. int orig(int); // This line says that there is a function called wrapper(), which is // transaction-safe, which has the same signature as orig(). When a // transaction calls orig(), we would like wrapper() to be called instead. int wrapper(int) __attribute__((transaction_safe, transaction_wrap (orig))); // Here is our original function. It does two things: // // 1 - saves its operand to a volatile variable iii. This is not // transaction-safe! // 2 - adds one to its operand and returns the sum volatile int iii; int orig(int x) { iii = x; return x + 1; } // Here is our wrapper function. It adds two to its operand and returns the // sum. Note that we have explicitly implemented this in a manner that // differs from orig(), so that we can easily see which is called int wrapper(int x) { return x + 2; } // Our driver function calls orig(1) from three contexts: nontransactional, // atomic transaction, and relaxed transaction, and prints the result of each // call // // Be warned: the behavior is not what you expect, because it depends on the // TM algorithm that is used. For serial-irrevocable (serialirr), the result // is (2,2,2). For serial, ml_wt, and gl_wt, the result is (2, 3, 3). For // htm, the result is (2,3,2). int main() { int x = orig(1); cout << "orig(1) (raw) == " << x << endl; __transaction_atomic { x = orig(1); } cout << "orig(1) (atomic) == " << x << endl; __transaction_relaxed { x = orig(1); } cout << "orig(1) (relaxed) == " << x << endl; return 0; }
Compile the code like this:
g++ -fgnu-tm -std=c++11 -O3 test.cc -o test
And as suggested in the comments, the output will depend on the ITM_DEFAULT_METHOD you choose:
ITM_DEFAULT_METHOD=serialirr ./test orig(1) (raw) == 2 orig(1) (atomic) == 2 orig(1) (relaxed) == 2 ITM_DEFAULT_METHOD=serial ./test orig(1) (raw) == 2 orig(1) (atomic) == 3 orig(1) (relaxed) == 3 ITM_DEFAULT_METHOD=ml_wt ./test orig(1) (raw) == 2 orig(1) (atomic) == 3 orig(1) (relaxed) == 3 ITM_DEFAULT_METHOD=gl_wt ./test orig(1) (raw) == 2 orig(1) (atomic) == 3 orig(1) (relaxed) == 3 ITM_DEFAULT_METHOD=htm ./test orig(1) (raw) == 2 orig(1) (atomic) == 3 orig(1) (relaxed) == 2