]> granicus.if.org Git - esp-idf/commitdiff
[pthread] Perform init_routine execution outside of the mutex
authorKedar Sovani <Kedar Sovani kedars@gmail.com>
Wed, 25 Oct 2017 06:42:10 +0000 (12:12 +0530)
committerKedar Sovani <Kedar Sovani kedars@gmail.com>
Wed, 25 Oct 2017 08:27:39 +0000 (13:57 +0530)
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

index 70cc24552a2f5b620ca52fcbcb63074e9a5cc056..0875a0eee4fc1285449004bfe82fd5f089e0ba5b 100644 (file)
@@ -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
     {