diff --git a/components/freertos/freertos/tasks.c b/components/freertos/freertos/tasks.c index 66c7e854..c747cd74 100644 --- a/components/freertos/freertos/tasks.c +++ b/components/freertos/freertos/tasks.c @@ -5221,4 +5221,114 @@ when performing module tests). */ #endif +#if( configENABLE_TASK_MODIFY_STACK_DEPTH == 1 ) + +#if( INCLUDE_xTimerPendFunctionCall != 1 || configUSE_TIMERS != 1) +#error "INCLUDE_xTimerPendFunctionCall and configUSE_TIMERS should be enable" +#endif + + #include "semphr.h" + + struct prvTaskModifyParam { + TCB_t *pxTCB; + uint32_t newStackDepth; + SemaphoreHandle_t sem; + BaseType_t uxResult; + }; + + static void prvTaskModifyStackDepth(void *param, uint32_t null_val) + { + struct prvTaskModifyParam *pTaskModifyParam = (struct prvTaskModifyParam *)param; + StackType_t *pxStack; + UBaseType_t oldStackBytes; + TCB_t *pxTCB = (TCB_t *)pTaskModifyParam->pxTCB; + UBaseType_t newStackBytes = (size_t)pTaskModifyParam->newStackDepth * sizeof(StackType_t); + const UBaseType_t unitSize = sizeof(void *); + + oldStackBytes = (size_t)pxTCB->pxEndOfStack - (size_t)pxTCB->pxTopOfStack + unitSize; + if (oldStackBytes >= newStackBytes) { + pTaskModifyParam->uxResult = pdFAIL; + goto exit; + } + + pxStack = pvPortMalloc(newStackBytes); + if (!pxStack) { + pTaskModifyParam->uxResult = pdFAIL; + goto exit; + } + memset(pxStack, tskSTACK_FILL_BYTE, newStackBytes - oldStackBytes); + vPortInitContextFromOldStack(&pxStack[newStackBytes - oldStackBytes], (StackType_t *)pxTCB->pxTopOfStack, oldStackBytes); + + vPortFree(pxTCB->pxStack); + + pxTCB->pxStack = pxStack; + pxTCB->pxTopOfStack = &pxStack[newStackBytes - oldStackBytes]; + pxTCB->pxEndOfStack = (StackType_t *)((size_t)pxStack + (size_t)pTaskModifyParam->newStackDepth - unitSize); + + pTaskModifyParam->uxResult = pdPASS; + + exit: + if (pTaskModifyParam->sem) + xSemaphoreGive(pTaskModifyParam->sem); + } + + BaseType_t vTaskModifyStackDepth(TaskHandle_t xTask, const configSTACK_DEPTH_TYPE newStackDepth) + { + BaseType_t xReturn; + + if (newStackDepth & 0x3) { + return pdFAIL; + } + + if (prvGetTCBFromHandle(xTask) != pxCurrentTCB) { + struct prvTaskModifyParam taskModifyParam; + + taskModifyParam.pxTCB = prvGetTCBFromHandle(xTask); + taskModifyParam.newStackDepth = newStackDepth; + taskModifyParam.sem = NULL; + + vTaskSuspend(xTask); + prvTaskModifyStackDepth(&taskModifyParam, 0); + xReturn = taskModifyParam.uxResult; + vTaskResume(xTask); + } else { + SemaphoreHandle_t sem; + struct prvTaskModifyParam *taskModifyParam; + + if (xTimerGetTimerDaemonTaskHandle() == xTask) { + return pdFAIL; + } + + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + return pdFAIL; + } + + sem = xSemaphoreCreateBinary(); + if (!sem) { + return pdFAIL; + } + + taskModifyParam = pvPortMalloc(sizeof(struct prvTaskModifyParam)); + if (!taskModifyParam) { + vSemaphoreDelete(sem); + return pdFAIL; + } + + taskModifyParam->pxTCB = prvGetTCBFromHandle(xTask); + taskModifyParam->newStackDepth = newStackDepth; + taskModifyParam->sem = sem; + + xReturn = xTimerPendFunctionCall(prvTaskModifyStackDepth, taskModifyParam, 0, portMAX_DELAY); + if (xReturn == pdPASS) { + xSemaphoreTake(sem, portMAX_DELAY); + xReturn = taskModifyParam->uxResult; + } + + vSemaphoreDelete(sem); + vPortFree(taskModifyParam); + } + + return xReturn; + } +#endif /* configENABLE_TASK_MODIFY_STACK_DEPTH == 1 */ diff --git a/components/freertos/include/freertos/private/portable.h b/components/freertos/include/freertos/private/portable.h index 55d7f04c..6d2212c7 100644 --- a/components/freertos/include/freertos/private/portable.h +++ b/components/freertos/include/freertos/private/portable.h @@ -146,6 +146,16 @@ void vPortEndScheduler( void ) PRIVILEGED_FUNCTION; */ int xPortInIsrContext(void); +/** + * @brief Copy thread context from old thread stack to new thread stack and + * then reset the SP. + * + * @param newStackTop new thread stack pointer + * @param oldStackTop old thread stack pointer + * @param stackSize stack size + */ +void vPortInitContextFromOldStack(StackType_t *newStackTop, StackType_t *oldStackTop, UBaseType_t stackSize); + #ifdef __cplusplus } #endif diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index bd677d8c..5f50397c 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -2383,6 +2383,16 @@ typedef struct xTASK_SNAPSHOT */ UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArraySize, UBaseType_t * const pxTcbSz ); +/** + * @brief Modify task stack size dynamically. + * + * @param xTask task handle which created by xTaskCreate. + * @param newStackDepth task' new stack size. + * + * @return pdPASS if success or others if failed + */ +BaseType_t vTaskModifyStackDepth(TaskHandle_t xTask, const configSTACK_DEPTH_TYPE newStackDepth); + #ifdef __cplusplus } #endif diff --git a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h index bfbda69a..295e9c32 100644 --- a/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/port/esp8266/include/freertos/FreeRTOSConfig.h @@ -194,5 +194,9 @@ uint32_t esp_get_time(void); #define configENABLE_TASK_SNAPSHOT 1 #endif +#ifndef configENABLE_TASK_MODIFY_STACK_DEPTH +#define configENABLE_TASK_MODIFY_STACK_DEPTH 1 +#endif + #endif /* FREERTOS_CONFIG_H */ diff --git a/components/freertos/port/esp8266/port.c b/components/freertos/port/esp8266/port.c index 4f3721b4..3b75a342 100644 --- a/components/freertos/port/esp8266/port.c +++ b/components/freertos/port/esp8266/port.c @@ -29,6 +29,7 @@ /* Scheduler includes. */ #include +#include #include #include @@ -218,6 +219,15 @@ portBASE_TYPE xPortStartScheduler(void) return pdTRUE; } +void vPortInitContextFromOldStack(StackType_t *newStackTop, StackType_t *oldStackTop, UBaseType_t stackSize) +{ + uintptr_t *sp; + + memcpy(newStackTop, oldStackTop, stackSize); + sp = (uintptr_t *)newStackTop; + sp[XT_STK_A1 / sizeof(uintptr_t)] = (uintptr_t)sp + XT_STK_FRMSZ; +} + void vPortEndScheduler(void) { /* It is unlikely that the CM3 port will require this function as there diff --git a/components/freertos/test/test_freertos_task_modify_stack_depth.c b/components/freertos/test/test_freertos_task_modify_stack_depth.c new file mode 100644 index 00000000..e4955114 --- /dev/null +++ b/components/freertos/test/test_freertos_task_modify_stack_depth.c @@ -0,0 +1,113 @@ +/* FreeRTOS timer tests +*/ +//#define LOG_LOCAL_LEVEL 5 + +#include +#include "unity.h" +#include "esp_system.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" + +#define TASK_DEPTH_SIZE 8192 +#define TAG "test_modify_stack_depth" + +static SemaphoreHandle_t s_main_sem, s_sync_sem[3]; +static TaskHandle_t s_task_handle[3]; + +static void test_thread_1(void *p) +{ + for (int i = 0; i < 16; i++) { + ESP_LOGD(TAG, "Modify tasks' stack depth to be %u", TASK_DEPTH_SIZE - i * 128); + + vTaskModifyStackDepth(NULL, TASK_DEPTH_SIZE - i * 128); + } + + xSemaphoreGive(s_main_sem); + + vTaskDelete(NULL); +} + +static void test_thread_2(void *p) +{ + for (int i = 0; i < 10; i++) { + vTaskPrioritySet(NULL, 5); + + ESP_LOGD(TAG, "Modify tasks' stack depth to be %u", TASK_DEPTH_SIZE - i * 128); + + for (int j = 0; j < 3; j++) { + vTaskModifyStackDepth(s_task_handle[j], TASK_DEPTH_SIZE - i * 128); + xSemaphoreGive(s_sync_sem[j]); + } + + ESP_LOGD(TAG, "Modify successfully"); + + vTaskPrioritySet(NULL, 3); + } + + xSemaphoreGive(s_main_sem); + + vTaskDelete(NULL); +} + +static void test_thread_3(void *p) +{ + int count = 10; + int num = (int)p; + + while (count--) { + TEST_ASSERT(xSemaphoreTake(s_sync_sem[num], portMAX_DELAY) == pdTRUE); + } + + vTaskDelete(NULL); +} + +TEST_CASE("Test task modifies itself's stack depth", "[freertos]") +{ + TEST_ASSERT(s_main_sem = xSemaphoreCreateBinary()); + + TEST_ASSERT(xTaskCreatePinnedToCore(test_thread_1, "thread_1", TASK_DEPTH_SIZE, NULL, 5, NULL, 0) == pdTRUE); + + TEST_ASSERT(xSemaphoreTake(s_main_sem, portMAX_DELAY) == pdTRUE); + + vQueueDelete(s_main_sem); + s_main_sem = NULL; + + vTaskDelay(5); +} + +TEST_CASE("Test task modifies other tasks' stack depth", "[freertos]") +{ + ESP_LOGD(TAG, "before heap is %u", esp_get_free_heap_size()); + + TEST_ASSERT(s_main_sem = xSemaphoreCreateBinary()); + + for (int i = 0; i < 3; i++) { + TEST_ASSERT(s_sync_sem[i] = xSemaphoreCreateBinary()); + } + + vTaskSuspendAll(); + + TEST_ASSERT(xTaskCreatePinnedToCore(test_thread_2, "thread_2", TASK_DEPTH_SIZE, NULL, 5, NULL, 0) == pdTRUE); + + TEST_ASSERT(xTaskCreatePinnedToCore(test_thread_3, "thread_4", TASK_DEPTH_SIZE, (void *)0, 4, &s_task_handle[0], 0) == pdTRUE); + TEST_ASSERT(xTaskCreatePinnedToCore(test_thread_3, "thread_5", TASK_DEPTH_SIZE, (void *)1, 5, &s_task_handle[1], 0) == pdTRUE); + TEST_ASSERT(xTaskCreatePinnedToCore(test_thread_3, "thread_6", TASK_DEPTH_SIZE, (void *)2, 6, &s_task_handle[2], 0) == pdTRUE); + + xTaskResumeAll(); + + TEST_ASSERT(xSemaphoreTake(s_main_sem, portMAX_DELAY) == pdTRUE); + + for (int i = 0; i < 3; i++) { + vQueueDelete(s_sync_sem[i]); + s_sync_sem[i] = NULL; + } + + vQueueDelete(s_main_sem); + s_main_sem = NULL; + + vTaskDelay(5); + + ESP_LOGD(TAG, "after heap is %u", esp_get_free_heap_size()); +} diff --git a/examples/protocols/openssl_demo/main/openssl_demo_example_main.c b/examples/protocols/openssl_demo/main/openssl_demo_example_main.c index 7638e0cd..66b4eda4 100644 --- a/examples/protocols/openssl_demo/main/openssl_demo_example_main.c +++ b/examples/protocols/openssl_demo/main/openssl_demo_example_main.c @@ -139,6 +139,12 @@ static void openssl_task(void *p) ESP_LOGI(TAG, "OK"); +#if configENABLE_TASK_MODIFY_STACK_DEPTH == 1 + ESP_LOGI(TAG, "Before modification stack depth of this thread, free heap size is %u", esp_get_free_heap_size()); + vTaskModifyStackDepth(NULL, 2048); + ESP_LOGI(TAG, "After modification stack depth of this thread, free heap size is %u", esp_get_free_heap_size()); +#endif + ESP_LOGI(TAG, "send request to %s port %d ......", OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); ret = SSL_write(ssl, send_data, send_bytes);