source: rtems/cpukit/libcsupport/src/malloc.c @ 458bd34

4.104.114.84.95
Last change on this file since 458bd34 was 458bd34, checked in by Joel Sherrill <joel.sherrill@…>, on 11/05/99 at 16:44:02

This is another pass at making sure that nothing outside the BSP
unnecessarily uses any variables defined by the BSP. On this
sweep, use of BSP_Configuration and Cpu_table was eliminated.

A significant part of this modification was the addition of
macros to access fields in the RTEMS configuration structures.

This is necessary to strengthen the division between the BSP independent
parts of RTEMS and the BSPs themselves. This started after
comments and analysis by Ralf Corsepius <corsepiu@…>.

  • Property mode set to 100644
File size: 9.3 KB
Line 
1/*
2 *  RTEMS Malloc Family Implementation
3 *
4 *
5 *  COPYRIGHT (c) 1989-1998.
6 *  On-Line Applications Research Corporation (OAR).
7 *  Copyright assigned to U.S. Government, 1994.
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.OARcorp.com/rtems/license.html.
12 *
13 *  $Id$
14 */
15
16#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
17#include <rtems.h>
18#include "libcsupport.h"
19#ifdef RTEMS_NEWLIB
20#include <sys/reent.h>
21#endif
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <assert.h>
27#include <errno.h>
28#include <string.h>
29
30#include <unistd.h>    /* sbrk(2) */
31
32rtems_id RTEMS_Malloc_Heap;
33size_t RTEMS_Malloc_Sbrk_amount;
34
35#ifdef RTEMS_DEBUG
36#define MALLOC_STATS
37#define MALLOC_DIRTY
38#endif
39
40#ifdef MALLOC_STATS
41#define MSBUMP(f,n)    rtems_malloc_stats.f += (n)
42
43struct {
44    unsigned32  space_available;             /* current size of malloc area */
45    unsigned32  malloc_calls;                /* # calls to malloc */
46    unsigned32  free_calls;
47    unsigned32  realloc_calls;
48    unsigned32  calloc_calls;
49    unsigned32  max_depth;                   /* most ever malloc'd at 1 time */
50    unsigned64  lifetime_allocated;
51    unsigned64  lifetime_freed;
52} rtems_malloc_stats;
53
54#else                   /* No rtems_malloc_stats */
55#define MSBUMP(f,n)
56#endif
57
58void RTEMS_Malloc_Initialize(
59  void   *start,
60  size_t  length,
61  size_t  sbrk_amount
62)
63{
64  rtems_status_code   status;
65  void               *starting_address;
66  rtems_unsigned32    old_address;
67  rtems_unsigned32    u32_address;
68
69  /*
70   * If the starting address is 0 then we are to attempt to
71   * get length worth of memory using sbrk. Make sure we
72   * align the address that we get back.
73   */
74
75  starting_address = start;
76  RTEMS_Malloc_Sbrk_amount = sbrk_amount;
77
78  if (!starting_address) {
79    u32_address = (unsigned int)sbrk(length);
80
81    if (u32_address == (rtems_unsigned32) -1) {
82      rtems_fatal_error_occurred( RTEMS_NO_MEMORY );
83      /* DOES NOT RETURN!!! */
84    }
85
86    if (u32_address & (CPU_ALIGNMENT-1)) {
87      old_address = u32_address;
88      u32_address = (u32_address + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1);
89
90       /*
91        * adjust the length by whatever we aligned by
92        */
93
94      length -= u32_address - old_address;
95    }
96
97    starting_address = (void *)u32_address;
98  }
99
100  /*
101   *  If the BSP is not clearing out the workspace, then it is most likely
102   *  not clearing out the initial memory for the heap.  There is no
103   *  standard supporting zeroing out the heap memory.  But much code
104   *  with UNIX history seems to assume that memory malloc'ed during
105   *  initialization (before any free's) is zero'ed.  This is true most
106   *  of the time under UNIX because zero'ing memory when it is first
107   *  given to a process eliminates the chance of a process seeing data
108   *  left over from another process.  This would be a security violation.
109   */
110
111  if ( rtems_cpu_configuration_get_do_zero_of_workspace() )
112     memset( starting_address, 0, length );
113
114  /*
115   *  Unfortunately we cannot use assert if this fails because if this
116   *  has failed we do not have a heap and if we do not have a heap
117   *  STDIO cannot work because there will be no buffers.
118   */
119
120  status = rtems_region_create(
121    rtems_build_name( 'H', 'E', 'A', 'P' ),
122    starting_address,
123    length,
124    CPU_ALIGNMENT,
125    RTEMS_DEFAULT_ATTRIBUTES,
126    &RTEMS_Malloc_Heap
127  );
128  if ( status != RTEMS_SUCCESSFUL )
129    rtems_fatal_error_occurred( status );
130
131#ifdef MALLOC_STATS
132  /* zero all the stats */
133  (void) memset( &rtems_malloc_stats, 0, sizeof(rtems_malloc_stats) );
134#endif
135 
136  MSBUMP(space_available, length);
137}
138
139#ifdef RTEMS_NEWLIB
140void *malloc(
141  size_t  size
142)
143{
144  void              *return_this;
145  void              *starting_address;
146  rtems_unsigned32   the_size;
147  rtems_unsigned32   sbrk_amount;
148  rtems_status_code  status;
149
150  MSBUMP(malloc_calls, 1);
151
152  if ( !size )
153    return (void *) 0;
154
155  /*
156   * Try to give a segment in the current region if there is not
157   * enough space then try to grow the region using rtems_region_extend().
158   * If this fails then return a NULL pointer.
159   */
160
161  status = rtems_region_get_segment(
162    RTEMS_Malloc_Heap,
163    size,
164    RTEMS_NO_WAIT,
165    RTEMS_NO_TIMEOUT,
166    &return_this
167  );
168
169  if ( status != RTEMS_SUCCESSFUL ) {
170    /*
171     *  Round to the "requested sbrk amount" so hopefully we won't have
172     *  to grow again for a while.  This effectively does sbrk() calls
173     *  in "page" amounts.
174     */
175
176    sbrk_amount = RTEMS_Malloc_Sbrk_amount;
177
178    if ( sbrk_amount == 0 )
179      return (void *) 0;
180
181    the_size = ((size + sbrk_amount) / sbrk_amount * sbrk_amount);
182
183    if (((rtems_unsigned32)starting_address = (void *)sbrk(the_size))
184            == (rtems_unsigned32) -1)
185      return (void *) 0;
186
187    status = rtems_region_extend(
188      RTEMS_Malloc_Heap,
189      starting_address,
190      the_size
191    );
192    if ( status != RTEMS_SUCCESSFUL ) {
193      sbrk(-the_size);
194      errno = ENOMEM;
195      return (void *) 0;
196    }
197   
198    MSBUMP(space_available, the_size);
199
200    status = rtems_region_get_segment(
201      RTEMS_Malloc_Heap,
202       size,
203       RTEMS_NO_WAIT,
204       RTEMS_NO_TIMEOUT,
205       &return_this
206    );
207    if ( status != RTEMS_SUCCESSFUL ) {
208      errno = ENOMEM;
209      return (void *) 0;
210    }
211  }
212
213#ifdef MALLOC_STATS
214  if (return_this)
215  {
216      unsigned32 actual_size;
217      unsigned32 current_depth;
218      status = rtems_region_get_segment_size(
219                   RTEMS_Malloc_Heap, return_this, &actual_size);
220      MSBUMP(lifetime_allocated, actual_size);
221      current_depth = rtems_malloc_stats.lifetime_allocated -
222                   rtems_malloc_stats.lifetime_freed;
223      if (current_depth > rtems_malloc_stats.max_depth)
224          rtems_malloc_stats.max_depth = current_depth;
225  }
226#endif
227
228#ifdef MALLOC_DIRTY
229  (void) memset(return_this, 0xCF, size);
230#endif
231
232  return return_this;
233}
234
235void *calloc(
236  size_t nelem,
237  size_t elsize
238)
239{
240  register char *cptr;
241  int length;
242
243  MSBUMP(calloc_calls, 1);
244
245  length = nelem * elsize;
246  cptr = malloc( length );
247  if ( cptr )
248    memset( cptr, '\0', length );
249
250  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
251
252  return cptr;
253}
254
255void *realloc(
256  void *ptr,
257  size_t size
258)
259{
260  rtems_unsigned32  old_size;
261  rtems_status_code status;
262  char *new_area;
263
264  MSBUMP(realloc_calls, 1);
265
266  if ( !ptr )
267    return malloc( size );
268
269  if ( !size ) {
270    free( ptr );
271    return (void *) 0;
272  }
273
274  new_area = malloc( size );
275 
276  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
277
278  if ( !new_area ) {
279    free( ptr );
280    return (void *) 0;
281  }
282
283  status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &old_size );
284  if ( status != RTEMS_SUCCESSFUL ) {
285    errno = EINVAL;
286    return (void *) 0;
287  }
288
289  memcpy( new_area, ptr, (size < old_size) ? size : old_size );
290  free( ptr );
291
292  return new_area;
293
294}
295
296void free(
297  void *ptr
298)
299{
300  rtems_status_code status;
301
302  MSBUMP(free_calls, 1);
303
304  if ( !ptr )
305    return;
306
307#ifdef MALLOC_STATS
308  {
309      unsigned32        size;
310      status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &size );
311      if ( status == RTEMS_SUCCESSFUL ) {
312          MSBUMP(lifetime_freed, size);
313      }
314  }
315#endif
316 
317  status = rtems_region_return_segment( RTEMS_Malloc_Heap, ptr );
318  if ( status != RTEMS_SUCCESSFUL ) {
319    errno = EINVAL;
320    assert( 0 );
321  }
322}
323/* end if RTEMS_NEWLIB */
324#endif
325
326#ifdef MALLOC_STATS
327/*
328 * Dump the malloc statistics
329 * May be called via atexit()  (installable by our bsp) or
330 * at any time by user
331 */
332
333void malloc_dump(void)
334{
335    unsigned32 allocated = rtems_malloc_stats.lifetime_allocated -
336                     rtems_malloc_stats.lifetime_freed;
337
338    printf("Malloc stats\n");
339    printf("  avail:%uk  allocated:%uk (%d%%) "
340              "max:%uk (%d%%) lifetime:%Luk freed:%Luk\n",
341           (unsigned int) rtems_malloc_stats.space_available / 1024,
342           (unsigned int) allocated / 1024,
343           /* avoid float! */
344           (allocated * 100) / rtems_malloc_stats.space_available,
345           (unsigned int) rtems_malloc_stats.max_depth / 1024,
346           (rtems_malloc_stats.max_depth * 100) / rtems_malloc_stats.space_available,
347           (unsigned64) rtems_malloc_stats.lifetime_allocated / 1024,
348           (unsigned64) rtems_malloc_stats.lifetime_freed / 1024);
349    printf("  Call counts:   malloc:%d   free:%d   realloc:%d   calloc:%d\n",
350           rtems_malloc_stats.malloc_calls,
351           rtems_malloc_stats.free_calls,
352           rtems_malloc_stats.realloc_calls,
353           rtems_malloc_stats.calloc_calls);
354}
355
356
357void malloc_walk(size_t source, size_t printf_enabled)
358{
359   register Region_Control *the_region;
360   Objects_Locations        location;
361 
362   the_region = _Region_Get( RTEMS_Malloc_Heap, &location );
363   if ( location == OBJECTS_LOCAL )
364   {
365      _Heap_Walk( &the_region->Memory, source, printf_enabled );
366      _Thread_Enable_dispatch();
367   }
368}
369
370#else
371
372void malloc_dump(void)
373{
374   return;
375}
376 
377void malloc_walk(size_t source, size_t printf_enabled)
378{
379   return;
380}
381
382#endif
383
384/*
385 *  "Reentrant" versions of the above routines implemented above.
386 */
387
388#ifdef RTEMS_NEWLIB
389void *_malloc_r(
390  struct _reent *ignored,
391  size_t  size
392)
393{
394  return malloc( size );
395}
396
397void *_calloc_r(
398  struct _reent *ignored,
399  size_t nelem,
400  size_t elsize
401)
402{
403  return calloc( nelem, elsize );
404}
405
406void *_realloc_r(
407  struct _reent *ignored,
408  void *ptr,
409  size_t size
410)
411{
412  return realloc( ptr, size );
413}
414
415void _free_r(
416  struct _reent *ignored,
417  void *ptr
418)
419{
420  free( ptr );
421}
422#endif
423
Note: See TracBrowser for help on using the repository browser.