source: rtems/cpukit/include/rtems/score/tls.h @ 4c20da4b

5
Last change on this file since 4c20da4b was 4c20da4b, checked in by Sebastian Huber <sebastian.huber@…>, on 04/04/19 at 07:18:11

doxygen: Rename Score* groups in RTEMSScore*

Update #3706

  • Property mode set to 100644
File size: 5.0 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
61extern char _TLS_Alignment[];
62
63typedef struct {
64  /*
65   * FIXME: Not sure if the generation number type is correct for all
66   * architectures.
67  */
68  uint32_t generation_number;
69
70  void *tls_blocks[1];
71} TLS_Dynamic_thread_vector;
72
73typedef struct TLS_Thread_control_block {
74#ifdef __i386__
75  struct TLS_Thread_control_block *tcb;
76#else
77  TLS_Dynamic_thread_vector *dtv;
78  uintptr_t reserved;
79#endif
80} TLS_Thread_control_block;
81
82typedef struct {
83  uintptr_t module;
84  uintptr_t offset;
85} TLS_Index;
86
87static inline uintptr_t _TLS_Get_size( void )
88{
89  /*
90   * Do not use _TLS_Size here since this will lead GCC to assume that this
91   * symbol is not 0 and the tests for 0 will be optimized away.
92   */
93  return (uintptr_t) _TLS_BSS_end - (uintptr_t) _TLS_Data_begin;
94}
95
96static inline uintptr_t _TLS_Heap_align_up( uintptr_t val )
97{
98  uintptr_t msk = CPU_HEAP_ALIGNMENT - 1;
99
100  return (val + msk) & ~msk;
101}
102
103static inline uintptr_t _TLS_Get_thread_control_block_area_size(
104  uintptr_t alignment
105)
106{
107  return alignment <= sizeof(TLS_Thread_control_block) ?
108    sizeof(TLS_Thread_control_block) : alignment;
109}
110
111static inline uintptr_t _TLS_Get_allocation_size(
112  uintptr_t size,
113  uintptr_t alignment
114)
115{
116  uintptr_t allocation_size = 0;
117
118  allocation_size += _TLS_Heap_align_up( size );
119  allocation_size += _TLS_Get_thread_control_block_area_size( alignment );
120
121#ifndef __i386__
122  allocation_size += sizeof(TLS_Dynamic_thread_vector);
123#endif
124
125  return allocation_size;
126}
127
128static inline void *_TLS_Copy_and_clear( void *tls_area )
129{
130  tls_area = memcpy(
131    tls_area,
132    _TLS_Data_begin,
133    (size_t) ((uintptr_t)_TLS_Data_size)
134  );
135
136
137  memset(
138    (char *) tls_area + (size_t)((intptr_t) _TLS_BSS_begin) -
139      (size_t)((intptr_t) _TLS_Data_begin),
140    0,
141    ((size_t) (intptr_t)_TLS_BSS_size)
142  );
143
144  return tls_area;
145}
146
147static inline void *_TLS_Initialize(
148  void *tls_block,
149  TLS_Thread_control_block *tcb,
150  TLS_Dynamic_thread_vector *dtv
151)
152{
153#ifdef __i386__
154  (void) dtv;
155  tcb->tcb = tcb;
156#else
157  tcb->dtv = dtv;
158  dtv->generation_number = 1;
159  dtv->tls_blocks[0] = tls_block;
160#endif
161
162  return _TLS_Copy_and_clear( tls_block );
163}
164
165/* Use Variant I, TLS offsets emitted by linker takes the TCB into account */
166static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
167{
168  void *tls_block = (char *) tls_area
169    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
170  TLS_Thread_control_block *tcb = tls_area;
171  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
172  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
173    ((char *) tls_block + aligned_size);
174
175  return _TLS_Initialize( tls_block, tcb, dtv );
176}
177
178/* Use Variant I, TLS offsets emitted by linker neglects the TCB */
179static inline void *_TLS_TCB_before_TLS_block_initialize( void *tls_area )
180{
181  void *tls_block = (char *) tls_area
182    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
183  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
184    ((char *) tls_block - sizeof(*tcb));
185  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
186  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
187    ((char *) tls_block + aligned_size);
188
189  return _TLS_Initialize( tls_block, tcb, dtv );
190}
191
192/* Use Variant II */
193static inline void *_TLS_TCB_after_TLS_block_initialize( void *tls_area )
194{
195  uintptr_t size = (uintptr_t) _TLS_Size;
196  uintptr_t tls_align = (uintptr_t) _TLS_Alignment;
197  uintptr_t tls_mask = tls_align - 1;
198  uintptr_t heap_align = _TLS_Heap_align_up( tls_align );
199  uintptr_t heap_mask = heap_align - 1;
200  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
201    ((char *) tls_area + ((size + heap_mask) & ~heap_mask));
202  void *tls_block = (char *) tcb - ((size + tls_mask) & ~tls_mask);
203  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
204    ((char *) tcb + sizeof(*tcb));
205
206  _TLS_Initialize( tls_block, tcb, dtv );
207
208  return tcb;
209}
210
211/** @} */
212
213#ifdef __cplusplus
214}
215#endif /* __cplusplus */
216
217#endif /* _RTEMS_SCORE_TLS_H */
Note: See TracBrowser for help on using the repository browser.