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

View file

@ -108,6 +108,7 @@
#include "esp_crosscore_int.h" #include "esp_crosscore_int.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "esp_log.h"
/* Defined in portasm.h */ /* Defined in portasm.h */
extern void _frxt_tick_timer_init(void); extern void _frxt_tick_timer_init(void);
@ -133,6 +134,18 @@ unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting
// User exception dispatcher when exiting // User exception dispatcher when exiting
void _xt_user_exit(void); 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 * Stack initialization
*/ */
@ -173,19 +186,33 @@ StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t px
frame = (XtExcFrame *) sp; frame = (XtExcFrame *) sp;
/* Explicitly initialize certain saved registers */ /* Explicitly initialize certain saved registers */
frame->pc = (UBaseType_t) pxCode; /* task entrypoint */ #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->a0 = 0; /* to terminate GDB backtrace */ frame->pc = (UBaseType_t) vPortTaskWrapper; /* task wrapper */
frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */ #else
frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */ 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. */ /* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
/* Also set entry point argument parameter. */ /* Also set entry point argument parameter. */
#ifdef __XTENSA_CALL0_ABI__ #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; frame->ps = PS_UM | PS_EXCM;
#else #else
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */ /* + 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); frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
#endif #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 particular functions in ESP-IDF FreeRTOS which have not been fully tested
in an SMP context. 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