Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix detection of C11 atomics #68

Closed
wants to merge 1 commit into from

Conversation

tpetazzoni
Copy link
Contributor

Currently, the CMakeLists.txt logic to detect the availability of C11
atomics is based on building a small program that uses the
atomic_load().

However, atomic_load() does not need to use any function from
libatomic (part of the gcc runtime). So even if libatomic is missing,
this test concludes that C11 atomic support is available. For example
on SPARC, the example program builds fine without linking to
libatomic, but calling other functions of the atomic_*() APIs fail
without linking to libatomic.

So, this patch adjusts the CMakeLists.txt test to use a function that
is known to require the libatomic run-time library (on architectures
where it is needed). This way, openal will only use the _atomic*()
built-ins when they are actually functional.

Signed-off-by: Thomas Petazzoni thomas.petazzoni@free-electrons.com

Currently, the CMakeLists.txt logic to detect the availability of C11
atomics is based on building a small program that uses the
atomic_load().

However, atomic_load() does not need to use any function from
libatomic (part of the gcc runtime). So even if libatomic is missing,
this test concludes that C11 atomic support is available. For example
on SPARC, the example program builds fine without linking to
libatomic, but calling other functions of the atomic_*() APIs fail
without linking to libatomic.

So, this patch adjusts the CMakeLists.txt test to use a function that
is known to require the libatomic run-time library (on architectures
where it is needed). This way, openal will only use the __atomic_*()
built-ins when they are actually functional.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
@kcat
Copy link
Owner

kcat commented Sep 11, 2016

This will actually break Clang, or certain versions of it at least, which support C11 atomics but fail on things like atomic_load with a const _Atomic* parameter. A better option may be to simply check if libatomic exists and add it to the list of extra libraries if it does (similar to how libm is handled).

@kcat
Copy link
Owner

kcat commented Sep 12, 2016

Actually, I'm curious about the consequences of using libatomic. In normal cases, atomic methods should generate inline assembly rather than external function calls. If it's calling into a separate library, that makes me concerned that the functions are using slow mutex-protected implementations. Do both C11 atomics and GCC's built-in atomics both call into external functions? If so, why doesn't GCC's built-ins use the same lib as C11 atomics?

@tpetazzoni
Copy link
Contributor Author

@kcat There are platforms that really don't provide the appropriate atomic instructions, so there is no other choice than to have a slower mutex-based implementation. The code in libatomic is only used if there are no way around it.

@kcat
Copy link
Owner

kcat commented Sep 12, 2016

Okay, that makes sense. Commit a004ccf adds a check for, and links with, libatomic, so C11 atomics should work now. It'll also check atomic_fetch_add just to be sure. Does it work for you?

@tpetazzoni
Copy link
Contributor Author

@kcat Unfortunately, this doesn't work: it doesn't detect that atomic_fetch_add is available in libatomic (tested on SPARC, where all atomic_*() functions are provided in libatomic) :

-- Looking for atomic_fetch_add in atomic
-- Looking for atomic_fetch_add in atomic - not found

From the CMake error log:

etermining if the function atomic_fetch_add exists in the atomic failed with the following output:
Change Dir: /home/thomas/projets/buildroot/output/build/openal-1.17.2/CMakeFiles/CMakeTmp

Run Build Command:"/usr/bin/make" "cmTC_d499b/fast"
make[2]: Entering directory '/home/thomas/projets/buildroot/output/build/openal-1.17.2/CMakeFiles/CMakeTmp'
/usr/bin/make -f CMakeFiles/cmTC_d499b.dir/build.make CMakeFiles/cmTC_d499b.dir/build
make[3]: Entering directory '/home/thomas/projets/buildroot/output/build/openal-1.17.2/CMakeFiles/CMakeTmp'
Building C object CMakeFiles/cmTC_d499b.dir/CheckFunctionExists.c.o
/home/thomas/projets/buildroot/output/host/usr/bin/sparc-linux-gcc  --sysroot=/home/thomas/projets/buildroot/output/host/usr/sparc-buildroot-linux-uclibc/sysroot   -std=c11 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os  -DCHECK_FUNCTION_EXISTS=atomic_fetch_add  -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -D_LARGEFILE_SOURCE -D_LARGE_FILES   -o CMakeFiles/cmTC_d499b.dir/CheckFunctionExists.c.o   -c /home/thomas/projets/buildroot/output/host/usr/share/cmake-3.5/Modules/CheckFunctionExists.c
Linking C executable cmTC_d499b
/home/thomas/projets/buildroot/output/host/usr/bin/cmake -E cmake_link_script CMakeFiles/cmTC_d499b.dir/link.txt --verbose=1
/home/thomas/projets/buildroot/output/host/usr/bin/sparc-linux-gcc  --sysroot=/home/thomas/projets/buildroot/output/host/usr/sparc-buildroot-linux-uclibc/sysroot -std=c11 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os  -DCHECK_FUNCTION_EXISTS=atomic_fetch_add  -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -D_LARGEFILE_SOURCE -D_LARGE_FILES     CMakeFiles/cmTC_d499b.dir/CheckFunctionExists.c.o  -o cmTC_d499b -rdynamic -latomic 
CMakeFiles/cmTC_d499b.dir/CheckFunctionExists.c.o: In function `main':
CheckFunctionExists.c:(.text.startup+0x4): undefined reference to `atomic_fetch_add'
collect2: error: ld returned 1 exit status
CMakeFiles/cmTC_d499b.dir/build.make:97: recipe for target 'cmTC_d499b' failed
make[3]: *** [cmTC_d499b] Error 1
make[3]: Leaving directory '/home/thomas/projets/buildroot/output/build/openal-1.17.2/CMakeFiles/CMakeTmp'
Makefile:126: recipe for target 'cmTC_d499b/fast' failed
make[2]: *** [cmTC_d499b/fast] Error 2
make[2]: Leaving directory '/home/thomas/projets/buildroot/output/build/openal-1.17.2/CMakeFiles/CMakeTmp'

I am not sure how CMake is doing its function test, but atomic_fetch_add() is not a normal function, it gets replaced by a call to atomic_fetch_add_4, atomic_fetch_add_8, atomic_fetch_add_2, atomic_fetch_add_1 depending on the size of the integer passed as argument.

@kcat
Copy link
Owner

kcat commented Sep 12, 2016

I see. This is turning out to be unfortunate... I got the check working using a different method, but there's another issue. If libatomic exists in the build environment, it'll be linked. Even if it's not needed on the target, as long as it's included in the link command it'll be a(n unnecessary) dependency. Checking if it's actually needed isn't so simple either, since different CPU targets will have different needs (some may need external functions for incrementing/decrementing integers by more than one, some may need it for 8-byte types, some may need it for compare-exchange..).

@kcat
Copy link
Owner

kcat commented Sep 13, 2016

Commit af5fb3d should properly detect libatomic. I'll worry about linking it only when needed later. Does it work now? (make sure to do a fresh build, or clear CMakeCache.txt so it properly retests)

@kcat
Copy link
Owner

kcat commented Apr 24, 2017

Closing since this should be handled now. It links with libatomic if it's there, regardless if it's really needed or not. If there's still a problem, please open a new Issue or make a new PR.

@kcat kcat closed this Apr 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants