Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Implement pthread_barrier calls in sthread, and test them in McMini
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 12 Nov 2023 19:33:45 +0000 (20:33 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 12 Nov 2023 19:37:59 +0000 (20:37 +0100)
13 files changed:
MANIFEST.in
src/sthread/sthread.c
src/sthread/sthread.h
src/sthread/sthread_impl.cpp
teshsuite/mc/CMakeLists.txt
teshsuite/mc/mcmini/simple_barrier_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_ok.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_deadlock.tesh [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_ok.c [new file with mode: 0644]
teshsuite/mc/mcmini/simple_barrier_with_threads_ok.tesh [new file with mode: 0644]

index 21a22fe..3a53385 100644 (file)
@@ -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
index 7ba6a23..6f20733 100644 (file)
@@ -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                                                                                              \
   {                                                                                                                    \
index 4a51866..6d9c0fa 100644 (file)
@@ -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;
index e54a9c3..fda1411 100644 (file)
@@ -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<sg4::Mutex*>(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<sg4::Barrier*>(barrier->barrier)->wait();
+  return 0;
+}
+int sthread_barrier_destroy(sthread_barrier_t* barrier){
+  XBT_DEBUG("%s(%p)", __func__, barrier);
+  intrusive_ptr_release(static_cast<sg4::Barrier*>(barrier->barrier));
+  return 0;
+}
+
 int sthread_sem_init(sthread_sem_t* sem, int /*pshared*/, unsigned int value)
 {
   auto s = sg4::Semaphore::create(value);
index 8432916..41cad5e 100644 (file)
@@ -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 (file)
index 0000000..16805ad
--- /dev/null
@@ -0,0 +1,10 @@
+#include <pthread.h>
+
+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 (file)
index 0000000..0b5980f
--- /dev/null
@@ -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 <pid> (<name>@<host>): <status>"
+> [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 (file)
index 0000000..1cfdd2a
--- /dev/null
@@ -0,0 +1,11 @@
+#include <pthread.h>
+
+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 (file)
index 0000000..187ac5a
--- /dev/null
@@ -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 (file)
index 0000000..f63f4ba
--- /dev/null
@@ -0,0 +1,43 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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 (file)
index 0000000..4f04dd7
--- /dev/null
@@ -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 <pid> (<name>@<host>): <status>"
+> [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 (file)
index 0000000..0e38451
--- /dev/null
@@ -0,0 +1,54 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+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 (file)
index 0000000..9e33a34
--- /dev/null
@@ -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)