From e8ae38024d5a13c3090f1ad500e48fb2143da3e8 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 19 Sep 2016 19:28:36 +0800 Subject: [PATCH] components/freertos: override per-task __cleanup handler to close stdin, stdout, stderr Default _cleanup_r doesn't do that, which leaks these three file descriptors. --- components/esp32/syscalls.c | 17 +++++++++++++++++ components/freertos/tasks.c | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/components/esp32/syscalls.c b/components/esp32/syscalls.c index 1aff0167aa..350f5f4105 100644 --- a/components/esp32/syscalls.c +++ b/components/esp32/syscalls.c @@ -367,6 +367,23 @@ void IRAM_ATTR _lock_release_recursive(_lock_t *lock) { lock_release_generic(lock, queueQUEUE_TYPE_RECURSIVE_MUTEX); } +// This function is not part on newlib API, it is defined in libc/stdio/local.h +// It is called as part of _reclaim_reent via a pointer in __cleanup member +// of struct _reent. +// This function doesn't call _fclose_r for _stdin, _stdout, _stderr members +// of struct reent. Not doing so causes a memory leak each time a task is +// terminated. We replace __cleanup member with _extra_cleanup_r (below) to work +// around this. +extern void _cleanup_r(struct _reent* r); + +void _extra_cleanup_r(struct _reent* r) +{ + _cleanup_r(r); + _fclose_r(r, r->_stdout); + _fclose_r(r, r->_stderr); + _fclose_r(r, r->_stdin); +} + static struct _reent s_reent; /* diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index a4595154ed..ff3a0530d6 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -85,6 +85,7 @@ task.h is included from an application file. */ #include "StackMacros.h" #include "portmacro.h" #include "semphr.h" +#include "sys/reent.h" /* Lint e961 and e750 are suppressed as a MISRA exception justified because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the @@ -3489,6 +3490,9 @@ TCB_t *pxNewTCB; #if ( INCLUDE_vTaskDelete == 1 ) + // TODO: move this to newlib component and provide a header file + extern void _extra_cleanup_r(struct _reent* r); + static void prvDeleteTCB( TCB_t *pxTCB ) { /* This call is required specifically for the TriCore port. It must be @@ -3500,6 +3504,7 @@ TCB_t *pxNewTCB; to the task to free any memory allocated at the application level. */ #if ( configUSE_NEWLIB_REENTRANT == 1 ) { + pxTCB->xNewLib_reent.__cleanup = &_extra_cleanup_r; _reclaim_reent( &( pxTCB->xNewLib_reent ) ); } #endif /* configUSE_NEWLIB_REENTRANT */