diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt
index d12aa009d2530f4ca3015a5037fa76cf1e5c274b..afc89c322e8e373f3408e907dc33065c8f1748bd 100644
--- a/src/plugins/e-acsl/headers/header_spec.txt
+++ b/src/plugins/e-acsl/headers/header_spec.txt
@@ -26,6 +26,7 @@ share/e-acsl/instrumentation_model/e_acsl_temporal_timestamp.h: CEA_LGPL_OR_PROP
 share/e-acsl/internals/e_acsl_alias.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/internals/e_acsl_bits.c: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/internals/e_acsl_bits.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+share/e-acsl/internals/e_acsl_concurrency.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/internals/e_acsl_config.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/internals/e_acsl_debug.c: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/internals/e_acsl_debug.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
diff --git a/src/plugins/e-acsl/share/e-acsl/internals/e_acsl_concurrency.h b/src/plugins/e-acsl/share/e-acsl/internals/e_acsl_concurrency.h
new file mode 100644
index 0000000000000000000000000000000000000000..4961dd4466d715e5b50fd8c8ddbb843d56773d44
--- /dev/null
+++ b/src/plugins/e-acsl/share/e-acsl/internals/e_acsl_concurrency.h
@@ -0,0 +1,158 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of the Frama-C's E-ACSL plug-in.                    */
+/*                                                                        */
+/*  Copyright (C) 2012-2021                                               */
+/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
+/*         alternatives)                                                  */
+/*                                                                        */
+/*  you can redistribute it and/or modify it under the terms of the GNU   */
+/*  Lesser General Public License as published by the Free Software       */
+/*  Foundation, version 2.1.                                              */
+/*                                                                        */
+/*  It is distributed in the hope that it will be useful,                 */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU Lesser General Public License for more details.                   */
+/*                                                                        */
+/*  See the GNU Lesser General Public License version 2.1                 */
+/*  for more details (enclosed in the file licenses/LGPLv2.1).            */
+/*                                                                        */
+/**************************************************************************/
+
+/*! ***********************************************************************
+ * \file
+ * \brief E-ACSL concurrency utility macros and functions.
+ **************************************************************************/
+
+#ifndef E_ACSL_CONCURRENCY
+#define E_ACSL_CONCURRENCY
+
+#ifdef E_ACSL_CONCURRENCY_PTHREAD
+#  include <pthread.h>
+#  include <string.h>
+
+#  include "e_acsl_debug.h"
+#  include "e_acsl_rtl_error.h"
+
+/************************************************************************/
+/*** Run once function {{{ ***/
+/************************************************************************/
+
+#  ifdef E_ACSL_DEBUG
+/*! \brief Buffer to hold a thread-specific error message.
+
+    This buffer and `rtl_strerror_t()` are used instead of directly
+    `rtl_strerror()` because since `E_ACSL_RUN_ONCE` is called when processing
+    logging functions, the message returned by `rtl_strerror()` in a
+    `DVASSERT()` call could be overwritten. */
+static __thread char __e_acsl_run_once_error_buffer[255];
+#  endif
+
+/*! \brief The first call to `E_ACSL_RUN_ONCE` will call the initialization
+    function `init_fct()` without arguments. Any subsequent call to
+    `E_ACSL_RUN_ONCE` will not call `init_fct()`. After calling
+    `E_ACSL_RUN_ONCE`, the function `init_fct()` has been called. */
+#  define E_ACSL_RUN_ONCE(init_fct)                                            \
+    do {                                                                       \
+      static pthread_once_t already_run = PTHREAD_ONCE_INIT;                   \
+      int result = pthread_once(&already_run, init_fct);                       \
+      DVASSERT(result == 0,                                                    \
+               "Unable to initialize with function '" #init_fct "()': %s\n",   \
+               rtl_strerror_r(errno, __e_acsl_run_once_error_buffer,           \
+                              sizeof(__e_acsl_run_once_error_buffer)));        \
+    } while (0)
+
+/*! \brief The first call to `E_ACSL_RUN_ONCE_WITH_ARGS` will call the
+    initialization function `init_fct()` with arguments `args...`. Any
+    subsequent call to `E_ACSL_RUN_ONCE_WITH_ARGS` will not call `init_fct()`.
+    After calling `E_ACSL_RUN_ONCE_WITH_ARGS`, the function `init_fct()` has
+    been called. */
+#  define E_ACSL_RUN_ONCE_WITH_ARGS(init_fct, args...)                         \
+    do {                                                                       \
+      static int already_run = 0;                                              \
+      static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;             \
+      pthread_rwlock_rdlock(&rwlock);                                          \
+      if (!already_run) {                                                      \
+        pthread_rwlock_unlock(&rwlock);                                        \
+        pthread_rwlock_wrlock(&rwlock);                                        \
+        if (!already_run) {                                                    \
+          init_fct(args);                                                      \
+          already_run = 1;                                                     \
+        }                                                                      \
+      }                                                                        \
+      pthread_rwlock_unlock(&rwlock);                                          \
+    } while (0)
+
+/* }}} */
+
+/************************************************************************/
+/*** Mutex {{{ ***/
+/************************************************************************/
+
+/*! \brief Declare a static mutex variable named `mutex` with the initialization
+    `init`. */
+#  define E_ACSL_MUTEX_DECL_INIT(mutex, init)                                  \
+    static pthread_mutex_t mutex = init
+
+/*! \brief Lock the given mutex */
+#  define E_ACSL_MUTEX_LOCK(mutex) pthread_mutex_lock(&(mutex))
+
+/*! \brief Unlock the given mutex */
+#  define E_ACSL_MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&(mutex))
+
+/* }}} */
+
+/************************************************************************/
+/*** Read-write lock {{{ ***/
+/************************************************************************/
+
+/*! \brief Declare a read-write lock variable named `rwlock`. */
+#  define E_ACSL_RWLOCK_DECL(rwlock) pthread_rwlock_t rwlock
+
+/*! \brief Initialize the given read-write lock with the given attributes. */
+#  define E_ACSL_RWINIT(rwlock, attrs) pthread_rwlock_init(&(rwlock), attrs)
+
+/*! \brief Destroy the given read-write lock. */
+#  define E_ACSL_RWDESTROY(rwlock) pthread_rwlock_destroy(&(rwlock))
+
+/*! \brief Apply a read lock to the given read-write lock. */
+#  define E_ACSL_RLOCK(rwlock)                                                 \
+    pthread_rwlock_rdlock((pthread_rwlock_t *)&(rwlock))
+
+/*! \brief Apply a write lock to the given read-write lock. */
+#  define E_ACSL_WLOCK(rwlock) pthread_rwlock_wrlock(&(rwlock))
+
+/*! \brief Unlock the given read-write lock. */
+#  define E_ACSL_RWUNLOCK(rwlock)                                              \
+    pthread_rwlock_unlock((pthread_rwlock_t *)&(rwlock))
+
+/* }}} */
+
+#else
+
+#  define E_ACSL_RUN_ONCE_WITH_ARGS(init_fct, args...)                         \
+    do {                                                                       \
+      static int already_run = 0;                                              \
+      if (!already_run) {                                                      \
+        init_fct(args);                                                        \
+        already_run = 1;                                                       \
+      }                                                                        \
+    } while (0)
+
+#  define E_ACSL_RUN_ONCE(init_fct) E_ACSL_RUN_ONCE_WITH_ARGS(init_fct)
+
+#  define E_ACSL_MUTEX_DECL_INIT(mutex, init)
+#  define E_ACSL_MUTEX_LOCK(mutex)
+#  define E_ACSL_MUTEX_UNLOCK(mutex)
+
+#  define E_ACSL_RWLOCK_DECL(rwlock)
+#  define E_ACSL_RWINIT(rwlock, attrs)
+#  define E_ACSL_RWDESTROY(rwlock)
+#  define E_ACSL_RLOCK(rwlock)
+#  define E_ACSL_WLOCK(rwlock)
+#  define E_ACSL_RWUNLOCK(rwlock)
+
+#endif
+
+#endif // E_ACSL_CONCURRENCY