diff --git a/src/lib/parameters/atomic_transaction.cpp b/src/lib/parameters/atomic_transaction.cpp index 3ff9cf3e19b..a279314dff8 100644 --- a/src/lib/parameters/atomic_transaction.cpp +++ b/src/lib/parameters/atomic_transaction.cpp @@ -34,10 +34,18 @@ #include "atomic_transaction.h" #ifdef __PX4_POSIX +// The mutex is recursive because a param lookup walks the layered param stack +// holding the lock and delegates to the parent layer (Layer::get() -> +// _parent->get()), which takes the same mutex again on the same thread. +// +// The recursive attribute is set at runtime rather than via a static initializer: +// PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP is a glibc extension that is not portable +// (unavailable on e.g. QURT, and gated behind _GNU_SOURCE elsewhere). initialize() +// is called from param_init(), before any thread accesses parameters, so there is +// no lazy-init race. static pthread_mutex_t _param_mutex; -static pthread_once_t _param_mutex_once = PTHREAD_ONCE_INIT; -static void _init_param_mutex() +void AtomicTransaction::initialize() { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); @@ -48,7 +56,6 @@ static void _init_param_mutex() pthread_mutex_t *AtomicTransaction::_get_mutex() { - pthread_once(&_param_mutex_once, _init_param_mutex); return &_param_mutex; } #endif diff --git a/src/lib/parameters/atomic_transaction.h b/src/lib/parameters/atomic_transaction.h index b03794b57a8..3975c662ebe 100644 --- a/src/lib/parameters/atomic_transaction.h +++ b/src/lib/parameters/atomic_transaction.h @@ -54,6 +54,12 @@ private: #endif public: +#ifdef __PX4_POSIX + // Initialize the recursive param mutex. Must be called once before any thread + // accesses parameters (done from param_init()). + static void initialize(); +#endif + AtomicTransaction() { lock(); diff --git a/src/lib/parameters/parameters.cpp b/src/lib/parameters/parameters.cpp index 096b27fa76e..b6b0e4955f7 100644 --- a/src/lib/parameters/parameters.cpp +++ b/src/lib/parameters/parameters.cpp @@ -130,6 +130,11 @@ static pthread_mutex_t file_mutex = void param_init() { +#ifdef __PX4_POSIX + // Set up the recursive param mutex before any thread can access parameters. + AtomicTransaction::initialize(); +#endif + param_export_perf = perf_alloc(PC_ELAPSED, "param: export"); param_find_perf = perf_alloc(PC_COUNT, "param: find"); param_get_perf = perf_alloc(PC_COUNT, "param: get");