feat(freertos): add feature to modify task stack deepth dynamically

This commit is contained in:
Dong Heng
2019-12-31 19:31:39 +08:00
parent 7adc7a6424
commit 5f61afc090
7 changed files with 263 additions and 0 deletions

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -29,6 +29,7 @@
/* Scheduler includes. */
#include <stdint.h>
#include <string.h>
#include <xtensa/config/core.h>
#include <xtensa/tie/xt_interrupt.h>
@ -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

View File

@ -0,0 +1,113 @@
/* FreeRTOS timer tests
*/
//#define LOG_LOCAL_LEVEL 5
#include <stdio.h>
#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());
}

View File

@ -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);