From: Martin Quinson Date: Sun, 12 Nov 2023 19:33:45 +0000 (+0100) Subject: Implement pthread_barrier calls in sthread, and test them in McMini X-Git-Tag: v3.35~72 X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/ad02a1b4a1730fb36f36295f8749d4811f4d9a65 Implement pthread_barrier calls in sthread, and test them in McMini --- diff --git a/MANIFEST.in b/MANIFEST.in index 21a22fee78..3a533855d2 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -670,6 +670,22 @@ include teshsuite/mc/mcmini/producer_consumer_deadlock.c include teshsuite/mc/mcmini/producer_consumer_deadlock.tesh include teshsuite/mc/mcmini/producer_consumer_ok.c include teshsuite/mc/mcmini/producer_consumer_ok.tesh +include teshsuite/mc/mcmini/simple_barrier_deadlock.c +include teshsuite/mc/mcmini/simple_barrier_deadlock.tesh +include teshsuite/mc/mcmini/simple_barrier_ok.c +include teshsuite/mc/mcmini/simple_barrier_ok.tesh +include teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c +include teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh +include teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c +include teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh +include teshsuite/mc/mcmini/simple_mutex_deadlock.c +include teshsuite/mc/mcmini/simple_mutex_deadlock.tesh +include teshsuite/mc/mcmini/simple_mutex_ok.c +include teshsuite/mc/mcmini/simple_mutex_ok.tesh +include teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.c +include teshsuite/mc/mcmini/simple_mutex_with_threads_deadlock.tesh +include teshsuite/mc/mcmini/simple_mutex_with_threads_ok.c +include teshsuite/mc/mcmini/simple_mutex_with_threads_ok.tesh include teshsuite/mc/mcmini/simple_semaphore_deadlock.c include teshsuite/mc/mcmini/simple_semaphore_deadlock.tesh include teshsuite/mc/mcmini/simple_semaphores_deadlock.c diff --git a/src/sthread/sthread.c b/src/sthread/sthread.c index 7ba6a23181..6f2073381a 100644 --- a/src/sthread/sthread.c +++ b/src/sthread/sthread.c @@ -34,6 +34,10 @@ static int (*raw_pthread_mutexattr_gettype)(const pthread_mutexattr_t* restrict, static int (*raw_pthread_mutexattr_getrobust)(const pthread_mutexattr_t*, int*); static int (*raw_pthread_mutexattr_setrobust)(pthread_mutexattr_t*, int); +static int (*raw_pthread_barrier_init)(pthread_barrier_t*, const pthread_barrierattr_t*, unsigned int count); +static int (*raw_pthread_barrier_wait)(pthread_barrier_t*); +static int (*raw_pthread_barrier_destroy)(pthread_barrier_t*); + static unsigned int (*raw_sleep)(unsigned int); static int (*raw_usleep)(useconds_t); static int (*raw_gettimeofday)(struct timeval*, void*); @@ -62,6 +66,10 @@ static void intercepter_init() raw_pthread_mutexattr_getrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_getrobust"); raw_pthread_mutexattr_setrobust = dlsym(RTLD_NEXT, "pthread_mutexattr_setrobust"); + raw_pthread_barrier_init = dlsym(RTLD_NEXT, "raw_pthread_barrier_init"); + raw_pthread_barrier_wait = dlsym(RTLD_NEXT, "raw_pthread_barrier_wait"); + raw_pthread_barrier_destroy = dlsym(RTLD_NEXT, "raw_pthread_barrier_destroy"); + raw_sleep = dlsym(RTLD_NEXT, "sleep"); raw_usleep = dlsym(RTLD_NEXT, "usleep"); raw_gettimeofday = dlsym(RTLD_NEXT, "gettimeofday"); @@ -121,6 +129,11 @@ intercepted_pthcall(mutex_trylock, (pthread_mutex_t * mutex), (mutex), ((sthread intercepted_pthcall(mutex_unlock, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex)); intercepted_pthcall(mutex_destroy, (pthread_mutex_t * mutex), (mutex), ((sthread_mutex_t*)mutex)); +intercepted_pthcall(barrier_init, (pthread_barrier_t * barrier, const pthread_barrierattr_t* attr, unsigned count), + (barrier, attr, count), ((sthread_barrier_t*)barrier, (const sthread_barrierattr_t*)attr, count)); +intercepted_pthcall(barrier_wait, (pthread_barrier_t* barrier),( barrier),((sthread_barrier_t*) barrier)); +intercepted_pthcall(barrier_destroy, (pthread_barrier_t* barrier),( barrier),((sthread_barrier_t*) barrier)); + #define intercepted_call(rettype, name, raw_params, call_params, sim_params) \ rettype name raw_params \ { \ diff --git a/src/sthread/sthread.h b/src/sthread/sthread.h index 4a518667f8..6d9c0fa722 100644 --- a/src/sthread/sthread.h +++ b/src/sthread/sthread.h @@ -52,6 +52,17 @@ int sthread_mutex_trylock(sthread_mutex_t* mutex); int sthread_mutex_unlock(sthread_mutex_t* mutex); int sthread_mutex_destroy(sthread_mutex_t* mutex); +typedef struct { + unsigned unused : 1; +} sthread_barrierattr_t; + +typedef struct { + void* barrier; +} sthread_barrier_t; +int sthread_barrier_init(sthread_barrier_t* barrier, const sthread_barrierattr_t* attr, unsigned count); +int sthread_barrier_wait(sthread_barrier_t* barrier); +int sthread_barrier_destroy(sthread_barrier_t* barrier); + typedef struct { void* sem; } sthread_sem_t; diff --git a/src/sthread/sthread_impl.cpp b/src/sthread/sthread_impl.cpp index e54a9c3014..fda1411572 100644 --- a/src/sthread/sthread_impl.cpp +++ b/src/sthread/sthread_impl.cpp @@ -5,6 +5,7 @@ /* SimGrid's pthread interposer. Actual implementation of the symbols (see the comment in sthread.h) */ +#include "simgrid/s4u/Barrier.hpp" #include "smpi/smpi.h" #include "xbt/asserts.h" #include "xbt/ex.h" @@ -48,7 +49,7 @@ int sthread_main(int argc, char** argv, char** envp, int (*raw_main)(int, char** } /* Do not intercept valgrind step 1 */ - if (not strcmp(argv[0], "/usr/bin/valgrind.bin") || not strcmp(argv[0], "/bin/sh")) { + if (not strcmp(argv[0], "/usr/bin/valgrind.bin") || not strcmp(argv[0], "/bin/sh")|| not strcmp(argv[0], "/bin/bash")|| not strcmp(argv[0], "gdb")) { printf("sthread refuses to intercept the execution of %s. Running the application unmodified.\n", argv[0]); fflush(stdout); return raw_main(argc, argv, envp); @@ -218,6 +219,25 @@ int sthread_mutex_destroy(sthread_mutex_t* mutex) intrusive_ptr_release(static_cast(mutex->mutex)); return 0; } + +int sthread_barrier_init(sthread_barrier_t* barrier, const sthread_barrierattr_t* attr, unsigned count){ + auto b = sg4::Barrier::create(count); + intrusive_ptr_add_ref(b.get()); + + barrier->barrier = b.get(); + return 0; +} +int sthread_barrier_wait(sthread_barrier_t* barrier){ + XBT_DEBUG("%s(%p)", __func__, barrier); + static_cast(barrier->barrier)->wait(); + return 0; +} +int sthread_barrier_destroy(sthread_barrier_t* barrier){ + XBT_DEBUG("%s(%p)", __func__, barrier); + intrusive_ptr_release(static_cast(barrier->barrier)); + return 0; +} + int sthread_sem_init(sthread_sem_t* sem, int /*pshared*/, unsigned int value) { auto s = sg4::Semaphore::create(value); diff --git a/teshsuite/mc/CMakeLists.txt b/teshsuite/mc/CMakeLists.txt index 8432916476..41cad5ea1d 100644 --- a/teshsuite/mc/CMakeLists.txt +++ b/teshsuite/mc/CMakeLists.txt @@ -56,7 +56,6 @@ foreach(x simple_semaphores_with_threads_ok simple_semaphores_with_threads_deadlock # # philosophers_spurious_deadlock -# simple_barrier_with_threads_deadlock # simple_cond_broadcast_with_semaphore_deadlock1 simple_cond_broadcast_with_semaphore_deadlock2 barber_shop_ok barber_shop_deadlock @@ -67,7 +66,9 @@ foreach(x # producer_consumer_spurious_nok # infinite no-op loop -# simple_barrier_ok simple_barrier_with_threads_ok simple_cond_broadcast_ok + simple_barrier_ok simple_barrier_deadlock + simple_barrier_with_threads_ok simple_barrier_with_threads_deadlock +# simple_cond_broadcast_ok # simple_cond_broadcast_with_semaphore_ok simple_cond_ok # simple_threads_ok ) diff --git a/teshsuite/mc/mcmini/simple_barrier_deadlock.c b/teshsuite/mc/mcmini/simple_barrier_deadlock.c new file mode 100644 index 0000000000..16805ad4ba --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_deadlock.c @@ -0,0 +1,10 @@ +#include + +pthread_barrier_t barrier; + +int main(int argc, char* argv[]) { + pthread_barrier_init(&barrier, NULL, 2); + pthread_barrier_wait(&barrier); + return 0; +} + diff --git a/teshsuite/mc/mcmini/simple_barrier_deadlock.tesh b/teshsuite/mc/mcmini/simple_barrier_deadlock.tesh new file mode 100644 index 0000000000..0b5980f7e3 --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_deadlock.tesh @@ -0,0 +1,17 @@ +# We ignore the LD_PRELOAD lines from the expected output because they contain the build path +! ignore .*LD_PRELOAD.* + +! expect return 3 +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_deadlock +> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor' +> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor. +> [0.000000] [mc_global/INFO] ************************** +> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED *** +> [0.000000] [mc_global/INFO] ************************** +> [0.000000] [ker_engine/INFO] 1 actors are still running, waiting for something. +> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor (@): " +> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall BARRIER_WAIT(barrier_id:0) +> [0.000000] [mc_global/INFO] Counter-example execution trace: +> [0.000000] [mc_global/INFO] Actor 1 in simcall BARRIER_ASYNC_LOCK(barrier: 0) +> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1' +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 2 unique states visited; 0 backtracks (0 transition replays, 2 states visited overall) diff --git a/teshsuite/mc/mcmini/simple_barrier_ok.c b/teshsuite/mc/mcmini/simple_barrier_ok.c new file mode 100644 index 0000000000..1cfdd2a246 --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_ok.c @@ -0,0 +1,11 @@ +#include + +pthread_barrier_t barrier; + +int main(int argc, char* argv[]) +{ + pthread_barrier_init(&barrier, NULL, 1); + pthread_barrier_wait(&barrier); + return 0; +} + diff --git a/teshsuite/mc/mcmini/simple_barrier_ok.tesh b/teshsuite/mc/mcmini/simple_barrier_ok.tesh new file mode 100644 index 0000000000..187ac5aebd --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_ok.tesh @@ -0,0 +1,7 @@ +# We ignore the LD_PRELOAD lines from the expected output because they contain the build path +! ignore .*LD_PRELOAD.* + +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_ok +> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor' +> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor. +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 3 unique states visited; 0 backtracks (0 transition replays, 3 states visited overall) diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c new file mode 100644 index 0000000000..f63f4ba5e7 --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c @@ -0,0 +1,43 @@ +#include +#include +#include + +int THREAD_NUM; +int DEBUG = 0; + +pthread_barrier_t barrier; +pthread_t *thread; + +static void * thread_doit(void *unused) +{ + if(DEBUG) printf("Thread %lu: Waiting at barrier\n", (unsigned long)pthread_self()); + pthread_barrier_wait(&barrier); + if(DEBUG) printf("Thread %lu: Passed the barrier\n", (unsigned long)pthread_self()); + return NULL; +} + +int main(int argc, char* argv[]) { + if(argc != 3){ + printf("Usage: %s THREAD_NUM DEBUG_FLAG\n", argv[0]); + return 1; + } + + THREAD_NUM = atoi(argv[1]); + DEBUG = atoi(argv[2]); + + thread = (pthread_t*) malloc(THREAD_NUM * sizeof(pthread_t)); + + pthread_barrier_init(&barrier, NULL, THREAD_NUM); + for(int i = 0; i < THREAD_NUM; i++) { + pthread_create(&thread[i], NULL, &thread_doit, NULL); + } + + pthread_barrier_wait(&barrier); + + for(int i = 0; i < THREAD_NUM; i++) { + pthread_join(thread[i], NULL); + } + + free(thread); + return 0; +} diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh new file mode 100644 index 0000000000..4f04dd72ef --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh @@ -0,0 +1,26 @@ +# We ignore the LD_PRELOAD lines from the expected output because they contain the build path +! ignore .*LD_PRELOAD.* + +! expect return 3 +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_with_threads_deadlock 3 0 +> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor' +> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor. +> [0.000000] [mc_global/INFO] ************************** +> [0.000000] [mc_global/INFO] *** DEADLOCK DETECTED *** +> [0.000000] [mc_global/INFO] ************************** +> [0.000000] [ker_engine/INFO] 2 actors are still running, waiting for something. +> [0.000000] [ker_engine/INFO] Legend of the following listing: "Actor (@): " +> [0.000000] [ker_engine/INFO] Actor 1 (main thread@Lilibeth) simcall ActorJoin(pid:4) +> [0.000000] [ker_engine/INFO] Actor 4 (thread 3@Lilibeth) simcall BARRIER_WAIT(barrier_id:0) +> [0.000000] [mc_global/INFO] Counter-example execution trace: +> [0.000000] [mc_global/INFO] Actor 1 in simcall BARRIER_ASYNC_LOCK(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 2 in simcall BARRIER_ASYNC_LOCK(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 3 in simcall BARRIER_ASYNC_LOCK(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 1 in simcall BARRIER_WAIT(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 2 in simcall BARRIER_WAIT(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 1 in simcall ActorJoin(target 2, no timeout) +> [0.000000] [mc_global/INFO] Actor 3 in simcall BARRIER_WAIT(barrier: 0) +> [0.000000] [mc_global/INFO] Actor 1 in simcall ActorJoin(target 3, no timeout) +> [0.000000] [mc_global/INFO] Actor 4 in simcall BARRIER_ASYNC_LOCK(barrier: 0) +> [0.000000] [mc_Session/INFO] You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with --cfg=model-check/replay:'1;2;3;1;2;1;3;1;4' +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 10 unique states visited; 0 backtracks (0 transition replays, 10 states visited overall) diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c new file mode 100644 index 0000000000..0e3845177e --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c @@ -0,0 +1,54 @@ +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include + +int DEBUG; + +pthread_barrier_t barrier; + +static void * thread_doit(void *t) +{ + int *tid = (int*)t; + if(DEBUG) { + printf("Thread %d: Waiting at barrier\n", *tid); + } + pthread_barrier_wait(&barrier); + if(DEBUG) { + printf("Thread %d: Crossed barrier\n", *tid); + } + return NULL; +} + +int main(int argc, char* argv[]) +{ + if(argc < 3) { + printf("Expected usage: %s THREAD_NUM DEBUG_FLAG\n", argv[0]); + printf("DEBUG_FLAG: 0 - Don't display debug information, 1 - Display debug information\n"); + return -1; + } + + int THREAD_NUM = atoi(argv[1]); + DEBUG = atoi(argv[2]); + + pthread_t *threads = malloc(sizeof(pthread_t) * THREAD_NUM); + + pthread_barrier_init(&barrier, NULL, THREAD_NUM); + + int *tids = malloc(sizeof(int) * THREAD_NUM); + for(int i = 0; i < THREAD_NUM; i++) { + tids[i] = i; + pthread_create(&threads[i], NULL, &thread_doit, &tids[i]); + } + + for(int i = 0; i < THREAD_NUM; i++) { + pthread_join(threads[i], NULL); + } + + free(threads); + free(tids); + pthread_barrier_destroy(&barrier); + + return 0; +} diff --git a/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh new file mode 100644 index 0000000000..9e33a340e9 --- /dev/null +++ b/teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh @@ -0,0 +1,7 @@ +# We ignore the LD_PRELOAD lines from the expected output because they contain the build path +! ignore .*LD_PRELOAD.* + +$ $VALGRIND_NO_TRACE_CHILDREN ${bindir:=.}/../../bin/simgrid-mc --cfg=model-check/reduction:odpor --cfg=model-check/setenv:LD_PRELOAD=${libdir:=.}/libsthread.so ${bindir:=.}/mcmini/mcmini-simple_barrier_with_threads_ok 3 0 +> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/reduction' to 'odpor' +> [0.000000] [mc_dfs/INFO] Start a DFS exploration. Reduction is: odpor. +> [0.000000] [mc_dfs/INFO] DFS exploration ended. 10 unique states visited; 0 backtracks (0 transition replays, 10 states visited overall)