source: rtems/c/src/lib/libc/malloc.c @ 0bf2ff8

4.104.114.84.95
Last change on this file since 0bf2ff8 was 07a3253d, checked in by Joel Sherrill <joel.sherrill@…>, on 11/23/98 at 19:07:58

Added base version of file system infrastructure. This includes a major
overhaul of the RTEMS system call interface. This base file system is
the "In-Memory File System" aka IMFS.

The design and implementation was done by the following people:

+ Joel Sherrill (joel@…)
+ Jennifer Averett (jennifer@…)
+ Steve "Mr Mount" Salitasc (salitasc@…)
+ Kerwin Wade (wade@…)

PROBLEMS
========

+ It is VERY likely that merging this will break the UNIX port. This

can/will be fixed.

+ There is likely some reentrancy/mutual exclusion needed.

+ Eventually, there should be a "mini-IMFS" description table to

eliminate links, symlinks, etc to save memory. All you need to
have "classic RTEMS" functionality is technically directories
and device IO. All the rest could be left out to save memory.

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