From f7f7e84fe08c5f1ba138c070501f962b741a1f80 Mon Sep 17 00:00:00 2001 From: Darian Biastoch Date: Fri, 13 Aug 2021 14:10:37 +0200 Subject: dlt_user: Make dlt_init thread safe This commit introduces the use of atomic_compare_exchange at beginning of both dlt_init functions. This function checks in an atomic way, if 'dlt_user_initialised' is 'false' (first run through dlt_init) and directly sets it 'true'. If a second thread also entered dlt-init at this point of time, its call of atomic_compare_exchange will return false and dlt_init will be immediately left due to that. This is only interesting for startup, because before each call of dlt_init, there is a check on 'dlt_user_initialised' that will fail for all later executions. Signed-off-by: Darian Biastoch --- src/lib/dlt_user.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/lib/dlt_user.c b/src/lib/dlt_user.c index bc9acc7..3d1c18c 100644 --- a/src/lib/dlt_user.c +++ b/src/lib/dlt_user.c @@ -55,6 +55,8 @@ #include +#include + #if defined DLT_LIB_USE_UNIX_SOCKET_IPC || defined DLT_LIB_USE_VSOCK_IPC # include #endif @@ -439,6 +441,16 @@ static DltReturnValue dlt_initialize_fifo_connection(void) DltReturnValue dlt_init(void) { + /* Compare 'dlt_user_initialised' to false. If equal, 'dlt_user_initialised' will be set to true. + Calls retruns true, if 'dlt_user_initialised' was false. + That way it's no problem, if two threads enter this function, because only the very first one will + pass fully. The other one will immediately return, because when it executes the atomic function + 'dlt_user_initialised' will be for sure already set to true. + */ + bool expected = false; + if (!(atomic_compare_exchange_strong(&dlt_user_initialised, &expected, true))) + return DLT_RETURN_OK; + /* check environment variables */ dlt_check_envvar(); @@ -449,10 +461,6 @@ DltReturnValue dlt_init(void) return DLT_RETURN_LOGGING_DISABLED; } - /* WARNING: multithread unsafe ! */ - /* Another thread will check that dlt_user_initialised != 0, but the lib is not initialised ! */ - dlt_user_initialised = true; - /* Initialize common part of dlt_init()/dlt_init_file() */ if (dlt_init_common() == DLT_RETURN_ERROR) { dlt_user_initialised = false; @@ -539,7 +547,15 @@ DltReturnValue dlt_init_file(const char *name) if (!name) return DLT_RETURN_WRONG_PARAMETER; - dlt_user_initialised = true; + /* Compare 'dlt_user_initialised' to false. If equal, 'dlt_user_initialised' will be set to true. + Calls retruns true, if 'dlt_user_initialised' was false. + That way it's no problem, if two threads enter this function, because only the very first one will + pass fully. The other one will immediately return, because when it executes the atomic function + 'dlt_user_initialised' will be for sure already set to true. + */ + bool expected = false; + if (!(atomic_compare_exchange_strong(&dlt_user_initialised, &expected, true))) + return DLT_RETURN_OK; /* Initialize common part of dlt_init()/dlt_init_file() */ if (dlt_init_common() == DLT_RETURN_ERROR) { -- cgit v1.2.1