atomic.cpp: split into several versions one per executable

This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-11-15 00:00:00 +00:00
parent 730eb8e991
commit 627623157c
13 changed files with 154 additions and 9 deletions

View File

@@ -3899,25 +3899,28 @@ it fails with:
ld: cannot find -lopenblas
....
[[cpp-static-and-pthreads]]
===== C++ static and pthreads
`g++` and pthreads also causes issues:
* https://stackoverflow.com/questions/35116327/when-g-static-link-pthread-cause-segmentation-fault-why
* https://stackoverflow.com/questions/58848694/gcc-whole-archive-recipe-for-static-linking-to-pthread-stopped-working-in-rec
As a consequence, the following fails:
As a consequence, the following just hangs as of LKMC ca0403849e03844a328029d70c08556155dc1cd0 + 1 the example link:userland/cpp/atomic/std_atomic.cpp[]:
....
./run --userland userland/cpp/atomic.cpp --static
./run --userland userland/cpp/atomic/std_atomic.cpp --static
....
with error:
And before that, it used to fail with other randomly different errors, e.g.:
....
qemu-x86_64: /path/to/linux-kernel-module-cheat/submodules/qemu/accel/tcg/cpu-exec.c:700: cpu_exec: Assertion `!have_mmap_lock()' failed.
qemu-x86_64: /path/to/linux-kernel-module-cheat/submodules/qemu/accel/tcg/cpu-exec.c:700: cpu_exec: Assertion `!have_mmap_lock()' failed.
....
and if we manually build and run natively on host it segfaults.
And a native Ubuntu 18.04 AMD64 run with static compilation segfaults.
The workaround:
@@ -13894,7 +13897,21 @@ Programs under link:userland/cpp/[] are examples of https://en.wikipedia.org/wik
** link:userland/cpp/thread_get_id.cpp[] `std::thread::get_id`
** link:userland/cpp/thread_return_value.cpp[]: how to return a value from a thread
* https://en.cppreference.com/w/cpp/header/atomic[`<atomic>`]: <<cpp17>> 32 "Atomic operations library"
** link:userland/cpp/atomic.cpp[]
===== atomic.cpp
link:userland/cpp/atomic/[]
In this set of examples, we exemplify various synchronization mechanisms, including assembly specific ones, by using the convenience of C++ multithreading:
* link:userland/cpp/atomic/main.hpp[]: contains all the code which is then specialized in spearated cpp files with macros
* link:userland/cpp/atomic/aarch64_add.cpp[]: non synchronized aarch64 inline assembly
* link:userland/cpp/atomic/aarch64_ldadd.cpp[]: synchronized aarch64 inline assembly
* link:userland/cpp/atomic/fail.cpp[]: non synchronized C++ operator `++`
* link:userland/cpp/atomic/mutex.cpp[]: synchronized `std::mutex`
* link:userland/cpp/atomic/std_atomic.cpp[]: synchronized `std::atomic_ulong`
* link:userland/cpp/atomic/x86_64_inc.cpp[]: non synchronized x86_64 inline assembly
* link:userland/cpp/atomic/x86_64_lock_inc.cpp[]: synchronized x86_64 inline assembly
[[cpp-standards]]
==== C++ standards
@@ -15456,7 +15473,7 @@ TODO We didn't manage to find a working ARM analogue to <<x86-rdtsc-instruction>
==== x86 LOCK prefix
Inline assembly example at: link:userland/cpp/atomic.cpp[]
Inline assembly example at: link:userland/cpp/atomic/x86_64_lock_inc.cpp[], see also: <<atomic-cpp>>.
Ensures that memory modifications are visible across all CPUs, which is fundamental for thread synchronization.
@@ -16529,7 +16546,7 @@ That document then describes the SVE instructions and registers.
<<armarm8-db>> "ARMv8.1-LSE, ARMv8.1 Large System Extensions"
* LDADD: link:userland/cpp/atomic.cpp[]
* LDADD: link:userland/cpp/atomic/aarch64_ldadd.cpp[], see also: <<atomic-cpp>>.
Bibliography:

View File

@@ -213,7 +213,7 @@ class PathProperties:
os.path.splitext(self.path_components[-1])[1] == '.c' and self['arm_sve']
) and not (
# C++ multithreading in static does not seem to work:
# https://cirosantilli.com/linux-kernel-module-cheat#user-mode-static-executables-with-dynamic-libraries
# https://cirosantilli.com/linux-kernel-module-cheat#cpp-static-and-pthreads
os.path.splitext(self.path_components[-1])[1] == '.cpp' and (
# TODO the better check here would be for 'static'
# to factor out with test-executable logic, but lazy.
@@ -581,7 +581,17 @@ path_properties_tuples = (
'cpp': (
{},
{
'atomic.cpp': {'test_run_args': {'cpus': 3}},
'atomic': (
{
'test_run_args': {'cpus': 3},
},
{
'aarch64_add.cpp': {'allowed_archs': {'aarch64'}},
'aarch64_ldadd.cpp': {'allowed_archs': {'aarch64'}},
'x86_64_add.cpp': {'allowed_archs': {'x86_64'}},
'x86_64_ldadd.cpp': {'allowed_archs': {'x86_64'}},
},
),
'count.cpp': {'more_than_1s': True},
'sleep_for.cpp': {
'more_than_1s': True,

View File

@@ -0,0 +1 @@
// https://cirosantilli.com/linux-kernel-module-cheat#atomic-cpp

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_AARCH64_ADD
#include "main.hpp"

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_AARCH64_LDADD
#include "main.hpp"

1
userland/cpp/atomic/build Symbolic link
View File

@@ -0,0 +1 @@
../build

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_FAIL
#include "main.hpp"

View File

@@ -0,0 +1,101 @@
// https://cirosantilli.com/linux-kernel-module-cheat#atomic-cpp
#if __cplusplus >= 201103L
#include <atomic>
#include <cassert>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
size_t niters;
#if defined(LKMC_USERLAND_ATOMIC_STD_ATOMIC)
std::atomic_ulong global(0);
#else
uint64_t global = 0;
#endif
#if defined(LKMC_USERLAND_ATOMIC_MUTEX)
std::mutex mutex;
#endif
void threadMain() {
for (size_t i = 0; i < niters; ++i) {
#if defined(LKMC_USERLAND_ATOMIC_MUTEX)
mutex.lock();
#endif
#if defined(LKMC_USERLAND_ATOMIC_X86_64_INC)
__asm__ __volatile__ (
"incq %0;"
: "+g" (global)
:
:
);
#elif defined(LKMC_USERLAND_ATOMIC_X86_64_LOCK_INC)
// https://cirosantilli.com/linux-kernel-module-cheat#x86-lock-prefix
__asm__ __volatile__ (
"lock;"
"incq %0;"
: "+m" (global)
:
:
);
#elif defined(LKMC_USERLAND_ATOMIC_AARCH64_ADD)
__asm__ __volatile__ (
"add %0, %0, 1;"
: "+r" (global)
:
:
);
#elif defined(LKMC_USERLAND_ATOMIC_AARCH64_LDADD)
// https://cirosantilli.com/linux-kernel-module-cheat#arm-lse
__asm__ __volatile__ (
"ldadd %[inc], xzr, [%[addr]];"
: "=m" (global)
: [inc] "r" (1),
[addr] "r" (&global)
:
);
#else
global++;
#endif
#if defined(LKMC_USERLAND_ATOMIC_MUTEX)
mutex.unlock();
#endif
#if 0
#endif
}
}
#endif
int main(int argc, char **argv) {
#if __cplusplus >= 201103L
size_t nthreads;
if (argc > 1) {
nthreads = std::stoull(argv[1], NULL, 0);
} else {
nthreads = 2;
}
if (argc > 2) {
niters = std::stoull(argv[2], NULL, 0);
} else {
niters = 10;
}
std::vector<std::thread> threads(nthreads);
for (size_t i = 0; i < nthreads; ++i)
threads[i] = std::thread(threadMain);
for (size_t i = 0; i < nthreads; ++i)
threads[i].join();
uint64_t expect = nthreads * niters;
#if defined(LKMC_USERLAND_ATOMIC_FAIL) || \
defined(LKMC_USERLAND_ATOMIC_X86_64_INC) || \
defined(LKMC_USERLAND_ATOMIC_AARCH64_INC)
// These fail, so we just print the outcomes.
std::cout << "expect " << expect << std::endl;
std::cout << "global " << global << std::endl;
#else
assert(global == expect);
#endif
#endif
}

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_MUTEX
#include "main.hpp"

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_STD_ATOMIC
#include "main.hpp"

1
userland/cpp/atomic/test Symbolic link
View File

@@ -0,0 +1 @@
../test

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_X86_64_INC
#include "main.hpp"

View File

@@ -0,0 +1,2 @@
#define LKMC_USERLAND_ATOMIC_X86_64_LOCK_INC
#include "main.hpp"