Not very familiar with the newlib reentrant feature, I’d like to ask whether it can be used on an SMP system.
Thanks
The current implementation may not be compatible with SMP systems. I believe that in an SMP environment, each core would require its own _impure_ptr, which would need to be updated during context switches. The existing implementation assumes a single global _impure_ptr, an assumption that probably won’t hold in a multi-core setup. We need to verify these concerns with the newlib maintainers and confirm whether newlib supports multi-core environments at all.
Thanks for your confirm!
@aggarg - Any update on this?
Thanks!
Not that I am aware of. As I have mentioned before, most likely, this would need a change in newlib first.
Ooops, hang on, this will take me a while to correct, sorry…
newlib must be built with:
--enable-newlib-reent-thread-localwhich places each task’s reentrancy structure in thread-local-storage (task-local-storage in FreeRTOS-speak). Internally--enable-newlib-reent-thread-localdefines the macro-D__DYNAMIC_REENT__--enable-newlib-multithread(might be the default)
Below was not looking at the current newlib sources; this has changed a bit…
Hi guys - To further clarify (I hope) this issue, if newlib is built with reentrancy enabled (add -D__DYNAMIC_REENT__ to CFLAGS build options), Newlib dynamically obtains _REENT through __getreent() instead of using a single global -impure_ptr. In turn, __getreent() must be implemented to return the appropriate reentrancy structure for the current processor, and the FreeRTOS implementation must support maintaining processor-specific reentrancy pointers during task switching.
@aggarg - Please let me know if this makes sense. Presumably SMP FreeRTOS is already doing this? Required for example to support NXP MCXN947 (two M33 cores). Thanks!
PS: This is documented here: newlib/newlib/libc/include/reent.h at master · eblot/newlib · GitHub
Perhaps part of the issue is that FreeRTOS doesn’t control how Newlib is bundled with the build system, as that is part of the setup provided by the build system.
At best, these routines are part of the port layer for the implementation.
You can’t just “randomly” and a new compilation of newlib into a system, unless you also have the source code of the rest of the system library and recompile that, as you need to maintain binary ABI compatibility, which might not hold between all options. (They try, but you would need to verify what options they used, and make sure they would be compatible enough).
As of today, we do not maintain per-core reentrancy pointers. Instead, we rely on a global _impure_ptr defined by newlib: FreeRTOS-Kernel/include/newlib-freertos.h at main · FreeRTOS/FreeRTOS-Kernel · GitHub.
The comment you shared seems to indicate that the following changes are required:
Maintain a per-core_impure_ptrarray.Update these macros to use these per-core_impure_ptr.- Implement
__getreent()to return the pointer tostruct _reentstored in the TCB of the task running on the current core.
These changes have not been implemented yet. If you’d like to take this on, we welcome contributions!
Out of curiosity, where did this comment come from?
Actually, I don’t think we need a separate pointer array, but that __getreent() should access a per-task pointer to the environment saved as a TCB entry.
You are right. Thank you for correcting me. I have updated my response.
This is because newlib only uses impure_ptr, not impure_ptr[id]. Therefore, using only the impure_ptr array in the FreeRTOS kernel is not feasible.
I currently have implementation that supports newlib reentrant for SMP. As you discussed before, this requires the toolchain to enable __DYNAMIC_REENT__.
Toolchain provides two reentrancy mechanisms:
- When
__DYNAMIC_REENT__is defined, the reentrancy structure corresponding to the current execution context is obtained through__getreent(). - When
__DYNAMIC_REENT__is not defined, the global variable_impure_ptris used directly.
#if defined(__DYNAMIC_REENT__) && !defined(__SINGLE_THREAD__)
#ifndef __getreent
struct _reent * __getreent (void);
#endif
# define _REENT (__getreent())
#else /* __SINGLE_THREAD__ || !__DYNAMIC_REENT__ */
# define _REENT _impure_ptr
#endif /* __SINGLE_THREAD__ || !__DYNAMIC_REENT__ */
With __DYNAMIC_REENT__ enabled, newlib provides lock APIs such as retarget_lock. These lock APIs should also require a FreeRTOS implementation. Furthermore, these locks also depend on toolchain configurations.
Thank you for clarifying that.
Are you saying that implementing __getreent() enables you to use newlib on a SMP system? If yes, can you share your implementation for others benefit?
Did you implement these too to get newlib working on SMP?
I will repeat again, with normal tool-chain use, you are not recompiling newlib with your program, and thus CAN NOT change the settings it was compiled with, like _DYNAMIC_REENT_. The vendor of the tool-chain will have compiled newlib with some settings, and you generally need to live with them. If you can’t, you can recompile newlib with different settings, but then YOU need to make sure your replacement version meets the requirements of the other vendor supplied libraries.
Yes @richard-damon, we understand, but there are a few further wrinkles. I’m trying to find time to make a complete write-up of this issue… Of course it might be more sensible to just use picolib…
Which are all tool implementer decisions. As long as you understand that, and don’t expect that you are talking to “tool-users”, it is good. Most of the people here are tool-users, and not implementers, so just want to make it clear to other users that what you are talking about isn’t something easy to do for such a user.
You’re completely right. We maintain an in-house toolchain and provide customized version.
@aggarg Yes to al. I’m definitely glad to share this work.
Currently, my implementation spans across both the BSP and the FreeRTOS kernel. I’m not entirely sure which repository would be the best fit for this, or if I should clean it up and submit the kernel portion directly to FreeRTOS-Kernel?
Would appreciate any comments on this draft:
It’s missing a few bits:
- AI prompt to evaluate current project and toolchain setup to see what you are working with and what important pieces are missing in your project,
- some minor stuff,
- please point out anything else !!
I know of a few SMP implementations floating around, glad to hear @Saiiijchan has one working.
@richard-damon - Context for all this is trying to figure out a path forward for some new applications. Been burned enough times that I want to verify the fundamentals first… Zephyr is getting much better and has fixed most of the issues formerly preventing our using it - still has reentrancy problems with C++ exceptions (we can live without exceptions, not everyone can, badly limits what libraries we can use).
Again, might be more sensible to use picolib with FreeRTOS but some more checking/writing required there as well.
Thanks guys!
That sounds reasonable.