source: rtems/cpukit/include/rtems/score/tls.h @ cab00c70

5
Last change on this file since cab00c70 was c5b7942, checked in by Chris Johns <chrisj@…>, on 08/19/22 at 05:22:17

cpukit/include: Fix including in C++

Closes #4709

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSScoreTLS
5 *
6 * @brief Thread-Local Storage (TLS)
7 */
8
9/*
10 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#ifndef _RTEMS_SCORE_TLS_H
24#define _RTEMS_SCORE_TLS_H
25
26#include <rtems/score/cpu.h>
27
28#include <string.h>
29
30#ifdef __cplusplus
31extern "C" {
32#endif /* __cplusplus */
33
34/**
35 * @defgroup RTEMSScoreTLS Thread-Local Storage (TLS)
36 *
37 * @ingroup RTEMSScore
38 *
39 * @brief Thread-local storage (TLS) support.
40 *
41 * Variants I and II are according to Ulrich Drepper, "ELF Handling For
42 * Thread-Local Storage".
43 *
44 * @{
45 */
46
47extern char _TLS_Data_begin[];
48
49extern char _TLS_Data_end[];
50
51extern char _TLS_Data_size[];
52
53extern char _TLS_BSS_begin[];
54
55extern char _TLS_BSS_end[];
56
57extern char _TLS_BSS_size[];
58
59extern char _TLS_Size[];
60
61/**
62 * @brief The TLS section alignment.
63 *
64 * This symbol is provided by the linker command file as the maximum alignment
65 * of the .tdata and .tbss sections.  The linker ensures that the first TLS
66 * output section is aligned to the maximum alignment of all TLS output
67 * sections, see function _bfd_elf_tls_setup() in bfd/elflink.c of the GNU
68 * Binutils sources.  The linker command file must take into account the case
69 * that the .tdata section is empty and the .tbss section is non-empty.
70 */
71extern char _TLS_Alignment[];
72
73typedef struct {
74  /*
75   * FIXME: Not sure if the generation number type is correct for all
76   * architectures.
77  */
78  uint32_t generation_number;
79
80  void *tls_blocks[1];
81} TLS_Dynamic_thread_vector;
82
83typedef struct TLS_Thread_control_block {
84#ifdef __i386__
85  struct TLS_Thread_control_block *tcb;
86#else /* !__i386__ */
87  TLS_Dynamic_thread_vector *dtv;
88#if CPU_SIZEOF_POINTER == 4
89  uintptr_t reserved;
90#endif
91#endif /* __i386__ */
92} TLS_Thread_control_block;
93
94typedef struct {
95  uintptr_t module;
96  uintptr_t offset;
97} TLS_Index;
98
99/**
100 * @brief Gets the TLS size.
101 *
102 * @return The TLS size.
103 */
104static inline uintptr_t _TLS_Get_size( void )
105{
106  uintptr_t size;
107
108  /*
109   * We must be careful with using _TLS_Size here since this could lead GCC to
110   * assume that this symbol is not 0 and the tests for 0 will be optimized
111   * away.
112   */
113  size = (uintptr_t) _TLS_Size;
114  RTEMS_OBFUSCATE_VARIABLE( size );
115  return size;
116}
117
118/**
119 * @brief Returns the value aligned up to the heap alignment.
120 *
121 * @param val The value to align.
122 *
123 * @return The value aligned to the heap alignment.
124 */
125static inline uintptr_t _TLS_Heap_align_up( uintptr_t val )
126{
127  uintptr_t msk = CPU_HEAP_ALIGNMENT - 1;
128
129  return (val + msk) & ~msk;
130}
131
132/**
133 * @brief Returns the size of the thread control block area size for this
134 *      alignment, or the minimum size if alignment is too small.
135 *
136 * @param alignment The alignment for the operation.
137 *
138 * @return The size of the thread control block area.
139 */
140static inline uintptr_t _TLS_Get_thread_control_block_area_size(
141  uintptr_t alignment
142)
143{
144  return alignment <= sizeof(TLS_Thread_control_block) ?
145    sizeof(TLS_Thread_control_block) : alignment;
146}
147
148/**
149 * @brief Return the TLS area allocation size.
150 *
151 * @return The TLS area allocation size.
152 */
153uintptr_t _TLS_Get_allocation_size( void );
154
155/**
156 * @brief Copies TLS size bytes from the address tls_area and returns a pointer
157 *      to the start of the area after clearing it.
158 *
159 * @param tls_area The starting address of the area to clear.
160 *
161 * @return The pointer to the beginning of the cleared section.
162 */
163static inline void *_TLS_Copy_and_clear( void *tls_area )
164{
165  tls_area = memcpy(
166    tls_area,
167    _TLS_Data_begin,
168    (size_t) ((uintptr_t)_TLS_Data_size)
169  );
170
171
172  memset(
173    (char *) tls_area + (size_t)((intptr_t) _TLS_BSS_begin) -
174      (size_t)((intptr_t) _TLS_Data_begin),
175    0,
176    ((size_t) (intptr_t)_TLS_BSS_size)
177  );
178
179  return tls_area;
180}
181
182/**
183 * @brief Initializes the dynamic thread vector.
184 *
185 * @param tls_block The tls block for @a dtv.
186 * @param tcb The thread control block for @a dtv.
187 * @param[out] dtv The dynamic thread vector to initialize.
188 *
189 * @return Pointer to an area that was copied and cleared from tls_block
190 *       onwards (@see _TLS_Copy_and_clear).
191 */
192static inline void *_TLS_Initialize(
193  void *tls_block,
194  TLS_Thread_control_block *tcb,
195  TLS_Dynamic_thread_vector *dtv
196)
197{
198#ifdef __i386__
199  (void) dtv;
200  tcb->tcb = tcb;
201#else
202  tcb->dtv = dtv;
203  dtv->generation_number = 1;
204  dtv->tls_blocks[0] = tls_block;
205#endif
206
207  return _TLS_Copy_and_clear( tls_block );
208}
209
210/**
211 * @brief Initializes a dynamic thread vector beginning at the given starting
212 *      address.
213 *
214 * Use Variant I, TLS offsets emitted by linker takes the TCB into account.
215 *
216 * @param tls_area The tls area for the initialization.
217 *
218 * @return Pointer to an area that was copied and cleared from tls_block
219 *       onwards (@see _TLS_Copy_and_clear).
220 */
221static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
222{
223  void *tls_block = (char *) tls_area
224    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
225  TLS_Thread_control_block *tcb = (TLS_Thread_control_block*) tls_area;
226  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
227  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
228    ((char *) tls_block + aligned_size);
229
230  return _TLS_Initialize( tls_block, tcb, dtv );
231}
232
233/**
234 * @brief Initializes a dynamic thread vector with the area before a given
235 * starting address as thread control block.
236 *
237 * Use Variant I, TLS offsets emitted by linker neglects the TCB.
238 *
239 * @param tls_area The tls area for the initialization.
240 *
241 * @return Pointer to an area that was copied and cleared from tls_block
242 *       onwards (@see _TLS_Copy_and_clear).
243 */
244static inline void *_TLS_TCB_before_TLS_block_initialize( void *tls_area )
245{
246  void *tls_block = (char *) tls_area
247    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
248  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
249    ((char *) tls_block - sizeof(*tcb));
250  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
251  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
252    ((char *) tls_block + aligned_size);
253
254  return _TLS_Initialize( tls_block, tcb, dtv );
255}
256
257/**
258 * @brief Initializes a dynamic thread vector with the area after a given
259 * starting address as thread control block.
260 *
261 * Use Variant II
262 *
263 * @param tls_area The tls area for the initialization.
264 *
265 * @return Pointer to an area that was copied and cleared from tls_block
266 *       onwards (@see _TLS_Copy_and_clear).
267 */
268static inline void *_TLS_TCB_after_TLS_block_initialize( void *tls_area )
269{
270  uintptr_t size = (uintptr_t) _TLS_Size;
271  uintptr_t tls_align = (uintptr_t) _TLS_Alignment;
272  uintptr_t tls_mask = tls_align - 1;
273  uintptr_t heap_align = _TLS_Heap_align_up( tls_align );
274  uintptr_t heap_mask = heap_align - 1;
275  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
276    ((char *) tls_area + ((size + heap_mask) & ~heap_mask));
277  void *tls_block = (char *) tcb - ((size + tls_mask) & ~tls_mask);
278  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
279    ((char *) tcb + sizeof(*tcb));
280
281  _TLS_Initialize( tls_block, tcb, dtv );
282
283  return tcb;
284}
285
286/** @} */
287
288#ifdef __cplusplus
289}
290#endif /* __cplusplus */
291
292#endif /* _RTEMS_SCORE_TLS_H */
Note: See TracBrowser for help on using the repository browser.