Merge branch 'feature/tasks_can_return' into 'master'

freertos: enclose task functions in wrapper function

See merge request idf/esp-idf!2935
This commit is contained in:
Angus Gratton 2018-09-18 07:38:24 +08:00
commit 822fdd6e53
3 changed files with 52 additions and 6 deletions

View file

@ -419,4 +419,15 @@ endif #FREERTOS_UNICORE
endif # FREERTOS_DEBUG_INTERNALS
config FREERTOS_TASK_FUNCTION_WRAPPER
bool "Enclose all task functions in a wrapper function"
depends on OPTIMIZATION_LEVEL_DEBUG
default y
help
If enabled, all FreeRTOS task functions will be enclosed in a wrapper function.
If a task function mistakenly returns (i.e. does not delete), the call flow will
return to the wrapper function. The wrapper function will then log an error and
abort the application. This option is also required for GDB backtraces and C++
exceptions to work correctly inside top-level task functions.
endmenu

View file

@ -108,6 +108,7 @@
#include "esp_crosscore_int.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
/* Defined in portasm.h */
extern void _frxt_tick_timer_init(void);
@ -133,6 +134,18 @@ unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting
// User exception dispatcher when exiting
void _xt_user_exit(void);
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
// Wrapper to allow task functions to return (increases stack overhead by 16 bytes)
static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
{
pxCode(pvParameters);
//FreeRTOS tasks should not return. Log the task name and abort.
char * pcTaskName = pcTaskGetTaskName(NULL);
ESP_LOGE("FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName);
abort();
}
#endif
/*
* Stack initialization
*/
@ -173,19 +186,33 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
frame = (XtExcFrame *) sp;
/* Explicitly initialize certain saved registers */
frame->pc = (UBaseType_t) pxCode; /* task entrypoint */
frame->a0 = 0; /* to terminate GDB backtrace */
frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */
frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->pc = (UBaseType_t) vPortTaskWrapper; /* task wrapper */
#else
frame->pc = (UBaseType_t) pxCode; /* task entrypoint */
#endif
frame->a0 = 0; /* to terminate GDB backtrace */
frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */
frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */
/* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
/* Also set entry point argument parameter. */
#ifdef __XTENSA_CALL0_ABI__
frame->a2 = (UBaseType_t) pvParameters;
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->a2 = (UBaseType_t) pxCode;
frame->a3 = (UBaseType_t) pvParameters;
#else
frame->a2 = (UBaseType_t) pvParameters;
#endif
frame->ps = PS_UM | PS_EXCM;
#else
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
frame->a6 = (UBaseType_t) pvParameters;
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->a6 = (UBaseType_t) pxCode;
frame->a7 = (UBaseType_t) pvParameters;
#else
frame->a6 = (UBaseType_t) pvParameters;
#endif
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
#endif

View file

@ -496,3 +496,11 @@ functionality of :cpp:func:`xTaskCreateStaticPinnedToCore` in ESP-IDF FreeRTOS
particular functions in ESP-IDF FreeRTOS which have not been fully tested
in an SMP context.
:envvar:`CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER` will enclose all task functions
within a wrapper function. In the case that a task function mistakenly returns
(i.e. does not call :cpp:func:`vTaskDelete`), the call flow will return to the
wrapper function. The wrapper function will then log an error and abort the
application, as illustrated below::
E (25) FreeRTOS: FreeRTOS task should not return. Aborting now!
abort() was called at PC 0x40085c53 on core 0