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

4.104.114.84.95
Last change on this file since cf1f72e was cf1f72e, checked in by Joel Sherrill <joel.sherrill@…>, on 06/13/00 at 21:53:38

Moved i386 and m68k cache management code to libcpu. Everything
now is an implementation of the prototypes in rtems/rtems/cache.h.
The libcpu/i386/wrapup directory is no longer needed.
The PowerPC needs this done to it.

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