How to use RTOS multi-threading support with Newlib?

Question

How do I implement Newlib threading support with my RTOS?

Answer

Starting with the 2015.12 release, all Sourcery CodeBench Personal, Standard and Professional Edition toolchains for ELF and EABI targets provide support in Newlib for multi-threaded applications. Earlier versions and most Sourcery CodeBench Lite toolchains do not contain the necessary support routines.

Threading support is supported by means of a "generic threads" interface. Threading is not a mandatory feature, so the default implementation of this interface in libgcc consists of stub routines that provide transparent single-threaded application support suitable for running on a target without a threading system.

To support a threaded environment, you must provide and link in an additional object or library that replaces some or all of the stub functions defined in libgcc with functions implemented using primitives provided by the RTOS or other target environment. The libgcc stubs have weak linkage, so any strongly-defined versions you provide take precedence.

You can find the libgcc stub functions in the GCC source code (downloadable as part of the source package for your release) in libgcc/gthr-generic.c. The data type definitions are at the start of libgcc/gthr-generic.h. That code has detailed comments explaining the interface.

More concretely, you can implement generic threads with an RTOS's threading and locking primitives by providing implementations of all the __generic_* functions in gthr-generic.c. As described in gthr-generic.h, if a void * cannot hold all required mutex state, your implementation needs to use dynamic memory allocation. Note that some of these functions may be called from static constructors to initialize mutexes used within the C library; thus, you must make sure that your implementations of at least the *_init* functions work correctly during libc startup when not all libc state has been initialized.

Thread safety in newlib uses a reentrancy structure. You must provide a function __getreent that returns a pointer to such a structure for the current thread. Again, this should work during startup. Such a structure may be statically initialized using the _REENT_INIT initializer from sys/reent.h (appropriate for the structure used by the initial thread), or dynamically initialized using _REENT_INIT_PTR (appropriate for those for subsequent threads). Data pointed to by such a structure may be freed (on thread exit) using _reclaim_reent.


This entry was last updated on 13 November 2015.