diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 73f23a00d..7817355fb 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -72,7 +72,7 @@ static int IRAM_ATTR pthread_mutex_lock_internal(esp_pthread_mutex_t *mux, TickT esp_err_t esp_pthread_init(void) { vListInitialise((List_t *)&s_threads_list); - s_once_mux = xSemaphoreCreateMutex(); + s_once_mux = xSemaphoreCreateRecursiveMutex(); if (s_once_mux == NULL) { return ESP_ERR_NO_MEM; } @@ -232,6 +232,7 @@ int pthread_join(pthread_t thread, void **retval) { esp_pthread_t *pthread = (esp_pthread_t *)thread; int ret = 0; + bool wait = false; ESP_LOGV(TAG, "%s %p", __FUNCTION__, pthread); @@ -257,6 +258,7 @@ int pthread_join(pthread_t thread, void **retval) } else { if (pthread->state == PTHREAD_TASK_STATE_RUN) { pthread->join_task = xTaskGetCurrentTaskHandle(); + wait = true; } else { pthread_delete(pthread); } @@ -264,7 +266,7 @@ int pthread_join(pthread_t thread, void **retval) } xSemaphoreGive(s_threads_mux); - if (ret == 0 && pthread->join_task) { + if (ret == 0 && wait) { xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); if (xSemaphoreTake(s_threads_mux, portMAX_DELAY) != pdTRUE) { assert(false && "Failed to lock threads list!"); @@ -375,7 +377,9 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) TaskHandle_t cur_task = xTaskGetCurrentTaskHandle(); // do not take mutex if OS is not running yet if (xTaskGetSchedulerState() == taskSCHEDULER_NOT_STARTED || - !cur_task || xSemaphoreTake(s_once_mux, portMAX_DELAY) == pdTRUE) + // init_routine can call pthread_once for another objects, so use recursive mutex + // FIXME: behaviour is undefined if init_routine calls pthread_once for the same object in the current context + !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); @@ -383,7 +387,7 @@ int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) once_control->init_executed = 1; } if (cur_task) { - xSemaphoreGive(s_once_mux); + xSemaphoreGiveRecursive(s_once_mux); } } else diff --git a/components/pthread/test/test_pthread_cxx.cpp b/components/pthread/test/test_pthread_cxx.cpp index 287a1da1b..ced961d09 100644 --- a/components/pthread/test/test_pthread_cxx.cpp +++ b/components/pthread/test/test_pthread_cxx.cpp @@ -1,10 +1,17 @@ #include +#include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "unity.h" #if __GTHREADS && __GTHREADS_CXX0X +#define LOG_LOCAL_LEVEL CONFIG_LOG_DEFAULT_LEVEL +#include "esp_log.h" +const static char *TAG = "pthread_test"; + static std::shared_ptr global_sp; static std::mutex mtx; static std::recursive_mutex recur_mtx; @@ -56,7 +63,7 @@ static void thread_main() } } -TEST_CASE("pthread CXX", "[pthread]") +TEST_CASE("pthread C++", "[pthread]") { global_sp.reset(new int(1)); @@ -80,4 +87,36 @@ TEST_CASE("pthread CXX", "[pthread]") } } +static void task_test_sandbox(void *arg) +{ + bool *running = (bool *)arg; + + ESP_LOGI(TAG, "About to create a string stream"); + std::stringstream ss; + ESP_LOGI(TAG, "About to write to string stream"); + ss << "Hello World!"; + ESP_LOGI(TAG, "About to extract from stringstream"); + ESP_LOGI(TAG, "Text: %s", ss.str().c_str()); + + if (running) { + *running = false; + vTaskDelete(NULL); + } +} + +TEST_CASE("pthread mix C/C++", "[pthread]") +{ + bool running = true; + + std::thread t1(task_test_sandbox, (void *)NULL); + xTaskCreatePinnedToCore((TaskFunction_t)&task_test_sandbox, "task_test_sandbox", 2048, &running, 5, NULL, 0); + while (running) { + vTaskDelay(1); + } + if (t1.joinable()) { + std::cout << "Join thread " << std::hex << t1.get_id() << std::endl; + t1.join(); + } +} + #endif