-
Notifications
You must be signed in to change notification settings - Fork 7.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
External Memory for Pthread (IDFGH-9237) #10623
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
f-hoepfinger-hr-agrartechnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
f-hoepfinger-hr-agrartechnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What was the reason for moving There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please take a look at pthread unit tests. They produce a deadlock, likely due to moving the |
||
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); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid this might cause trouble for users who initialized each member of
esp_pthread_cfg_t
manually like this:If they would upgrade IDF including this change,
esp_pthread_cfg_t.stack_alloc_caps
is uninitialized. Once the configuration is used, this would produce a crash at runtime at best or a way more subtle memory issue in the worst case.I don't have a definitive solution for this yet. The
esp_pthread_set_cfg
makes it hard to introduce non-breaking configuration changes.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I missed that our documentation is explicitly advising users to zero-initialize configuration structures. You can consider this comment resolved, then.