瀏覽代碼

Merge branch 'feature/tasks_can_return' into 'master'

freertos: enclose task functions in wrapper function

See merge request idf/esp-idf!2935
Angus Gratton 7 年之前
父節點
當前提交
822fdd6e53
共有 3 個文件被更改,包括 52 次插入6 次删除
  1. 11 0
      components/freertos/Kconfig
  2. 33 6
      components/freertos/port.c
  3. 8 0
      docs/en/api-guides/freertos-smp.rst

+ 11 - 0
components/freertos/Kconfig

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

+ 33 - 6
components/freertos/port.c

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

+ 8 - 0
docs/en/api-guides/freertos-smp.rst

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