mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-23 02:05:57 +01:00
Detailed gem5 analysis of how data races happen
And pass niters as a thread argument to all threading implementations... otherwise every loop has to do a memory load from the global!
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#c-multithreading */
|
||||
/* https://cirosantilli.com/linux-kernel-module-cheat#atomic-c */
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
||||
#include <stdatomic.h>
|
||||
@@ -9,10 +9,9 @@
|
||||
|
||||
atomic_int acnt;
|
||||
int cnt;
|
||||
size_t niters;
|
||||
|
||||
int f(void *thr_data) {
|
||||
(void)thr_data;
|
||||
int my_thread_main(void *thr_data) {
|
||||
size_t niters = *(size_t *)thr_data;
|
||||
for (size_t i = 0; i < niters; ++i) {
|
||||
++cnt;
|
||||
++acnt;
|
||||
@@ -23,7 +22,7 @@ int f(void *thr_data) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
||||
size_t nthreads;
|
||||
size_t niters, nthreads;
|
||||
thrd_t *threads;
|
||||
if (argc > 1) {
|
||||
nthreads = strtoull(argv[1], NULL, 0);
|
||||
@@ -37,7 +36,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
threads = malloc(sizeof(thrd_t) * nthreads);
|
||||
for(size_t i = 0; i < nthreads; ++i)
|
||||
thrd_create(threads + i, f, NULL);
|
||||
thrd_create(threads + i, my_thread_main, &niters);
|
||||
for(size_t i = 0; i < nthreads; ++i)
|
||||
thrd_join(threads[i], NULL);
|
||||
free(threads);
|
||||
|
||||
@@ -39,14 +39,18 @@ int main(void) {
|
||||
/* Less common case where string does not fit. Error handling would
|
||||
* normally follow in a real program. */
|
||||
{
|
||||
int in = 1234;
|
||||
char out[6];
|
||||
/* The return here is the same as before.
|
||||
*
|
||||
* Because it is >= than the imposed limit of 6, we know that
|
||||
* the write failed to fully complete. */
|
||||
#if 0
|
||||
/* GCC 8.3.0 with -O3 actually detects this and breaks the build.
|
||||
* error: ‘cd’ directive output truncated writing 2 bytes into a region of size 0 [-Werror=format-truncation=] */
|
||||
int in = 1234;
|
||||
char out[6];
|
||||
assert(snprintf(out, sizeof(out), "ab%dcd", in) == 8);
|
||||
assert(strcmp(out, "ab123") == 0);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
size_t niters;
|
||||
|
||||
#if LKMC_USERLAND_ATOMIC_STD_ATOMIC
|
||||
std::atomic_ulong global(0);
|
||||
#else
|
||||
@@ -20,7 +18,7 @@ uint64_t global = 0;
|
||||
std::mutex mutex;
|
||||
#endif
|
||||
|
||||
void threadMain() {
|
||||
void threadMain(size_t niters) {
|
||||
for (size_t i = 0; i < niters; ++i) {
|
||||
#if LKMC_USERLAND_ATOMIC_MUTEX
|
||||
mutex.lock();
|
||||
@@ -97,7 +95,7 @@ void threadMain() {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#if __cplusplus >= 201103L
|
||||
size_t nthreads;
|
||||
size_t niters, nthreads;
|
||||
if (argc > 1) {
|
||||
nthreads = std::stoull(argv[1], NULL, 0);
|
||||
} else {
|
||||
@@ -110,7 +108,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
std::vector<std::thread> threads(nthreads);
|
||||
for (size_t i = 0; i < nthreads; ++i)
|
||||
threads[i] = std::thread(threadMain);
|
||||
threads[i] = std::thread(threadMain, niters);
|
||||
for (size_t i = 0; i < nthreads; ++i)
|
||||
threads[i].join();
|
||||
uint64_t expect = nthreads * niters;
|
||||
|
||||
@@ -25,9 +25,13 @@ int main(int argc, char **argv) {
|
||||
request = strtol(argv[2], NULL, 10);
|
||||
if (argc > 3) {
|
||||
arg0 = strtol(argv[3], NULL, 10);
|
||||
} else {
|
||||
arg0 = 0;
|
||||
}
|
||||
if (argc > 4) {
|
||||
arg1 = strtol(argv[4], NULL, 10);
|
||||
} else {
|
||||
arg1 = 0;
|
||||
}
|
||||
|
||||
fd = open(ioctl_path, O_RDONLY);
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
unsigned long long niters;
|
||||
unsigned long long global = 0;
|
||||
pthread_mutex_t main_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void* main_thread(void *arg) {
|
||||
(void)arg;
|
||||
unsigned long long niters = *(unsigned long long *)arg;
|
||||
unsigned long long i;
|
||||
for (i = 0; i < niters; ++i) {
|
||||
pthread_mutex_lock(&main_thread_mutex);
|
||||
@@ -24,7 +23,7 @@ void* main_thread(void *arg) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pthread_t *threads;
|
||||
unsigned long long i, nthreads;
|
||||
unsigned long long i, niters, nthreads;
|
||||
|
||||
/* CLI arguments. */
|
||||
if (argc > 1) {
|
||||
@@ -41,7 +40,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* Action */
|
||||
for (i = 0; i < nthreads; ++i)
|
||||
pthread_create(&threads[i], NULL, main_thread, NULL);
|
||||
pthread_create(&threads[i], NULL, main_thread, &niters);
|
||||
for (i = 0; i < nthreads; ++i)
|
||||
pthread_join(threads[i], NULL);
|
||||
assert(global == nthreads * niters);
|
||||
|
||||
Reference in New Issue
Block a user