source: rtems/c/src/lib/libc/malloc.c @ 388be68

4.104.114.84.9
Last change on this file since 388be68 was 388be68, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 1, 1998 at 9:44:31 PM

Patch from Ian Lance Taylor <ian@…>:

The reentrant versions of the malloc functions in

c/src/lib/libc/malloc.c

do not match the definitions in newlib. These will be used if you use
newlib routines such as fdopen. I believe this patch to malloc.c is
needed to provide the correct versions.

  • 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(RTEMS_Malloc_Heap, return_this, &actual_size);
224      MSBUMP(lifetime_allocated, actual_size);
225      current_depth = rtems_malloc_stats.lifetime_allocated - 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 - rtems_malloc_stats.lifetime_freed;
339
340    printf("Malloc stats\n");
341    printf("  avail:%uk  allocated:%uk (%d%%) max:%uk (%d%%) lifetime:%Luk freed:%Luk\n",
342           (unsigned int) rtems_malloc_stats.space_available / 1024,
343           (unsigned int) allocated / 1024,
344           /* avoid float! */
345           (allocated * 100) / rtems_malloc_stats.space_available,
346           (unsigned int) rtems_malloc_stats.max_depth / 1024,
347           (rtems_malloc_stats.max_depth * 100) / rtems_malloc_stats.space_available,
348           (unsigned64) rtems_malloc_stats.lifetime_allocated / 1024,
349           (unsigned64) rtems_malloc_stats.lifetime_freed / 1024);
350    printf("  Call counts:   malloc:%d   free:%d   realloc:%d   calloc:%d\n",
351           rtems_malloc_stats.malloc_calls,
352           rtems_malloc_stats.free_calls,
353           rtems_malloc_stats.realloc_calls,
354           rtems_malloc_stats.calloc_calls);
355}
356
357
358void malloc_walk(size_t source, size_t printf_enabled)
359{
360   register Region_Control *the_region;
361   Objects_Locations        location;
362 
363   the_region = _Region_Get( RTEMS_Malloc_Heap, &location );
364   if ( location == OBJECTS_LOCAL )
365   {
366      _Heap_Walk( &the_region->Memory, source, printf_enabled );
367      _Thread_Enable_dispatch();
368   }
369}
370
371#else
372
373void malloc_dump(void)
374{
375   return;
376}
377 
378void malloc_walk(size_t source, size_t printf_enabled)
379{
380   return;
381}
382
383#endif
384
385/*
386 *  "Reentrant" versions of the above routines implemented above.
387 */
388
389#ifdef RTEMS_NEWLIB
390void *_malloc_r(
391  struct _reent *ignored,
392  size_t  size
393)
394{
395  return malloc( size );
396}
397
398void *_calloc_r(
399  struct _reent *ignored,
400  size_t nelem,
401  size_t elsize
402)
403{
404  return calloc( nelem, elsize );
405}
406
407void *_realloc_r(
408  struct _reent *ignored,
409  void *ptr,
410  size_t size
411)
412{
413  return realloc( ptr, size );
414}
415
416void _free_r(
417  struct _reent *ignored,
418  void *ptr
419)
420{
421  free( ptr );
422}
423#endif
424
Note: See TracBrowser for help on using the repository browser.