[cfe-dev] atomic intrinsics
Howard Hinnant
hhinnant at apple.com
Mon Oct 18 11:21:35 PDT 2010
On Oct 18, 2010, at 1:27 PM, Howard Hinnant wrote:
> On Oct 18, 2010, at 1:19 PM, John McCall wrote:
>
>>> One question about Design A that has yet to be discussed is the possible defaulting of memory orderings in the intrinsics. This defaulting, if it exists, is described at the very bottom of:
>>>
>>> http://libcxx.llvm.org/atomic_design_a.html
>>>
>>> I have no strong feeling either way. I can easily live with or without the memory order defaults. But I should either remove the "If desired" from the description (mandating the defaults), or remove the description of the defaults altogether (banning them). Please weigh in with your opinions.
>>
>> The defaulting scheme for the two-parameter versions is very complicated and precludes implementing the type-checking for these builtins with a single C++ function declaration. If we're going to allow defaulting, I think they should both default to 5.
>
> This would make it very easy to drop into undefined behavior. For example:
>
> while (__atomic_compare_exchange_strong(&atomic_obj, &expected, desired, memory_order_acquire))
> ...
>
> In the above example, only mem_failure is defaulted (to 5 as you suggest), and this violates the requirement that mem_failure <= mem_success (mem_success is 2).
Here's a brief C++ simulation of the "default behavior" that the C++ <atomic> header is specified to have for compare_exchange_strong and compare_exchange_weak. This functionality either goes into the lib, or into the intrinsic. Which is best, I don't really have an opinion. But if the intrinsics are to have defaults, I think they should match the behavior of the standard.
The demo below models undefined behavior with an assert:
#include <iostream>
#include <cassert>
typedef enum memory_order
{
memory_order_relaxed, memory_order_consume, memory_order_acquire,
memory_order_release, memory_order_acq_rel, memory_order_seq_cst
} memory_order;
int
translate_memory_order(int o)
{
switch (o)
{
case 4:
return 2;
case 3:
return 0;
}
return o;
}
void test(int mem_success = memory_order_seq_cst)
{
int mem_failure = translate_memory_order(mem_success);
std::cout << "mem_success = " << mem_success << '\n';
std::cout << "mem_failure = " << mem_failure << '\n';
assert(mem_success >= mem_failure);
assert(mem_failure != memory_order_release);
assert(mem_failure != memory_order_acq_rel);
std::cout << "------------------------\n";
}
void test(int mem_success, int mem_failure)
{
std::cout << "mem_success = " << mem_success << '\n';
std::cout << "mem_failure = " << mem_failure << '\n';
assert(mem_success >= mem_failure);
assert(mem_failure != memory_order_release);
assert(mem_failure != memory_order_acq_rel);
std::cout << "------------------------\n";
}
int main()
{
std::cout << "test()\n";
test();
std::cout << "test(memory_order_relaxed)\n";
test(memory_order_relaxed);
std::cout << "test(memory_order_consume)\n";
test(memory_order_consume);
std::cout << "test(memory_order_acquire)\n";
test(memory_order_acquire);
std::cout << "test(memory_order_release)\n";
test(memory_order_release);
std::cout << "test(memory_order_acq_rel)\n";
test(memory_order_acq_rel);
std::cout << "test(memory_order_seq_cst)\n";
test(memory_order_seq_cst);
std::cout << "test(memory_order_acquire, memory_order_consume)\n";
test(memory_order_acquire, memory_order_consume);
std::cout << "test(memory_order_acquire, memory_order_seq_cst)\n";
test(memory_order_acquire, memory_order_seq_cst);
}
test()
mem_success = 5
mem_failure = 5
------------------------
test(memory_order_relaxed)
mem_success = 0
mem_failure = 0
------------------------
test(memory_order_consume)
mem_success = 1
mem_failure = 1
------------------------
test(memory_order_acquire)
mem_success = 2
mem_failure = 2
------------------------
test(memory_order_release)
mem_success = 3
mem_failure = 0
------------------------
test(memory_order_acq_rel)
mem_success = 4
mem_failure = 2
------------------------
test(memory_order_seq_cst)
mem_success = 5
mem_failure = 5
------------------------
test(memory_order_acquire, memory_order_consume)
mem_success = 2
mem_failure = 1
------------------------
test(memory_order_acquire, memory_order_seq_cst)
mem_success = 2
mem_failure = 5
Assertion failed: (mem_success >= mem_failure), function test, file test.cpp, line 38.
Abort trap
-Howard
More information about the cfe-dev
mailing list