diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index 32d304a53ce2..7a8a18b7b99c 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -21,6 +21,7 @@ extern "C" { /** pthread configuration structure that influences pthread creation */ typedef struct { size_t stack_size; ///< The stack size of the pthread + uint32_t stack_alloc_caps; ///< A bit mask of memory capabilities (MALLOC_CAPS*) to use when allocating the stack. If zero, MALLOC_CAP_DEFAULT is assumed. size_t prio; ///< The thread's priority bool inherit_cfg; ///< Inherit this configuration further const char* thread_name; ///< The thread name. diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index 1d695bfd6838..e21b3b192460 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -38,6 +38,8 @@ typedef struct esp_pthread_entry { bool detached; ///< True if pthread is detached void *retval; ///< Value supplied to calling thread during join void *task_arg; ///< Task arguments + StackType_t *stack_for_task; ///< Task stack + StaticTask_t *taskTC; ///< Task taskTC } esp_pthread_t; /** pthread wrapper task arg */ @@ -121,6 +123,11 @@ static esp_pthread_t *pthread_find(TaskHandle_t task_handle) static void pthread_delete(esp_pthread_t *pthread) { SLIST_REMOVE(&s_threads_list, pthread, esp_pthread_entry, list_node); + if (pthread->task_arg) { + free(pthread->task_arg); + } + free(pthread->stack_for_task); + free(pthread->taskTC); free(pthread); } @@ -221,6 +228,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, } uint32_t stack_size = CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT; + uint32_t stack_alloc_caps = MALLOC_CAP_DEFAULT; BaseType_t prio = CONFIG_PTHREAD_TASK_PRIO_DEFAULT; BaseType_t core_id = get_default_pthread_core(); const char *task_name = CONFIG_PTHREAD_TASK_NAME_DEFAULT; @@ -230,6 +238,10 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, if (pthread_cfg->stack_size) { stack_size = pthread_cfg->stack_size; } + if(pthread_cfg->stack_alloc_caps){ + stack_alloc_caps = pthread_cfg->stack_alloc_caps; + } + if (pthread_cfg->prio && pthread_cfg->prio < configMAX_PRIORITIES) { prio = pthread_cfg->prio; } @@ -272,27 +284,44 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr, task_arg->func = start_routine; task_arg->arg = arg; pthread->task_arg = task_arg; - BaseType_t res = xTaskCreatePinnedToCore(&pthread_task_func, + // stack_size is in bytes. This transformation ensures that the units are + // transformed to the units used in FreeRTOS. + // Note: float division of ceil(m / n) == + // integer division of (m + n - 1) / n + int size_stack = (stack_size + sizeof(StackType_t) - 1) / sizeof(StackType_t); + StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, stack_alloc_caps | MALLOC_CAP_8BIT); + if (stack_for_task == NULL) { + ESP_LOGE(TAG, "Failed to allocate task stack!"); + free(pthread); + free(task_arg); + return ENOMEM; + } + pthread->stack_for_task = stack_for_task; + StaticTask_t *taskTC = (StaticTask_t *) heap_caps_calloc(1, sizeof(StaticTask_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if (taskTC == NULL) { + ESP_LOGE(TAG, "Failed to create task!"); + free(pthread); + free(task_arg); + free(stack_for_task); + return ENOMEM; + } + pthread->taskTC = taskTC; + xHandle = xTaskCreateStaticPinnedToCore(&pthread_task_func, task_name, - // stack_size is in bytes. This transformation ensures that the units are - // transformed to the units used in FreeRTOS. - // Note: float division of ceil(m / n) == - // integer division of (m + n - 1) / n - (stack_size + sizeof(StackType_t) - 1) / sizeof(StackType_t), + size_stack, task_arg, prio, - &xHandle, + stack_for_task, + taskTC, core_id); - if (res != pdPASS) { + if (xHandle == NULL) { ESP_LOGE(TAG, "Failed to create task!"); free(pthread); free(task_arg); - if (res == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) { - return ENOMEM; - } else { - return EAGAIN; - } + free(stack_for_task); + free(taskTC); + return EAGAIN; } pthread->handle = xHandle; @@ -349,6 +378,9 @@ int pthread_join(pthread_t thread, void **retval) wait = true; } else { // thread has exited and task is already suspended, or about to be suspended child_task_retval = pthread->retval; + /* clean up thread local storage before task deletion */ + pthread_internal_local_storage_destructor_callback(handle); + vTaskDelete(handle); pthread_delete(pthread); } } @@ -362,12 +394,12 @@ int pthread_join(pthread_t thread, void **retval) assert(false && "Failed to lock threads list!"); } child_task_retval = pthread->retval; + /* clean up thread local storage before task deletion */ + pthread_internal_local_storage_destructor_callback(handle); + vTaskDelete(handle); pthread_delete(pthread); xSemaphoreGive(s_threads_mux); } - /* clean up thread local storage before task deletion */ - pthread_internal_local_storage_destructor_callback(handle); - vTaskDelete(handle); } if (retval) { @@ -400,10 +432,10 @@ int pthread_detach(pthread_t thread) pthread->detached = true; } else { // pthread already stopped + vTaskDelete(handle); pthread_delete(pthread); /* clean up thread local storage before task deletion */ pthread_internal_local_storage_destructor_callback(handle); - vTaskDelete(handle); } xSemaphoreGive(s_threads_mux); ESP_LOGV(TAG, "%s %p EXIT %d", __FUNCTION__, pthread, ret); @@ -423,11 +455,9 @@ void pthread_exit(void *value_ptr) if (!pthread) { assert(false && "Failed to find pthread for current task!"); } - if (pthread->task_arg) { - free(pthread->task_arg); - } if (pthread->detached) { // auto-free for detached threads + vTaskDelete(NULL); pthread_delete(pthread); detached = true; } else { @@ -450,7 +480,7 @@ void pthread_exit(void *value_ptr) // do anything that might lock (such as printing to stdout) if (detached) { - vTaskDelete(NULL); + } else { vTaskSuspend(NULL); }