source: rtems/cpukit/score/src/wkspace.c @ e97806a

5
Last change on this file since e97806a was e97806a, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 14, 2018 at 5:20:05 PM

posix: Split posix_api_configuration_table

Use separate configuration variables to avoid false dependencies.

Update #2514.

  • Property mode set to 100644
File size: 7.0 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Workspace Handler Support
5 *  @ingroup ScoreWorkspace
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2009.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18  #include "config.h"
19#endif
20
21#include <rtems/score/wkspace.h>
22#include <rtems/score/assert.h>
23#include <rtems/score/heapimpl.h>
24#include <rtems/score/interr.h>
25#include <rtems/score/percpudata.h>
26#include <rtems/score/threadimpl.h>
27#include <rtems/score/tls.h>
28#include <rtems/posix/pthread.h>
29#include <rtems/config.h>
30
31#include <string.h>
32
33/* #define DEBUG_WORKSPACE */
34#if defined(DEBUG_WORKSPACE)
35  #include <rtems/bspIo.h>
36#endif
37
38RTEMS_LINKER_RWSET(
39  _Per_CPU_Data,
40  RTEMS_ALIGNED( CPU_CACHE_LINE_BYTES ) char
41);
42
43Heap_Control _Workspace_Area;
44
45static uint32_t _Workspace_Get_maximum_thread_count( void )
46{
47  uint32_t thread_count;
48
49  thread_count = 0;
50  thread_count += _Thread_Get_maximum_internal_threads();
51
52  thread_count += rtems_resource_maximum_per_allocation(
53    Configuration_RTEMS_API.maximum_tasks
54  );
55
56#if defined(RTEMS_POSIX_API)
57  thread_count += rtems_resource_maximum_per_allocation(
58    _Configuration_POSIX_Maximum_threads
59  );
60#endif
61
62  return thread_count;
63}
64
65static uintptr_t _Workspace_Space_for_TLS( uintptr_t page_size )
66{
67  uintptr_t tls_size;
68  uintptr_t space;
69
70  tls_size = _TLS_Get_size();
71
72  /*
73   * In case we have a non-zero TLS size, then we need a TLS area for each
74   * thread.  These areas are allocated from the workspace.  Ensure that the
75   * workspace is large enough to fulfill all requests known at configuration
76   * time (so excluding the unlimited option).  It is not possible to estimate
77   * the TLS size in the configuration at compile-time.  The TLS size is
78   * determined at application link-time.
79   */
80  if ( tls_size > 0 ) {
81    uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment );
82    uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align );
83
84    /*
85     * Memory allocated with an alignment constraint is allocated from the end
86     * of a free block.  The last allocation may need one free block of minimum
87     * size.
88     */
89    space = _Heap_Min_block_size( page_size );
90
91    space += _Workspace_Get_maximum_thread_count()
92      * _Heap_Size_with_overhead( page_size, tls_alloc, tls_align );
93  } else {
94    space = 0;
95  }
96
97  return space;
98}
99
100static uintptr_t _Workspace_Space_for_per_CPU_data( uintptr_t page_size )
101{
102  uintptr_t space;
103
104#ifdef RTEMS_SMP
105  uintptr_t size;
106
107  size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data );
108  _Assert( size % CPU_CACHE_LINE_BYTES == 0 );
109
110  if ( size > 0 ) {
111    /*
112     * Memory allocated with an alignment constraint is allocated from the end of
113     * a free block.  The last allocation may need one free block of minimum
114     * size.
115     */
116    space = _Heap_Min_block_size( page_size );
117
118    space += ( rtems_configuration_get_maximum_processors() - 1 )
119      * _Heap_Size_with_overhead( page_size, size, CPU_CACHE_LINE_BYTES );
120  } else {
121    space = 0;
122  }
123#else
124  space = 0;
125#endif
126
127  return space;
128}
129
130static void _Workspace_Allocate_per_CPU_data( void )
131{
132#ifdef RTEMS_SMP
133  uintptr_t size;
134
135  size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data );
136
137  if ( size > 0 ) {
138    Per_CPU_Control *cpu;
139    uint32_t         cpu_index;
140    uint32_t         cpu_max;
141
142    cpu = _Per_CPU_Get_by_index( 0 );
143    cpu->data = RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data );
144
145    cpu_max = rtems_configuration_get_maximum_processors();
146
147    for ( cpu_index = 1 ; cpu_index < cpu_max ; ++cpu_index ) {
148      cpu = _Per_CPU_Get_by_index( cpu_index );
149      cpu->data = _Workspace_Allocate_aligned( size, CPU_CACHE_LINE_BYTES );
150      _Assert( cpu->data != NULL );
151      memcpy( cpu->data, RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ), size);
152    }
153  }
154#endif
155}
156
157void _Workspace_Handler_initialization(
158  Heap_Area *areas,
159  size_t area_count,
160  Heap_Initialization_or_extend_handler extend
161)
162{
163  Heap_Initialization_or_extend_handler init_or_extend;
164  uintptr_t                             remaining;
165  bool                                  do_zero;
166  bool                                  unified;
167  uintptr_t                             page_size;
168  uintptr_t                             overhead;
169  size_t                                i;
170
171  page_size = CPU_HEAP_ALIGNMENT;
172
173  remaining = rtems_configuration_get_work_space_size();
174  remaining += _Workspace_Space_for_TLS( page_size );
175  remaining += _Workspace_Space_for_per_CPU_data( page_size );
176
177  init_or_extend = _Heap_Initialize;
178  do_zero = rtems_configuration_get_do_zero_of_workspace();
179  unified = rtems_configuration_get_unified_work_area();
180  overhead = _Heap_Area_overhead( page_size );
181
182  for ( i = 0; i < area_count; ++i ) {
183    Heap_Area *area;
184
185    area = &areas[ i ];
186
187    if ( do_zero ) {
188      memset( area->begin, 0, area->size );
189    }
190
191    if ( area->size > overhead ) {
192      uintptr_t space_available;
193      uintptr_t size;
194
195      if ( unified ) {
196        size = area->size;
197      } else {
198        if ( remaining > 0 ) {
199          size = remaining < area->size - overhead ?
200            remaining + overhead : area->size;
201        } else {
202          size = 0;
203        }
204      }
205
206      space_available = ( *init_or_extend )(
207        &_Workspace_Area,
208        area->begin,
209        size,
210        page_size
211      );
212
213      area->begin = (char *) area->begin + size;
214      area->size -= size;
215
216      if ( space_available < remaining ) {
217        remaining -= space_available;
218      } else {
219        remaining = 0;
220      }
221
222      init_or_extend = extend;
223    }
224  }
225
226  if ( remaining > 0 ) {
227    _Internal_error( INTERNAL_ERROR_TOO_LITTLE_WORKSPACE );
228  }
229
230  _Heap_Protection_set_delayed_free_fraction( &_Workspace_Area, 1 );
231  _Workspace_Allocate_per_CPU_data();
232}
233
234void *_Workspace_Allocate(
235  size_t   size
236)
237{
238  void *memory;
239
240  memory = _Heap_Allocate( &_Workspace_Area, size );
241  #if defined(DEBUG_WORKSPACE)
242    printk(
243      "Workspace_Allocate(%d) from %p/%p -> %p\n",
244      size,
245      __builtin_return_address( 0 ),
246      __builtin_return_address( 1 ),
247      memory
248    );
249  #endif
250  return memory;
251}
252
253void *_Workspace_Allocate_aligned( size_t size, size_t alignment )
254{
255  return _Heap_Allocate_aligned( &_Workspace_Area, size, alignment );
256}
257
258/*
259 *  _Workspace_Free
260 */
261void _Workspace_Free(
262  void *block
263)
264{
265  #if defined(DEBUG_WORKSPACE)
266    printk(
267      "Workspace_Free(%p) from %p/%p\n",
268      block,
269      __builtin_return_address( 0 ),
270      __builtin_return_address( 1 )
271    );
272  #endif
273  _Heap_Free( &_Workspace_Area, block );
274}
275
276void *_Workspace_Allocate_or_fatal_error(
277  size_t      size
278)
279{
280  void *memory;
281
282  memory = _Heap_Allocate( &_Workspace_Area, size );
283  #if defined(DEBUG_WORKSPACE)
284    printk(
285      "Workspace_Allocate_or_fatal_error(%d) from %p/%p -> %p\n",
286      size,
287      __builtin_return_address( 0 ),
288      __builtin_return_address( 1 ),
289      memory
290    );
291  #endif
292
293  if ( memory == NULL )
294    _Internal_error( INTERNAL_ERROR_WORKSPACE_ALLOCATION );
295
296  return memory;
297}
Note: See TracBrowser for help on using the repository browser.