source: rtems/c/src/lib/libc/malloc.c @ dfe5faf8

4.104.114.84.95
Last change on this file since dfe5faf8 was 9c49db4, checked in by Joel Sherrill <joel.sherrill@…>, on 01/08/01 at 18:26:44

2001-01-08 Ralf Corsepius <corsepiu@…>

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