Skip to content

Conversation

@Dazza0
Copy link
Contributor

@Dazza0 Dazza0 commented May 23, 2022

Description

Currently, when configUSE_NEWLIB_REENTRANT is enabled, FreeRTOS will update Newlibs _impure_ptr on every context switch to point to the current task's reent struct. However, this behavior is no longer valid for SMP due to the fact that two or more cores can switch contexts, thus leading to a corrupted _impure_ptr (i.e., multiple cores cannot share the same _impure_ptr.

Newlib provides a __DYNAMIC_REENT__ feature where all newlib functions will call a __getreent() function to get the required reentrancy structure instead of referring to the _impure_ptr. In case of FreeRTOS, it should just return the current core's current task's reent struct.

This commit adds the following changes:

  • A configNEWLIB_REENTRANT_IS_DYNAMIC option to enable Newlib dynamic reentrancy support in FreeRTOS SMP
  • _impure_ptr is no longer modified by FreeRTOS when configNEWLIB_REENTRANT_IS_DYNAMIC is enabled
  • Port should provide their own __getreent() (probably somewhere in freertos_tasks_c_additions.h. The function could look something like the following:
/**
 * @brief Get reentrancy structure of the current task
 *
 * - This funciton is required by newlib (when __DYNAMIC_REENT__ is enabled)
 * - It will return a pointer to the current task's reent struct
 * - If FreeRTOS is not running, it will return the global reent struct
 *
 * @return Pointer to a the (current taks's)/(global) reent struct
 */
struct _reent* __getreent(void) {
    // No lock needed because if this changes, we won't be running anymore.
    TCB_t *pxCurTask = xTaskGetCurrentTaskHandle();
    if (pxCurTask == NULL) {
        // No task running. Return global struct.
        return _GLOBAL_REENT;
    } else {
        // We have a task; return its reentrant struct.
        return &pxCurTask->xNewLib_reent;
    }
}

Previously, newlib's _impure_ptr was updated on every context switch
to point to the current task's _reent structure.

However, this behavior is no longer valid on multi-core systems due
to the fact that multiple cores can switch contexts at the same time,
thus leading to the corruption of the _impure_ptr.

However, Newlib can be compiled with __DYNAMIC_REENT__ enabled which
will cause newlib functions to call __getreent() instead in order to
obtain the required reent struct.

This commit adds dynamic reentrancy support to FreeRTOS:

- Added a configNEWLIB_REENTRANT_IS_DYNAMIC to enable dynamic reentrancy support
- _impure_ptr is no longer updated with reentrancy is dynamic
- Port must provide their own __getreent() that returns the current task's reent struct
@Dazza0 Dazza0 requested a review from a team as a code owner May 23, 2022 16:09
@ravibhagavandas ravibhagavandas merged commit 34b8e24 into FreeRTOS:smp May 31, 2022
@Dazza0 Dazza0 deleted the feature/newlib_dynamic_reentrancy branch October 29, 2023 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants