mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-28 20:44:26 +01:00
atomic.cpp: split into several versions one per executable
This commit is contained in:
31
README.adoc
31
README.adoc
@@ -3899,25 +3899,28 @@ it fails with:
|
|||||||
ld: cannot find -lopenblas
|
ld: cannot find -lopenblas
|
||||||
....
|
....
|
||||||
|
|
||||||
|
[[cpp-static-and-pthreads]]
|
||||||
|
===== C++ static and pthreads
|
||||||
|
|
||||||
`g++` and pthreads also causes issues:
|
`g++` and pthreads also causes issues:
|
||||||
|
|
||||||
* https://stackoverflow.com/questions/35116327/when-g-static-link-pthread-cause-segmentation-fault-why
|
* 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
|
* 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.
|
||||||
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:
|
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_get_id.cpp[] `std::thread::get_id`
|
||||||
** link:userland/cpp/thread_return_value.cpp[]: how to return a value from a thread
|
** 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"
|
* 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]]
|
[[cpp-standards]]
|
||||||
==== C++ 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
|
==== 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.
|
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"
|
<<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:
|
Bibliography:
|
||||||
|
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ class PathProperties:
|
|||||||
os.path.splitext(self.path_components[-1])[1] == '.c' and self['arm_sve']
|
os.path.splitext(self.path_components[-1])[1] == '.c' and self['arm_sve']
|
||||||
) and not (
|
) and not (
|
||||||
# C++ multithreading in static does not seem to work:
|
# 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 (
|
os.path.splitext(self.path_components[-1])[1] == '.cpp' and (
|
||||||
# TODO the better check here would be for 'static'
|
# TODO the better check here would be for 'static'
|
||||||
# to factor out with test-executable logic, but lazy.
|
# to factor out with test-executable logic, but lazy.
|
||||||
@@ -581,7 +581,17 @@ path_properties_tuples = (
|
|||||||
'cpp': (
|
'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},
|
'count.cpp': {'more_than_1s': True},
|
||||||
'sleep_for.cpp': {
|
'sleep_for.cpp': {
|
||||||
'more_than_1s': True,
|
'more_than_1s': True,
|
||||||
|
|||||||
1
userland/cpp/atomic/README.adoc
Normal file
1
userland/cpp/atomic/README.adoc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// https://cirosantilli.com/linux-kernel-module-cheat#atomic-cpp
|
||||||
2
userland/cpp/atomic/aarch64_add.cpp
Normal file
2
userland/cpp/atomic/aarch64_add.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_AARCH64_ADD
|
||||||
|
#include "main.hpp"
|
||||||
2
userland/cpp/atomic/aarch64_ldadd.cpp
Normal file
2
userland/cpp/atomic/aarch64_ldadd.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_AARCH64_LDADD
|
||||||
|
#include "main.hpp"
|
||||||
1
userland/cpp/atomic/build
Symbolic link
1
userland/cpp/atomic/build
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../build
|
||||||
2
userland/cpp/atomic/fail.cpp
Normal file
2
userland/cpp/atomic/fail.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_FAIL
|
||||||
|
#include "main.hpp"
|
||||||
101
userland/cpp/atomic/main.hpp
Normal file
101
userland/cpp/atomic/main.hpp
Normal 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
|
||||||
|
}
|
||||||
2
userland/cpp/atomic/mutex.cpp
Normal file
2
userland/cpp/atomic/mutex.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_MUTEX
|
||||||
|
#include "main.hpp"
|
||||||
2
userland/cpp/atomic/std_atomic.cpp
Normal file
2
userland/cpp/atomic/std_atomic.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_STD_ATOMIC
|
||||||
|
#include "main.hpp"
|
||||||
1
userland/cpp/atomic/test
Symbolic link
1
userland/cpp/atomic/test
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../test
|
||||||
2
userland/cpp/atomic/x86_64_inc.cpp
Normal file
2
userland/cpp/atomic/x86_64_inc.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_X86_64_INC
|
||||||
|
#include "main.hpp"
|
||||||
2
userland/cpp/atomic/x86_64_lock_inc.cpp
Normal file
2
userland/cpp/atomic/x86_64_lock_inc.cpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define LKMC_USERLAND_ATOMIC_X86_64_LOCK_INC
|
||||||
|
#include "main.hpp"
|
||||||
Reference in New Issue
Block a user