source: rtems/cpukit/score/src/wkspace.c @ 54f35888

Last change on this file since 54f35888 was 54f35888, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 25, 2018 at 8:54:12 AM

posix: Provide threads by default

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  thread_count += rtems_resource_maximum_per_allocation(
57    _Configuration_POSIX_Maximum_threads
58  );
59
60  return thread_count;
61}
62
63static uintptr_t _Workspace_Space_for_TLS( uintptr_t page_size )
64{
65  uintptr_t tls_size;
66  uintptr_t space;
67
68  tls_size = _TLS_Get_size();
69
70  /*
71   * In case we have a non-zero TLS size, then we need a TLS area for each
72   * thread.  These areas are allocated from the workspace.  Ensure that the
73   * workspace is large enough to fulfill all requests known at configuration
74   * time (so excluding the unlimited option).  It is not possible to estimate
75   * the TLS size in the configuration at compile-time.  The TLS size is
76   * determined at application link-time.
77   */
78  if ( tls_size > 0 ) {
79    uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment );
80    uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align );
81
82    /*
83     * Memory allocated with an alignment constraint is allocated from the end
84     * of a free block.  The last allocation may need one free block of minimum
85     * size.
86     */
87    space = _Heap_Min_block_size( page_size );
88
89    space += _Workspace_Get_maximum_thread_count()
90      * _Heap_Size_with_overhead( page_size, tls_alloc, tls_align );
91  } else {
92    space = 0;
93  }
94
95  return space;
96}
97
98static uintptr_t _Workspace_Space_for_per_CPU_data( uintptr_t page_size )
99{
100  uintptr_t space;
101
102#ifdef RTEMS_SMP
103  uintptr_t size;
104
105  size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data );
106  _Assert( size % CPU_CACHE_LINE_BYTES == 0 );
107
108  if ( size > 0 ) {
109    /*
110     * Memory allocated with an alignment constraint is allocated from the end of
111     * a free block.  The last allocation may need one free block of minimum
112     * size.
113     */
114    space = _Heap_Min_block_size( page_size );
115
116    space += ( rtems_configuration_get_maximum_processors() - 1 )
117      * _Heap_Size_with_overhead( page_size, size, CPU_CACHE_LINE_BYTES );
118  } else {
119    space = 0;
120  }
121#else
122  space = 0;
123#endif
124
125  return space;
126}
127
128static void _Workspace_Allocate_per_CPU_data( void )
129{
130#ifdef RTEMS_SMP
131  uintptr_t size;
132
133  size = RTEMS_LINKER_SET_SIZE( _Per_CPU_Data );
134
135  if ( size > 0 ) {
136    Per_CPU_Control *cpu;
137    uint32_t         cpu_index;
138    uint32_t         cpu_max;
139
140    cpu = _Per_CPU_Get_by_index( 0 );
141    cpu->data = RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data );
142
143    cpu_max = rtems_configuration_get_maximum_processors();
144
145    for ( cpu_index = 1 ; cpu_index < cpu_max ; ++cpu_index ) {
146      cpu = _Per_CPU_Get_by_index( cpu_index );
147      cpu->data = _Workspace_Allocate_aligned( size, CPU_CACHE_LINE_BYTES );
148      _Assert( cpu->data != NULL );
149      memcpy( cpu->data, RTEMS_LINKER_SET_BEGIN( _Per_CPU_Data ), size);
150    }
151  }
152#endif
153}
154
155void _Workspace_Handler_initialization(
156  Heap_Area *areas,
157  size_t area_count,
158  Heap_Initialization_or_extend_handler extend
159)
160{
161  Heap_Initialization_or_extend_handler init_or_extend;
162  uintptr_t                             remaining;
163  bool                                  do_zero;
164  bool                                  unified;
165  uintptr_t                             page_size;
166  uintptr_t                             overhead;
167  size_t                                i;
168
169  page_size = CPU_HEAP_ALIGNMENT;
170
171  remaining = rtems_configuration_get_work_space_size();
172  remaining += _Workspace_Space_for_TLS( page_size );
173  remaining += _Workspace_Space_for_per_CPU_data( page_size );
174
175  init_or_extend = _Heap_Initialize;
176  do_zero = rtems_configuration_get_do_zero_of_workspace();
177  unified = rtems_configuration_get_unified_work_area();
178  overhead = _Heap_Area_overhead( page_size );
179
180  for ( i = 0; i < area_count; ++i ) {
181    Heap_Area *area;
182
183    area = &areas[ i ];
184
185    if ( do_zero ) {
186      memset( area->begin, 0, area->size );
187    }
188
189    if ( area->size > overhead ) {
190      uintptr_t space_available;
191      uintptr_t size;
192
193      if ( unified ) {
194        size = area->size;
195      } else {
196        if ( remaining > 0 ) {
197          size = remaining < area->size - overhead ?
198            remaining + overhead : area->size;
199        } else {
200          size = 0;
201        }
202      }
203
204      space_available = ( *init_or_extend )(
205        &_Workspace_Area,
206        area->begin,
207        size,
208        page_size
209      );
210
211      area->begin = (char *) area->begin + size;
212      area->size -= size;
213
214      if ( space_available < remaining ) {
215        remaining -= space_available;
216      } else {
217        remaining = 0;
218      }
219
220      init_or_extend = extend;
221    }
222  }
223
224  if ( remaining > 0 ) {
225    _Internal_error( INTERNAL_ERROR_TOO_LITTLE_WORKSPACE );
226  }
227
228  _Heap_Protection_set_delayed_free_fraction( &_Workspace_Area, 1 );
229  _Workspace_Allocate_per_CPU_data();
230}
231
232void *_Workspace_Allocate(
233  size_t   size
234)
235{
236  void *memory;
237
238  memory = _Heap_Allocate( &_Workspace_Area, size );
239  #if defined(DEBUG_WORKSPACE)
240    printk(
241      "Workspace_Allocate(%d) from %p/%p -> %p\n",
242      size,
243      __builtin_return_address( 0 ),
244      __builtin_return_address( 1 ),
245      memory
246    );
247  #endif
248  return memory;
249}
250
251void *_Workspace_Allocate_aligned( size_t size, size_t alignment )
252{
253  return _Heap_Allocate_aligned( &_Workspace_Area, size, alignment );
254}
255
256/*
257 *  _Workspace_Free
258 */
259void _Workspace_Free(
260  void *block
261)
262{
263  #if defined(DEBUG_WORKSPACE)
264    printk(
265      "Workspace_Free(%p) from %p/%p\n",
266      block,
267      __builtin_return_address( 0 ),
268      __builtin_return_address( 1 )
269    );
270  #endif
271  _Heap_Free( &_Workspace_Area, block );
272}
273
274void *_Workspace_Allocate_or_fatal_error(
275  size_t      size
276)
277{
278  void *memory;
279
280  memory = _Heap_Allocate( &_Workspace_Area, size );
281  #if defined(DEBUG_WORKSPACE)
282    printk(
283      "Workspace_Allocate_or_fatal_error(%d) from %p/%p -> %p\n",
284      size,
285      __builtin_return_address( 0 ),
286      __builtin_return_address( 1 ),
287      memory
288    );
289  #endif
290
291  if ( memory == NULL )
292    _Internal_error( INTERNAL_ERROR_WORKSPACE_ALLOCATION );
293
294  return memory;
295}
Note: See TracBrowser for help on using the repository browser.