Skip to content

Commit b36251d

Browse files
committed
Add Thread Local Storage (TLS) support using Picolibc functions
Thread Local Storage (TLS) offers a platform-native mechanism for managing per-task variables that doesn't rely on custom support in FreeRTOS for things like errno. Picolibc uses TLS internally for all variables that are intended to be task-local. Because of the TLS architecture, only variables which are actually used end up getting allocate space in the TLS block. Contrast this with the newlib 'struct _reent' block which holds all possible task-local values, even for APIs not used by the application. Picolibc also has TLS helper functions that provide the necessary platform-specific code which makes the FreeRTOS changes platform independent. This patch uses those hooks instead of providing the platform specific code in FreeRTOS itself. The picolibc helper functions rely on elements within the linker script to arrange the TLS data in memory and define some symbols. Applications wanting to use this mechanism will need changes in their linker script when migrating to picolibc. Signed-off-by: Keith Packard <[email protected]>
1 parent ec7c403 commit b36251d

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

.github/lexicon.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,7 @@ mclk
10611061
mconfigintcoresw
10621062
mcr
10631063
mcu
1064+
md
10641065
mddr
10651066
mder
10661067
mdh
@@ -1341,6 +1342,7 @@ phy
13411342
phya
13421343
pic
13431344
picnt
1345+
picolibc
13441346
pien
13451347
piir
13461348
pimr

include/FreeRTOS.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@
7474
#include <reent.h>
7575
#endif
7676

77+
#ifndef configUSE_PICOLIBC_TLS
78+
#ifdef PICOLIBC_TLS
79+
#define configUSE_PICOLIBC_TLS 1
80+
#else
81+
#define configUSE_PICOLIBC_TLS 0
82+
#endif
83+
#endif
84+
7785
/*
7886
* Check all the required application specific macros have been defined.
7987
* These macros are application specific and (as downloaded) are defined
@@ -1228,6 +1236,9 @@ typedef struct xSTATIC_TCB
12281236
#if ( configUSE_POSIX_ERRNO == 1 )
12291237
int iDummy22;
12301238
#endif
1239+
#if ( configUSE_PICOLIBC_TLS == 1)
1240+
void *pvDummy23;
1241+
#endif
12311242
} StaticTask_t;
12321243

12331244
/*

tasks.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@
5858
#include <stdio.h>
5959
#endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
6060

61+
#if ( configUSE_PICOLIBC_TLS == 1)
62+
63+
/* If picolibc TLS support is being used, then initialize a per-thread
64+
* TLS block off the end of the stack and set the TLS pointer at each
65+
* task switch. More information about picolibc's thread local storage
66+
* support is provided on the following link:
67+
* https://github.com/picolibc/picolibc/blob/main/doc/tls.md */
68+
69+
#include <picotls.h>
70+
#endif
71+
6172
#if ( configUSE_PREEMPTION == 0 )
6273

6374
/* If the cooperative scheduler is being used then a yield should not be
@@ -329,6 +340,13 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to
329340
#if ( configUSE_POSIX_ERRNO == 1 )
330341
int iTaskErrno;
331342
#endif
343+
#if ( configUSE_PICOLIBC_TLS == 1)
344+
/* Pointer to thread-local variables for this task.
345+
* These are allocated from the task stack and managed
346+
* using Picolibc TLS support functions.
347+
*/
348+
void *pvTls;
349+
#endif
332350
} tskTCB;
333351

334352
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
@@ -964,6 +982,29 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
964982
}
965983
#endif
966984

985+
#if ( configUSE_PICOLIBC_TLS == 1)
986+
{
987+
/* Allocate thread local storage block off the end of the
988+
* stack. The _tls_size() function returns the size (in
989+
* bytes) of the total TLS area used by the application */
990+
#if ( portSTACK_GROWTH < 0 )
991+
{
992+
pxTopOfStack = ( StackType_t *) ( ( ( portPOINTER_SIZE_TYPE) pxTopOfStack) - _tls_size() );
993+
pxNewTCB->pvTls = pxTopOfStack;
994+
}
995+
#else /* portSTACK_GROWTH */
996+
{
997+
pxNewTCB->pvTls = pxTopOfStack;
998+
pxTopOfStack = ( StackType_t *) ( ( ( portPOINTER_SIZE_TYPE) pxTopOfStack) + _tls_size() );
999+
}
1000+
#endif /* portSTACK_GROWTH */
1001+
/* Initialize the thread local storage block. This copies
1002+
* the initialization data to initialized variables and
1003+
* clears uninitialized variables to zero */
1004+
_init_tls(pxNewTCB->pvTls);
1005+
}
1006+
#endif
1007+
9671008
#if ( configUSE_NEWLIB_REENTRANT == 1 )
9681009
{
9691010
/* Initialise this task's Newlib reent structure.
@@ -2047,6 +2088,11 @@ void vTaskStartScheduler( void )
20472088
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
20482089
}
20492090
#endif /* configUSE_NEWLIB_REENTRANT */
2091+
#if ( configUSE_PICOLIBC_TLS == 1)
2092+
{
2093+
_set_tls(pxCurrentTCB->pvTls);
2094+
}
2095+
#endif
20502096

20512097
xNextTaskUnblockTime = portMAX_DELAY;
20522098
xSchedulerRunning = pdTRUE;
@@ -3087,6 +3133,11 @@ void vTaskSwitchContext( void )
30873133
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
30883134
}
30893135
#endif /* configUSE_NEWLIB_REENTRANT */
3136+
#if ( configUSE_PICOLIBC_TLS == 1)
3137+
{
3138+
_set_tls(pxCurrentTCB->pvTls);
3139+
}
3140+
#endif
30903141
}
30913142
}
30923143
/*-----------------------------------------------------------*/

0 commit comments

Comments
 (0)