DRNadler / FreeRTOS_helpers

Helpers for some common problems when using FreeRTOS, GCC, and newlib.
135 stars 20 forks source link

Flaws with current implementation on STM32 Cortex-M4 port. #15

Open Spamfast opened 11 months ago

Spamfast commented 11 months ago
  1. As well as wrappers for malloc_lock/unlock & __env_lock/unlock, we could provide tz_lock/unlock using the same logic as the env one. https://sourceware.org/newlib/libc.html#g_t_005f_005ftz_005flock
  2. The Newlib documentations states that __malloc_lock/unlock must be recursive - https://sourceware.org/newlib/libc.html#g_t_005f_005fmalloc_005flock. However, the current ISR safe implementation is not, in that a second call to lock will trash malLock_uxSavedInterruptStatus. I don't think she is at the moment, but if Corinna choses to use the flexibility, the callbacks will leave interrupts disabled. It needs a counter to match lock calls to unlock calls and only actually lock and unlock on the first and last call respectively.
  3. The implementation of _sbrk assumes that the initial stack below _estack can be reclaimed once the FreeRTOS scheduler is running. Actually on all M4 ports I've used, FreeRTOS uses the PSP to point to the task stack and exceptions use the MSP which FreeRTOS sets back to _estack when starting the first task. The end of the heap can be defined as (uint8_t *) &_estack - (size_t) &_Min_Stack_Size where _Min_Stack_Size is the linker symbol from the linker LD file. I usually have a uint8_t pointer initialized in the first call to _sbrk to avoid calculating this expression every time.
  4. There are a bunch of internal locks protecting filesystem APIs and lots of other stuff which don't have __XXX_lock/unlock support. In STM's (and OpenSTM's) implementation these are non-functional and because Newlib is supplied as a binary with the library lock structure defined as a struct containing a single char, can't easily be overridden.
    • The best solution is to rebuild Newlib from scratch of course but that's a pain.
    • For projects using such non-reentrant Newlib binaries, I use the linker's wrapper facility to wrap the functions described in https://sourceware.org/newlib/libc.html#g_t_005f_005fretarget_005flock_005finit with wrappers.
    • For dynamically created locks, since a Semaphore_t is just a pointer and a _LOCK_T is also a pointer, then all that is needed is casting.
    • However, this doesn't work for the static lock objects that Newlib expects to be present and which STM et al hard-code into the binary because they are expected to have been initialized already. For these, I provide a table mapping pointers to the existing symbols to SemaphoreHandle_t or StaticSemaphore_t which an initialization function called very early on populates with an appropriate recursive or non-recursive mutex. The __retargetXXX lock/unlock functions check the table and alias to the appropriate FreeRTOS mutex.