From 07992b08e89f575daf26f449e6e58f9191d38e75 Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Wed, 25 Oct 2017 12:12:10 +0530 Subject: [PATCH] [pthread] Perform init_routine execution outside of the mutex The mutex is common across all the threads. It needn't be held across the init_routine() call as long as the 'once' behaviour is guaranteed Saw a deadlock case, where init_routine of one thread was waiting for the completion of init_routine in another thread. t2: wait for command t1: pthread_once: lock once_mux init_routine: inform thread t2 wait for signal from t2 t2: received command pthread_once lock once_mux (already held by t1) ---- Deadlock ---- --- components/pthread/pthread.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 70cc24552..0875a0eee 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -347,6 +347,7 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) } TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); + uint8_t do_execute = 0; // do not take mutex if OS is not running yet if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED || // init_routine can call pthread_once for another objects, so use recursive mutex @@ -354,13 +355,16 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) !cur_task || xSemaphoreTakeRecursive(s_once_mux, portMAX_DELAY) == pdTRUE) { if (!once_control->init_executed) { - ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control); - init_routine(); + do_execute = 1; once_control->init_executed = 1; } if (cur_task) { xSemaphoreGiveRecursive(s_once_mux); } + if (do_execute) { + ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control); + init_routine(); + } } else {