Skip to content

Commit 488011b

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 4633870 commit 488011b

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

.github/lexicon.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,7 @@ mclk
10631063
mconfigintcoresw
10641064
mcr
10651065
mcu
1066+
md
10661067
mddr
10671068
mder
10681069
mdh
@@ -1344,6 +1345,7 @@ phy
13441345
phya
13451346
pic
13461347
picnt
1348+
picolibc
13471349
pien
13481350
piir
13491351
pimr

include/FreeRTOS.h

+11
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
@@ -1223,6 +1231,9 @@ typedef struct xSTATIC_TCB
12231231
#if ( configUSE_POSIX_ERRNO == 1 )
12241232
int iDummy22;
12251233
#endif
1234+
#if ( configUSE_PICOLIBC_TLS == 1)
1235+
void *pvDummy23;
1236+
#endif
12261237
} StaticTask_t;
12271238

12281239
/*

tasks.c

+51
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
@@ -328,6 +339,13 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to
328339
#if ( configUSE_POSIX_ERRNO == 1 )
329340
int iTaskErrno;
330341
#endif
342+
#if ( configUSE_PICOLIBC_TLS == 1)
343+
/* Pointer to thread-local variables for this task.
344+
* These are allocated from the task stack and managed
345+
* using Picolibc TLS support functions.
346+
*/
347+
void *pvTls;
348+
#endif
331349
} tskTCB;
332350

333351
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
@@ -986,6 +1004,29 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
9861004
}
9871005
#endif
9881006

1007+
#if ( configUSE_PICOLIBC_TLS == 1)
1008+
{
1009+
/* Allocate thread local storage block off the end of the
1010+
* stack. The _tls_size() function returns the size (in
1011+
* bytes) of the total TLS area used by the application */
1012+
#if ( portSTACK_GROWTH < 0 )
1013+
{
1014+
pxTopOfStack = ( StackType_t *) ( ( ( portPOINTER_SIZE_TYPE) pxTopOfStack) - _tls_size() );
1015+
pxNewTCB->pvTls = pxTopOfStack;
1016+
}
1017+
#else /* portSTACK_GROWTH */
1018+
{
1019+
pxNewTCB->pvTls = pxTopOfStack;
1020+
pxTopOfStack = ( StackType_t *) ( ( ( portPOINTER_SIZE_TYPE) pxTopOfStack) + _tls_size() );
1021+
}
1022+
#endif /* portSTACK_GROWTH */
1023+
/* Initialize the thread local storage block. This copies
1024+
* the initialization data to initialized variables and
1025+
* clears uninitialized variables to zero */
1026+
_init_tls(pxNewTCB->pvTls);
1027+
}
1028+
#endif
1029+
9891030
#if ( configUSE_NEWLIB_REENTRANT == 1 )
9901031
{
9911032
/* Initialise this task's Newlib reent structure.
@@ -2068,6 +2109,11 @@ void vTaskStartScheduler( void )
20682109
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
20692110
}
20702111
#endif /* configUSE_NEWLIB_REENTRANT */
2112+
#if ( configUSE_PICOLIBC_TLS == 1)
2113+
{
2114+
_set_tls(pxCurrentTCB->pvTls);
2115+
}
2116+
#endif
20712117

20722118
xNextTaskUnblockTime = portMAX_DELAY;
20732119
xSchedulerRunning = pdTRUE;
@@ -3081,6 +3127,11 @@ void vTaskSwitchContext( void )
30813127
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
30823128
}
30833129
#endif /* configUSE_NEWLIB_REENTRANT */
3130+
#if ( configUSE_PICOLIBC_TLS == 1)
3131+
{
3132+
_set_tls(pxCurrentTCB->pvTls);
3133+
}
3134+
#endif
30843135
}
30853136
}
30863137
/*-----------------------------------------------------------*/

0 commit comments

Comments
 (0)