source: rtems/cpukit/libcsupport/src/malloc.c @ d16b2d3

4.104.114.84.95
Last change on this file since d16b2d3 was 690861c, checked in by Joel Sherrill <joel.sherrill@…>, on 11/26/03 at 17:50:53

2003-11-26 Joel Sherrill <joel@…>

PR 523/filesystem

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