[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 ----
This commit is contained in:
parent
2765514314
commit
07992b08e8
1 changed files with 6 additions and 2 deletions
|
@ -347,6 +347,7 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
|
||||||
|
uint8_t do_execute = 0;
|
||||||
// do not take mutex if OS is not running yet
|
// do not take mutex if OS is not running yet
|
||||||
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ||
|
if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED ||
|
||||||
// init_routine can call pthread_once for another objects, so use recursive mutex
|
// 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)
|
!cur_task || xSemaphoreTakeRecursive(s_once_mux, portMAX_DELAY) == pdTRUE)
|
||||||
{
|
{
|
||||||
if (!once_control->init_executed) {
|
if (!once_control->init_executed) {
|
||||||
ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
|
do_execute = 1;
|
||||||
init_routine();
|
|
||||||
once_control->init_executed = 1;
|
once_control->init_executed = 1;
|
||||||
}
|
}
|
||||||
if (cur_task) {
|
if (cur_task) {
|
||||||
xSemaphoreGiveRecursive(s_once_mux);
|
xSemaphoreGiveRecursive(s_once_mux);
|
||||||
}
|
}
|
||||||
|
if (do_execute) {
|
||||||
|
ESP_LOGV(TAG, "%s: call init_routine %p", __FUNCTION__, once_control);
|
||||||
|
init_routine();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue