Merge pull request #8636 from paul-elliott-arm/new_test_thread_interface

New test thread interface
diff --git a/3rdparty/everest/Makefile.inc b/3rdparty/everest/Makefile.inc
index 77a6b49..8055ce9 100644
--- a/3rdparty/everest/Makefile.inc
+++ b/3rdparty/everest/Makefile.inc
@@ -1,6 +1,6 @@
-THIRDPARTY_INCLUDES+=-I../3rdparty/everest/include -I../3rdparty/everest/include/everest -I../3rdparty/everest/include/everest/kremlib
+THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/everest/include -I$(THIRDPARTY_DIR)/everest/include/everest -I$(THIRDPARTY_DIR)/everest/include/everest/kremlib
 
 THIRDPARTY_CRYPTO_OBJECTS+= \
-	../3rdparty/everest/library/everest.o \
-	../3rdparty/everest/library/x25519.o \
-	../3rdparty/everest/library/Hacl_Curve25519_joined.o
+	$(THIRDPARTY_DIR)/everest/library/everest.o \
+	$(THIRDPARTY_DIR)/everest/library/x25519.o \
+	$(THIRDPARTY_DIR)/everest/library/Hacl_Curve25519_joined.o
diff --git a/3rdparty/p256-m/Makefile.inc b/3rdparty/p256-m/Makefile.inc
index fc8f73b..53bb55b 100644
--- a/3rdparty/p256-m/Makefile.inc
+++ b/3rdparty/p256-m/Makefile.inc
@@ -1,5 +1,5 @@
-THIRDPARTY_INCLUDES+=-I../3rdparty/p256-m/p256-m/include -I../3rdparty/p256-m/p256-m/include/p256-m -I../3rdparty/p256-m/p256-m_driver_interface
+THIRDPARTY_INCLUDES+=-I$(THIRDPARTY_DIR)/p256-m/p256-m/include -I$(THIRDPARTY_DIR)/p256-m/p256-m/include/p256-m -I$(THIRDPARTY_DIR)/p256-m/p256-m_driver_interface
 
 THIRDPARTY_CRYPTO_OBJECTS+= \
-	../3rdparty/p256-m//p256-m_driver_entrypoints.o \
-	../3rdparty/p256-m//p256-m/p256-m.o
+	$(THIRDPARTY_DIR)/p256-m//p256-m_driver_entrypoints.o \
+	$(THIRDPARTY_DIR)/p256-m//p256-m/p256-m.o
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 78599d9..38806d9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -114,6 +114,11 @@
 
 endif()
 
+# We now potentially need to link all executables against PThreads, if available
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+find_package(Threads)
+
 # If this is the root project add longer list of available CMAKE_BUILD_TYPE values
 if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
     set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index b6ea73e..47ecf17 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -231,7 +231,7 @@
 endif(HAIKU)
 
 if(LINK_WITH_PTHREAD)
-    set(libs ${libs} pthread)
+    set(libs ${libs} ${CMAKE_THREAD_LIBS_INIT})
 endif()
 
 if(LINK_WITH_TRUSTED_STORAGE)
diff --git a/programs/Makefile b/programs/Makefile
index 82c8569..6baf465 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -114,7 +114,7 @@
 endif
 
 fuzz: ${MBEDTLS_TEST_OBJS}
-	$(MAKE) -C fuzz THIRDPARTY_INCLUDES=$(THIRDPARTY_INCLUDES)
+	$(MAKE) -C fuzz
 
 ${MBEDTLS_TEST_OBJS}:
 	$(MAKE) -C ../tests mbedtls_test
diff --git a/programs/aes/CMakeLists.txt b/programs/aes/CMakeLists.txt
index 85bcd5f..ccb8db5 100644
--- a/programs/aes/CMakeLists.txt
+++ b/programs/aes/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/cipher/CMakeLists.txt b/programs/cipher/CMakeLists.txt
index 93e5f31..e925524 100644
--- a/programs/cipher/CMakeLists.txt
+++ b/programs/cipher/CMakeLists.txt
@@ -4,7 +4,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/fuzz/CMakeLists.txt b/programs/fuzz/CMakeLists.txt
index 7747744..c389029 100644
--- a/programs/fuzz/CMakeLists.txt
+++ b/programs/fuzz/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(libs
     ${mbedtls_target}
+    ${CMAKE_THREAD_LIBS_INIT}
 )
 
 find_library(FUZZINGENGINE_LIB FuzzingEngine)
diff --git a/programs/fuzz/Makefile b/programs/fuzz/Makefile
index b4fc76a..828e518 100644
--- a/programs/fuzz/Makefile
+++ b/programs/fuzz/Makefile
@@ -1,36 +1,14 @@
-MBEDTLS_TEST_PATH:=../../tests/src
-MBEDTLS_TEST_OBJS:=$(patsubst %.c,%.o,$(wildcard ${MBEDTLS_TEST_PATH}/*.c ${MBEDTLS_TEST_PATH}/drivers/*.c))
+MBEDTLS_TEST_PATH:=../../tests
 
-CFLAGS ?= -O2
-WARNING_CFLAGS ?= -Wall -Wextra
-LOCAL_CFLAGS = $(WARNING_CFLAGS) -I../../tests/include -I../../include -D_FILE_OFFSET_BITS=64
-LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS}		\
-		-L../../library			\
-		-lmbedtls$(SHARED_SUFFIX)	\
-		-lmbedx509$(SHARED_SUFFIX)	\
-		-lmbedcrypto$(SHARED_SUFFIX)
+MBEDTLS_PATH := ../..
+include ../../scripts/common.make
 
-LOCAL_CFLAGS += $(patsubst -I../%,-I../../%,$(THIRDPARTY_INCLUDES))
-
-ifndef SHARED
-DEP=../../library/libmbedcrypto.a ../../library/libmbedx509.a ../../library/libmbedtls.a
-else
-DEP=../../library/libmbedcrypto.$(DLEXT) ../../library/libmbedx509.$(DLEXT) ../../library/libmbedtls.$(DLEXT)
-endif
-
-
-DLEXT ?= so
-EXEXT=
-SHARED_SUFFIX=
+DEP=${MBEDLIBS}
 
 ifdef FUZZINGENGINE
 LOCAL_LDFLAGS += -lFuzzingEngine
 endif
 
-ifdef WINDOWS_BUILD
-LOCAL_LDFLAGS += -lbcrypt
-endif
-
 # A test application is built for each suites/test_suite_*.data file.
 # Application name is same as .data file's base name and can be
 # constructed by stripping path 'suites/' and extension .data.
@@ -45,9 +23,6 @@
 
 all: $(BINARIES)
 
-$(DEP):
-	$(MAKE) -C ../../library
-
 C_FILES := $(addsuffix .c,$(APPS))
 
 %.o: %.c
diff --git a/programs/hash/CMakeLists.txt b/programs/hash/CMakeLists.txt
index da98188..fcacf3b 100644
--- a/programs/hash/CMakeLists.txt
+++ b/programs/hash/CMakeLists.txt
@@ -6,7 +6,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/pkey/CMakeLists.txt b/programs/pkey/CMakeLists.txt
index 3ad5643..cd0387a 100644
--- a/programs/pkey/CMakeLists.txt
+++ b/programs/pkey/CMakeLists.txt
@@ -5,7 +5,7 @@
 
 foreach(exe IN LISTS executables_mbedtls)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedtls_target})
+    target_link_libraries(${exe} ${mbedtls_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
@@ -32,7 +32,7 @@
 
 foreach(exe IN LISTS executables_mbedcrypto)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/psa/CMakeLists.txt b/programs/psa/CMakeLists.txt
index c8ee626..a8e4b0e 100644
--- a/programs/psa/CMakeLists.txt
+++ b/programs/psa/CMakeLists.txt
@@ -28,7 +28,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/random/CMakeLists.txt b/programs/random/CMakeLists.txt
index e5edf7b..5940395 100644
--- a/programs/random/CMakeLists.txt
+++ b/programs/random/CMakeLists.txt
@@ -5,7 +5,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${mbedcrypto_target})
+    target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/ssl/CMakeLists.txt b/programs/ssl/CMakeLists.txt
index 280bbcf..ec2c86f 100644
--- a/programs/ssl/CMakeLists.txt
+++ b/programs/ssl/CMakeLists.txt
@@ -1,4 +1,3 @@
-set(THREADS_USE_PTHREADS_WIN32 true)
 find_package(Threads)
 
 set(libs
@@ -39,7 +38,7 @@
     endif()
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>
         ${extra_sources})
-    target_link_libraries(${exe} ${libs})
+    target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
     if(exe STREQUAL "ssl_client2" OR exe STREQUAL "ssl_server2")
         if(GEN_FILES)
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index 650fbfb..7616b69 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -13,7 +13,7 @@
 #include "ssl_test_lib.h"
 
 #if defined(MBEDTLS_TEST_HOOKS)
-#include "test/helpers.h"
+#include "test/threading_helpers.h"
 #endif
 
 #if !defined(MBEDTLS_SSL_TEST_IMPOSSIBLE)
diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt
index 0778731..f91f786 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -26,7 +26,7 @@
     )
     add_executable(cpp_dummy_build "${cpp_dummy_build_cpp}")
     target_include_directories(cpp_dummy_build PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
-    target_link_libraries(cpp_dummy_build ${mbedcrypto_target})
+    target_link_libraries(cpp_dummy_build ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
 endif()
 
 if(USE_SHARED_MBEDTLS_LIBRARY AND
@@ -81,9 +81,9 @@
     # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3
     list(FIND executables_libs ${exe} exe_index)
     if (${exe_index} GREATER -1)
-        target_link_libraries(${exe} ${libs})
+        target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
     else()
-        target_link_libraries(${exe} ${mbedcrypto_target})
+        target_link_libraries(${exe} ${mbedcrypto_target} ${CMAKE_THREAD_LIBS_INIT})
     endif()
 endforeach()
 
diff --git a/programs/test/cmake_subproject/CMakeLists.txt b/programs/test/cmake_subproject/CMakeLists.txt
index 3c3cba3..78bd5e7 100644
--- a/programs/test/cmake_subproject/CMakeLists.txt
+++ b/programs/test/cmake_subproject/CMakeLists.txt
@@ -20,4 +20,4 @@
 )
 
 add_executable(cmake_subproject cmake_subproject.c)
-target_link_libraries(cmake_subproject ${libs})
+target_link_libraries(cmake_subproject ${libs} ${CMAKE_THREAD_LIBS_INIT})
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
index b8dffa9..82ecf95 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -31,6 +31,7 @@
 #include <mbedtls/platform.h>
 #include <mbedtls/platform_util.h>
 #include "test/helpers.h"
+#include "test/threading_helpers.h"
 #include "test/macros.h"
 
 #include <stdio.h>
diff --git a/programs/util/CMakeLists.txt b/programs/util/CMakeLists.txt
index 7fc58cb..cb6bc3d 100644
--- a/programs/util/CMakeLists.txt
+++ b/programs/util/CMakeLists.txt
@@ -9,7 +9,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${libs})
+    target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt
index 5876b8d..43437f0 100644
--- a/programs/x509/CMakeLists.txt
+++ b/programs/x509/CMakeLists.txt
@@ -13,7 +13,7 @@
 
 foreach(exe IN LISTS executables)
     add_executable(${exe} ${exe}.c $<TARGET_OBJECTS:mbedtls_test>)
-    target_link_libraries(${exe} ${libs})
+    target_link_libraries(${exe} ${libs} ${CMAKE_THREAD_LIBS_INIT})
     target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/include)
 endforeach()
 
diff --git a/scripts/common.make b/scripts/common.make
index 6c95b42..2714bcd 100644
--- a/scripts/common.make
+++ b/scripts/common.make
@@ -1,25 +1,29 @@
 # To compile on SunOS: add "-lsocket -lnsl" to LDFLAGS
 
+ifndef MBEDTLS_PATH
+MBEDTLS_PATH := ..
+endif
+
 CFLAGS	?= -O2
 WARNING_CFLAGS ?= -Wall -Wextra -Wformat=2 -Wno-format-nonliteral
 WARNING_CXXFLAGS ?= -Wall -Wextra -Wformat=2 -Wno-format-nonliteral
 LDFLAGS ?=
 
-LOCAL_CFLAGS = $(WARNING_CFLAGS) -I$(MBEDTLS_TEST_PATH)/include -I../include -D_FILE_OFFSET_BITS=64
-LOCAL_CXXFLAGS = $(WARNING_CXXFLAGS) -I../include -I../tests/include -D_FILE_OFFSET_BITS=64
+LOCAL_CFLAGS = $(WARNING_CFLAGS) -I$(MBEDTLS_TEST_PATH)/include -I$(MBEDTLS_PATH)/include -D_FILE_OFFSET_BITS=64
+LOCAL_CXXFLAGS = $(WARNING_CXXFLAGS) -I$(MBEDTLS_PATH)/include -I$(MBEDTLS_PATH)/tests/include -D_FILE_OFFSET_BITS=64
 LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS} 		\
-		-L../library			\
+		-L$(MBEDTLS_PATH)/library			\
 		-lmbedtls$(SHARED_SUFFIX)	\
 		-lmbedx509$(SHARED_SUFFIX)	\
 		-lmbedcrypto$(SHARED_SUFFIX)
 
-include ../3rdparty/Makefile.inc
+include $(MBEDTLS_PATH)/3rdparty/Makefile.inc
 LOCAL_CFLAGS+=$(THIRDPARTY_INCLUDES)
 
 ifndef SHARED
-MBEDLIBS=../library/libmbedcrypto.a ../library/libmbedx509.a ../library/libmbedtls.a
+MBEDLIBS=$(MBEDTLS_PATH)/library/libmbedcrypto.a $(MBEDTLS_PATH)/library/libmbedx509.a $(MBEDTLS_PATH)/library/libmbedtls.a
 else
-MBEDLIBS=../library/libmbedcrypto.$(DLEXT) ../library/libmbedx509.$(DLEXT) ../library/libmbedtls.$(DLEXT)
+MBEDLIBS=$(MBEDTLS_PATH)/library/libmbedcrypto.$(DLEXT) $(MBEDTLS_PATH)/library/libmbedx509.$(DLEXT) $(MBEDTLS_PATH)/library/libmbedtls.$(DLEXT)
 endif
 
 ifdef DEBUG
@@ -97,7 +101,7 @@
 default: all
 
 $(MBEDLIBS):
-	$(MAKE) -C ../library
+	$(MAKE) -C $(MBEDTLS_PATH)/library
 
 neat: clean
 ifndef WINDOWS
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 68bc57f..70f5bc9 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,5 +1,3 @@
-find_package(Threads)
-
 set(libs
     ${mbedtls_target}
     ${CMAKE_THREAD_LIBS_INIT}
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index 47d4dcd..3658868 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -39,11 +39,7 @@
 #  endif
 #endif
 
-#if defined(MBEDTLS_THREADING_C) && defined(MBEDTLS_THREADING_PTHREAD) && \
-    defined(MBEDTLS_TEST_HOOKS)
-#define MBEDTLS_TEST_MUTEX_USAGE
-#endif
-
+#include "test/threading_helpers.h"
 #include "mbedtls/platform.h"
 
 #include <stddef.h>
@@ -258,24 +254,6 @@
 #include "test/fake_external_rng_for_test.h"
 #endif
 
-#if defined(MBEDTLS_TEST_MUTEX_USAGE)
-/**
- *  Activate the mutex usage verification framework. See threading_helpers.c for
- *  information.
- *  */
-void mbedtls_test_mutex_usage_init(void);
-
-/**
- *  Deactivate the mutex usage verification framework. See threading_helpers.c
- *  for information.
- */
-void mbedtls_test_mutex_usage_end(void);
-
-/** Call this function after executing a test case to check for mutex usage
- * errors. */
-void mbedtls_test_mutex_usage_check(void);
-#endif /* MBEDTLS_TEST_MUTEX_USAGE */
-
 #if defined(MBEDTLS_TEST_HOOKS)
 /**
  * \brief   Check that only a pure high-level error code is being combined with
diff --git a/tests/include/test/threading_helpers.h b/tests/include/test/threading_helpers.h
new file mode 100644
index 0000000..79bc6c0
--- /dev/null
+++ b/tests/include/test/threading_helpers.h
@@ -0,0 +1,112 @@
+/**
+ * \file threading_helpers.h
+ *
+ * \brief This file contains the prototypes of helper functions for the purpose
+ *        of testing threading.
+ */
+
+/*
+ *  Copyright The Mbed TLS Contributors
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+ */
+
+#ifndef THREADING_HELPERS_H
+#define THREADING_HELPERS_H
+
+#if defined MBEDTLS_THREADING_C
+
+#include "mbedtls/private_access.h"
+#include "mbedtls/build_info.h"
+
+/* Most fields of publicly available structs are private and are wrapped with
+ * MBEDTLS_PRIVATE macro. This define allows tests to access the private fields
+ * directly (without using the MBEDTLS_PRIVATE wrapper). */
+#define MBEDTLS_ALLOW_PRIVATE_ACCESS
+
+#define MBEDTLS_ERR_THREADING_THREAD_ERROR                 -0x001F
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+#include <pthread.h>
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
+#if defined(MBEDTLS_THREADING_ALT)
+/* You should define the mbedtls_test_thread_t type in your header */
+#include "threading_alt.h"
+
+/**
+ * \brief                   Set your alternate threading implementation
+ *                          function pointers for test threads. If used, this
+ *                          function must be called once in the main thread
+ *                          before any other MbedTLS function is called.
+ *
+ * \note                    These functions are part of the testing API only and
+ *                          thus not considered part of the public API of
+ *                          MbedTLS and thus may change without notice.
+ *
+ * \param thread_create     The thread create function implementation.
+ * \param thread_join       The thread join function implementation.
+
+ */
+void mbedtls_test_thread_set_alt(int (*thread_create)(mbedtls_test_thread_t *thread,
+                                                      void *(*thread_func)(
+                                                          void *),
+                                                      void *thread_data),
+                                 int (*thread_join)(mbedtls_test_thread_t *thread));
+
+#else /* MBEDTLS_THREADING_ALT*/
+
+typedef struct mbedtls_test_thread_t {
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+    pthread_t MBEDTLS_PRIVATE(thread);
+#else /* MBEDTLS_THREADING_PTHREAD */
+    /* Make sure this struct is always non-empty */
+    unsigned dummy;
+#endif
+
+} mbedtls_test_thread_t;
+
+#endif /* MBEDTLS_THREADING_ALT*/
+
+/**
+ * \brief                   The function pointers for thread create and thread
+ *                          join.
+ *
+ * \note                    These functions are part of the testing API only
+ *                          and thus not considered part of the public API of
+ *                          MbedTLS and thus may change without notice.
+ *
+ * \note                    All these functions are expected to work or
+ *                          the result will be undefined.
+ */
+extern int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread,
+                                         void *(*thread_func)(void *), void *thread_data);
+extern int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread);
+
+#if defined(MBEDTLS_THREADING_PTHREAD) && defined(MBEDTLS_TEST_HOOKS)
+#define MBEDTLS_TEST_MUTEX_USAGE
+#endif
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/**
+ *  Activate the mutex usage verification framework. See threading_helpers.c for
+ *  information.
+ */
+void mbedtls_test_mutex_usage_init(void);
+
+/**
+ *  Deactivate the mutex usage verification framework. See threading_helpers.c
+ *  for information.
+ */
+void mbedtls_test_mutex_usage_end(void);
+
+/**
+ *  Call this function after executing a test case to check for mutex usage
+ * errors.
+ */
+void mbedtls_test_mutex_usage_check(void);
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+#endif /* MBEDTLS_THREADING_C */
+
+#endif /* THREADING_HELPERS_H */
diff --git a/tests/src/threading_helpers.c b/tests/src/threading_helpers.c
index 5fbf65b..5a871e1 100644
--- a/tests/src/threading_helpers.c
+++ b/tests/src/threading_helpers.c
@@ -6,8 +6,74 @@
  */
 
 #include <test/helpers.h>
+#include <test/threading_helpers.h>
 #include <test/macros.h>
 
+#include "mbedtls/threading.h"
+
+#if defined(MBEDTLS_THREADING_C)
+
+#if defined(MBEDTLS_THREADING_PTHREAD)
+
+static int threading_thread_create_pthread(mbedtls_test_thread_t *thread, void *(*thread_func)(
+                                               void *), void *thread_data)
+{
+    if (thread == NULL || thread_func == NULL) {
+        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+    }
+
+    if (pthread_create(&thread->thread, NULL, thread_func, thread_data)) {
+        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
+    }
+
+    return 0;
+}
+
+static int threading_thread_join_pthread(mbedtls_test_thread_t *thread)
+{
+    if (thread == NULL) {
+        return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+    }
+
+    if (pthread_join(thread->thread, NULL) != 0) {
+        return MBEDTLS_ERR_THREADING_THREAD_ERROR;
+    }
+
+    return 0;
+}
+
+int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
+                                  void *thread_data) = threading_thread_create_pthread;
+int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_pthread;
+
+#endif /* MBEDTLS_THREADING_PTHREAD */
+
+#if defined(MBEDTLS_THREADING_ALT)
+
+static int threading_thread_create_fail(mbedtls_test_thread_t *thread,
+                                        void *(*thread_func)(void *),
+                                        void *thread_data)
+{
+    (void) thread;
+    (void) thread_func;
+    (void) thread_data;
+
+    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+}
+
+static int threading_thread_join_fail(mbedtls_test_thread_t *thread)
+{
+    (void) thread;
+
+    return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA;
+}
+
+int (*mbedtls_test_thread_create)(mbedtls_test_thread_t *thread, void *(*thread_func)(void *),
+                                  void *thread_data) = threading_thread_create_fail;
+int (*mbedtls_test_thread_join)(mbedtls_test_thread_t *thread) = threading_thread_join_fail;
+
+#endif /* MBEDTLS_THREADING_ALT */
+
 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
 
 #include "mbedtls/threading.h"
@@ -257,3 +323,5 @@
 }
 
 #endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+#endif /* MBEDTLS_THREADING_C */
diff --git a/tests/suites/helpers.function b/tests/suites/helpers.function
index 86ff5b4..b5f5796 100644
--- a/tests/suites/helpers.function
+++ b/tests/suites/helpers.function
@@ -8,6 +8,7 @@
 #include <test/random.h>
 #include <test/bignum_helpers.h>
 #include <test/psa_crypto_helpers.h>
+#include <test/threading_helpers.h>
 
 #include <errno.h>
 #include <limits.h>
diff --git a/tests/suites/test_suite_ctr_drbg.function b/tests/suites/test_suite_ctr_drbg.function
index 63524f2..720eb3e 100644
--- a/tests/suites/test_suite_ctr_drbg.function
+++ b/tests/suites/test_suite_ctr_drbg.function
@@ -347,7 +347,7 @@
 void ctr_drbg_threads(data_t *expected_result, int reseed, int arg_thread_count)
 {
     size_t thread_count = (size_t) arg_thread_count;
-    pthread_t *threads = NULL;
+    mbedtls_test_thread_t *threads = NULL;
 
     unsigned char out[16];
     unsigned char *entropy = NULL;
@@ -364,7 +364,7 @@
 
     AES_PSA_INIT();
 
-    TEST_CALLOC(threads, sizeof(pthread_t) * thread_count);
+    TEST_CALLOC(threads, sizeof(mbedtls_test_thread_t) * thread_count);
     memset(out, 0, sizeof(out));
 
     mbedtls_ctr_drbg_context ctx;
@@ -398,13 +398,13 @@
 
     for (size_t i = 0; i < thread_count; i++) {
         TEST_EQUAL(
-            pthread_create(&threads[i], NULL,
-                           thread_random_function, (void *) &ctx),
+            mbedtls_test_thread_create(&threads[i],
+                                       thread_random_function, (void *) &ctx),
             0);
     }
 
     for (size_t i = 0; i < thread_count; i++) {
-        TEST_EQUAL(pthread_join(threads[i], NULL), 0);
+        TEST_EQUAL(mbedtls_test_thread_join(&threads[i]), 0);
     }
 
     /* Take a last output for comparing and thus verifying the DRBG state */