Ok, attached is a testcase which should test all std::atomic<> and 
std::atomic_flag features (atomic<> only for specialization atomic<int>). 
On failure this does a standard assert(), not sure whether this is 
compatible with the emscripten test suite. On success "success!" is printed 
and the code exits with return value 0.

To compile on native clang (tested with OSX native clang):

clang -std=c++11 test_atomic.cpp -o test_atomic

Compiling with emscripten only works with the i386-pc-linux-gnu triple, all 
tests work in this case :)

EMCC_LLVM_TARGET=i386-pc-linux-gnu ~/emscripten/emcc -std=c++11 
test_atomic.cpp -o test.html

Is the plan to get this working with the standard-triple? If this is not 
feasible, maybe selecting the LLVM_TARGET through a "-s" command line 
setting instead of an environment variable might be a good solution in the 
meantime?

Cheers,
-Floh

Am Dienstag, 17. Dezember 2013 13:01:33 UTC+1 schrieb Floh:

> Using the i386-pc-linux-gnu target does indeed work out of the box! I'll 
> write a little test case. Getting at least the C++11 atomic stuff 
> transparently working would indeed be very cool. I'll write a little test 
> case next.
>
> Am Montag, 16. Dezember 2013 23:12:49 UTC+1 schrieb azakai:
>>
>> This might be a limitation of the le32 target, does x86 have it? try with 
>> EMCC_LLVM_TARGET=i386-pc-linux-gnu in the environment. If so though, that's 
>> not good workaround, but at least we'd know what needs fixing.
>>
>> Can you make a testcase of this? I can test it on latest upstream le32 as 
>> well.
>>
>> - Alon
>>
>>
>>
>> On Mon, Dec 16, 2013 at 9:00 AM, Floh <[email protected]> wrote:
>>
>>> Hi,
>>>
>>> I'm currently playing around with C++11 as a side project, and I'm 
>>> having trouble in emscripten with std::atomic (somewhat expected, but I was 
>>> naively hoping that this compiles to some sort of dummy implementation).
>>>
>>> I'm having these problems:
>>>
>>> std::atomic<int> increment and decrement produces these errors:
>>>
>>> '''
>>> In file included from 
>>> /Users/floh/emscripten/system/include/libcxx/memory:610:
>>> /Users/floh/emscripten/system/include/libcxx/atomic:667:17: error: 
>>> cannot compile this atomic library call yet
>>>         {return __c11_atomic_fetch_sub(&this->__a_, __op, __m);}
>>>                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> /Users/floh/emscripten/system/include/libcxx/atomic:661:17: error: 
>>> cannot compile this atomic library call yet
>>>         {return __c11_atomic_fetch_add(&this->__a_, __op, __m);}
>>>                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> '''
>>>
>>> This looks like this is already happening in clang, but going from 3.2 
>>> to 3.3 didn't help.
>>>
>>> The other problem is a simple linker error that __atomic_load can't be 
>>> resolved.
>>>
>>> Other than this threading/atomic stuff I didn't encounter other C++11 
>>> problems in emscripten so far (but I've only scratched the surface yet: 
>>> in-class member-initialisation, move-stuff, make_shared and the new for (x 
>>> : y) loop stuff).
>>>
>>> Cheers,
>>> -Floh.
>>>
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "emscripten-discuss" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to [email protected].
>>> For more options, visit https://groups.google.com/groups/opt_out.
>>>
>>
>>

-- 
You received this message because you are subscribed to the Google Groups 
"emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
// test C++11 atomic<int> and atomic_flag
#include <atomic>
#include <cassert>
#include <cstdio>

int main() {
    int val;
    bool res;

    // construction and assignment
    std::atomic<int> a0(5);
    assert(a0 == 5);
    std::atomic<int> a1{6};
    assert(a1 == 6);
    a1 = 7;
    assert(a1 == 7);

    // 32-bit int should be lock-free on all CPUs(?)
    assert(a0.is_lock_free());

    // load and store    
    a0.store(1);
    assert(a0 == 1);
    val = a0.load();
    assert(val == 1);
    a0.store(2, std::memory_order_release);
    assert(a0 == 2);
    val = a0.load(std::memory_order_acquire);
    assert(val == 2);

    // exchange
    val = a0.exchange(3);
    assert(val == 2 && a0 == 3);
    val = a0.exchange(4, std::memory_order_relaxed);
    assert(val == 3 && a0 == 4);

    // compare_exchange_weak
    int expected = 1;
    int desired = 2;
    a0 = 3;
    res = a0.compare_exchange_weak(expected, desired);
    // this should have failed since expected != a0, expected has been written with a0
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = a0.compare_exchange_weak(expected, desired);
    // this should have worked, and a0 should now be desired
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    // repeat for compare_exchange_strong
    expected = 1;
    desired = 2;
    a0 = 3;
    res = a0.compare_exchange_strong(expected, desired);
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = a0.compare_exchange_strong(expected, desired);
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    // fetch methods
    a0 = 1;
    val = a0.fetch_add(2);
    assert(val == 1 && a0 == 3);
    val = a0.fetch_sub(2);
    assert(val == 3 && a0 == 1);
    a0 = 0xFEFE;
    val = a0.fetch_and(0x0F0F);
    assert(val == 0xFEFE && a0 == 0x0E0E);
    val = a0.fetch_or(0x1010);
    assert(val == 0x0E0E && a0 == 0x1E1E);
    val = a0.fetch_xor(0xFFFF);
    assert(val == 0x1E1E && a0 == 0xE1E1);

    // operators
    a0 = 0;
    a0++;
    assert(a0 == 1);
    ++a0;
    assert(a0 == 2);
    a0--;
    assert(a0 == 1);
    --a0;
    assert(a0 == 0);
    a0 += 5;
    assert(a0 == 5);
    a0 -= 5;
    assert(a0 == 0);
    a0 = 0xFEFE;
    a0 &= 0x0F0F;
    assert(a0 == 0x0E0E);
    a0 |= 0x1010;
    assert(a0 == 0x1E1E);
    a0 ^= 0xFFFF;
    assert(a0 == 0xE1E1);
    std::atomic<int> a2;
    a0 = 1;
    a1 = 2;
    a2 = a0 + a1;
    assert(a2 == 3);

    // quickly go through the global functions
    std::atomic_init(&a0, 0);
    assert(a0 == 0);
    res = std::atomic_is_lock_free(&a0);
    assert(res);
    std::atomic_store(&a0, 2);
    assert(a0 == 2);
    val = std::atomic_load(&a0);
    assert(val == 2);
    std::atomic_store_explicit(&a0, 3, std::memory_order_release);
    assert(a0 == 3);
    val = std::atomic_load_explicit(&a0, std::memory_order_acquire);
    assert(val == 3);
    val = std::atomic_exchange(&a0, 4);
    assert(val == 3 && a0 == 4);
    val = std::atomic_exchange_explicit(&a0, 3, std::memory_order_relaxed);
    assert(val == 4 && a0 == 3);

    expected = 1;
    desired = 2;
    std::atomic_store(&a0, 3);
    res = std::atomic_compare_exchange_weak(&a0, &expected, desired);
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = std::atomic_compare_exchange_weak(&a0, &expected, desired);
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    expected = 1;
    desired = 2;
    std::atomic_store(&a0, 3);
    res = std::atomic_compare_exchange_strong(&a0, &expected, desired);
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = std::atomic_compare_exchange_strong(&a0, &expected, desired);
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    expected = 1;
    desired = 2;
    std::atomic_store(&a0, 3);
    res = std::atomic_compare_exchange_weak_explicit(&a0, &expected, desired, std::memory_order_relaxed, std::memory_order_relaxed);
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = std::atomic_compare_exchange_weak_explicit(&a0, &expected, desired, std::memory_order_relaxed, std::memory_order_relaxed);
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    expected = 1;
    desired = 2;
    std::atomic_store(&a0, 3);
    res = std::atomic_compare_exchange_strong_explicit(&a0, &expected, desired, std::memory_order_relaxed, std::memory_order_relaxed);
    assert(!res && expected == 3 && desired == 2 && a0 == 3);
    res = std::atomic_compare_exchange_strong_explicit(&a0, &expected, desired, std::memory_order_relaxed, std::memory_order_relaxed);
    assert(res && expected == 3 && desired == 2 && a0 == 2);

    a0 = 1;
    val = std::atomic_fetch_add(&a0, 2);
    assert(val == 1 && a0 == 3);
    val = std::atomic_fetch_sub(&a0, 2);
    assert(val == 3 && a0 == 1);
    a0 = 0xFEFE;
    val = std::atomic_fetch_and(&a0, 0x0F0F);
    assert(val == 0xFEFE && a0 == 0x0E0E);
    val = std::atomic_fetch_or(&a0, 0x1010);
    assert(val == 0x0E0E && a0 == 0x1E1E);
    val = std::atomic_fetch_xor(&a0, 0xFFFF);
    assert(val == 0x1E1E && a0 == 0xE1E1);

    a0 = 1;
    val = std::atomic_fetch_add_explicit(&a0, 2, std::memory_order_relaxed);
    assert(val == 1 && a0 == 3);
    val = std::atomic_fetch_sub_explicit(&a0, 2, std::memory_order_relaxed);
    assert(val == 3 && a0 == 1);
    a0 = 0xFEFE;
    val = std::atomic_fetch_and_explicit(&a0, 0x0F0F, std::memory_order_relaxed);
    assert(val == 0xFEFE && a0 == 0x0E0E);
    val = std::atomic_fetch_or_explicit(&a0, 0x1010, std::memory_order_relaxed);
    assert(val == 0x0E0E && a0 == 0x1E1E);
    val = std::atomic_fetch_xor_explicit(&a0, 0xFFFF, std::memory_order_relaxed);
    assert(val == 0x1E1E && a0 == 0xE1E1);

    // atomic_flag
    std::atomic_flag f = ATOMIC_FLAG_INIT;
    res = f.test_and_set(); 
    assert(!res);
    res = f.test_and_set();
    assert(res);
    f.clear();
    res = f.test_and_set();
    assert(!res);
    f.clear();

    res = std::atomic_flag_test_and_set(&f);
    assert(!res);
    res = std::atomic_flag_test_and_set(&f);
    assert(res);
    std::atomic_flag_clear(&f);

    res = std::atomic_flag_test_and_set_explicit(&f, std::memory_order_acquire);
    assert(!res);
    res = std::atomic_flag_test_and_set_explicit(&f, std::memory_order_acquire);
    assert(res);
    std::atomic_flag_clear_explicit(&f, std::memory_order_release);
    res = std::atomic_flag_test_and_set_explicit(&f, std::memory_order_acquire);
    assert(!res);    

    printf("success!\n");
    return 0;
}

Reply via email to