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

4.115
Last change on this file since bee71f8e was bee71f8e, checked in by Sebastian Huber <sebastian.huber@…>, on 04/30/14 at 12:54:58

score: Fix TLS size usage

  • Property mode set to 100644
File size: 4.7 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup ScoreTLS
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 ScoreTLS Thread-Local Storage (TLS)
36 *
37 * @ingroup Score
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 {
74  TLS_Dynamic_thread_vector *dtv;
75  uintptr_t reserved;
76} TLS_Thread_control_block;
77
78typedef struct {
79  uintptr_t module;
80  uintptr_t offset;
81} TLS_Index;
82
83static inline uintptr_t _TLS_Get_size( void )
84{
85  /*
86   * Do not use _TLS_Size here since this will lead GCC to assume that this
87   * symbol is not 0 and the tests for 0 will be optimized away.
88   */
89  return (uintptr_t) _TLS_BSS_end - (uintptr_t) _TLS_Data_begin;
90}
91
92static inline uintptr_t _TLS_Heap_align_up( uintptr_t val )
93{
94  uintptr_t msk = CPU_HEAP_ALIGNMENT - 1;
95
96  return (val + msk) & ~msk;
97}
98
99static inline uintptr_t _TLS_Get_thread_control_block_area_size(
100  uintptr_t alignment
101)
102{
103  return alignment <= sizeof(TLS_Thread_control_block) ?
104    sizeof(TLS_Thread_control_block) : alignment;
105}
106
107static inline uintptr_t _TLS_Get_allocation_size(
108  uintptr_t size,
109  uintptr_t alignment
110)
111{
112  uintptr_t aligned_size = _TLS_Heap_align_up( size );
113
114  return _TLS_Get_thread_control_block_area_size( alignment )
115    + aligned_size + sizeof(TLS_Dynamic_thread_vector);
116}
117
118static inline void *_TLS_Copy_and_clear( void *tls_area )
119{
120  tls_area = memcpy( tls_area, _TLS_Data_begin, (size_t) _TLS_Data_size );
121
122  memset(
123    (char *) tls_area + (size_t) _TLS_BSS_begin - (size_t) _TLS_Data_begin,
124    0,
125    (size_t) _TLS_BSS_size
126  );
127
128  return tls_area;
129}
130
131static inline void *_TLS_Initialize(
132  void *tls_block,
133  TLS_Thread_control_block *tcb,
134  TLS_Dynamic_thread_vector *dtv
135)
136{
137  tcb->dtv = dtv;
138  dtv->generation_number = 1;
139  dtv->tls_blocks[0] = tls_block;
140
141  return _TLS_Copy_and_clear( tls_block );
142}
143
144/* Use Variant I, TLS offsets emitted by linker takes the TCB into account */
145static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
146{
147  void *tls_block = (char *) tls_area
148    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
149  TLS_Thread_control_block *tcb = tls_area;
150  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
151  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
152    ((char *) tls_block + aligned_size);
153
154  return _TLS_Initialize( tls_block, tcb, dtv );
155}
156
157/* Use Variant I, TLS offsets emitted by linker neglects the TCB */
158static inline void *_TLS_TCB_before_TLS_block_initialize( void *tls_area )
159{
160  void *tls_block = (char *) tls_area
161    + _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
162  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
163    ((char *) tls_block - sizeof(*tcb));
164  uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
165  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
166    ((char *) tls_block + aligned_size);
167
168  return _TLS_Initialize( tls_block, tcb, dtv );
169}
170
171/* Use Variant II */
172static inline void *_TLS_TCB_after_TLS_block_initialize( void *tls_area )
173{
174  uintptr_t size = (uintptr_t) _TLS_Size;
175  uintptr_t tls_align = (uintptr_t) _TLS_Alignment;
176  uintptr_t tls_mask = tls_align - 1;
177  uintptr_t heap_align = _TLS_Heap_align_up( tls_align );
178  uintptr_t heap_mask = heap_align - 1;
179  TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
180    ((char *) tls_area + ((size + heap_mask) & ~heap_mask));
181  void *tls_block = (char *) tcb - ((size + tls_mask) & ~tls_mask);
182  TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
183    ((char *) tcb + sizeof(*tcb));
184
185  _TLS_Initialize( tls_block, tcb, dtv );
186
187  return tcb;
188}
189
190/** @} */
191
192#ifdef __cplusplus
193}
194#endif /* __cplusplus */
195
196#endif /* _RTEMS_SCORE_TLS_H */
Note: See TracBrowser for help on using the repository browser.