source: rtems/c/src/exec/libcsupport/src/malloc.c @ 8b2ecf85

4.104.114.84.95
Last change on this file since 8b2ecf85 was 8b2ecf85, checked in by Joel Sherrill <joel.sherrill@…>, on 05/23/96 at 15:37:38

updates from Tony Bennett

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[ac7d5ef0]1/*
2 *  RTEMS Malloc Family Implementation
3 *
4 *
5 *  COPYRIGHT (c) 1989, 1990, 1991, 1992, 1993, 1994.
6 *  On-Line Applications Research Corporation (OAR).
7 *  All rights assigned to U.S. Government, 1994.
8 *
9 *  This material may be reproduced by or for the U.S. Government pursuant
10 *  to the copyright license under the clause at DFARS 252.227-7013.  This
11 *  notice must appear in all copies of this file and its derivatives.
12 *
13 *  $Id$
14 */
15
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>
[1f94ed6b]28#include <unistd.h>    /* sbrk(2) */
[ac7d5ef0]29
[11290355]30rtems_id RTEMS_Malloc_Heap;
31size_t RTEMS_Malloc_Sbrk_amount;
[ac7d5ef0]32
[11290355]33#ifdef RTEMS_DEBUG
34#define MALLOC_STATS
[1f94ed6b]35#define MALLOC_DIRTY
[ac7d5ef0]36#endif
37
[11290355]38#ifdef MALLOC_STATS
39#define MSBUMP(f,n)    malloc_stats.f += (n)
40
41struct {
42    unsigned32  space_available;             /* current size of malloc area */
43    unsigned32  malloc_calls;                /* # calls to malloc */
44    unsigned32  free_calls;
45    unsigned32  realloc_calls;
46    unsigned32  calloc_calls;
47    unsigned32  max_depth;                   /* most ever malloc'd at 1 time */
48    unsigned64  lifetime_allocated;
49    unsigned64  lifetime_freed;
50} malloc_stats;
51
52#else                   /* No malloc_stats */
53#define MSBUMP(f,n)
54#endif
[ac7d5ef0]55
56void RTEMS_Malloc_Initialize(
57  void   *start,
58  size_t  length,
59  size_t  sbrk_amount
60)
61{
62  rtems_status_code   status;
63  void               *starting_address;
[4cc631db]64  rtems_unsigned32    old_address;
[ac7d5ef0]65  rtems_unsigned32    u32_address;
66
67  /*
68   * If the starting address is 0 then we are to attempt to
69   * get length worth of memory using sbrk. Make sure we
70   * align the address that we get back.
71   */
72
73  starting_address = start;
[e8512eb]74  RTEMS_Malloc_Sbrk_amount = sbrk_amount;
[ac7d5ef0]75
76  if (!starting_address) {
77    u32_address = (unsigned int)sbrk(length);
78
79    if (u32_address == -1) {
80      rtems_fatal_error_occurred( RTEMS_NO_MEMORY );
81      /* DOES NOT RETURN!!! */
82    }
83
84    if (u32_address & (CPU_ALIGNMENT-1)) {
[4cc631db]85      old_address = u32_address;
[ac7d5ef0]86      u32_address = (u32_address + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1);
[4cc631db]87
[11290355]88       /*
89        * adjust the length by whatever we aligned by
90        */
[4cc631db]91
92      length -= u32_address - old_address;
[ac7d5ef0]93    }
94
95    starting_address = (void *)u32_address;
96  }
97
98  /*
99   *  Unfortunately we cannot use assert if this fails because if this
100   *  has failed we do not have a heap and if we do not have a heap
101   *  STDIO cannot work because there will be no buffers.
102   */
103
104  status = rtems_region_create(
105    rtems_build_name( 'H', 'E', 'A', 'P' ),
106    starting_address,
107    length,
[11290355]108    CPU_ALIGNMENT,
[ac7d5ef0]109    RTEMS_DEFAULT_ATTRIBUTES,
110    &RTEMS_Malloc_Heap
111  );
112  if ( status != RTEMS_SUCCESSFUL )
113    rtems_fatal_error_occurred( status );
[11290355]114
115#ifdef MALLOC_STATS
116  /* zero all the stats */
117  (void) memset(&malloc_stats, 0, sizeof(malloc_stats));
118#endif
119 
120  MSBUMP(space_available, length);
[ac7d5ef0]121}
122
123void *malloc(
124  size_t  size
125)
126{
127  void              *return_this;
128  void              *starting_address;
129  rtems_unsigned32   the_size;
130  rtems_unsigned32   sbrk_amount;
131  rtems_status_code  status;
132
[11290355]133  MSBUMP(malloc_calls, 1);
134
[ac7d5ef0]135  if ( !size )
136    return (void *) 0;
137
138  /*
139   * Try to give a segment in the current region if there is not
140   * enough space then try to grow the region using rtems_region_extend().
141   * If this fails then return a NULL pointer.
142   */
143
144  status = rtems_region_get_segment(
145    RTEMS_Malloc_Heap,
146    size,
147    RTEMS_NO_WAIT,
148    RTEMS_NO_TIMEOUT,
149    &return_this
150  );
151
152  if ( status != RTEMS_SUCCESSFUL ) {
153    /*
154     *  Round to the "requested sbrk amount" so hopefully we won't have
155     *  to grow again for a while.  This effectively does sbrk() calls
156     *  in "page" amounts.
157     */
158
159    sbrk_amount = RTEMS_Malloc_Sbrk_amount;
160
161    if ( sbrk_amount == 0 )
162      return (void *) 0;
163
164    the_size = ((size + sbrk_amount) / sbrk_amount * sbrk_amount);
165
166    if (((rtems_unsigned32)starting_address = sbrk(the_size)) == -1)
167      return (void *) 0;
168
169    status = rtems_region_extend(
170      RTEMS_Malloc_Heap,
171      starting_address,
172      the_size
173    );
174    if ( status != RTEMS_SUCCESSFUL ) {
175      sbrk(-the_size);
176      errno = ENOMEM;
177      return (void *) 0;
178    }
[11290355]179   
180    MSBUMP(space_available, the_size);
181
[ac7d5ef0]182    status = rtems_region_get_segment(
183      RTEMS_Malloc_Heap,
184       size,
185       RTEMS_NO_WAIT,
186       RTEMS_NO_TIMEOUT,
187       &return_this
188    );
189    if ( status != RTEMS_SUCCESSFUL ) {
190      errno = ENOMEM;
191      return (void *) 0;
192    }
193  }
194
[11290355]195#ifdef MALLOC_STATS
196  if (return_this)
197  {
[289ad86]198      unsigned32 actual_size;
[11290355]199      unsigned32 current_depth;
[289ad86]200      status = rtems_region_get_segment_size(RTEMS_Malloc_Heap, return_this, &actual_size);
201      MSBUMP(lifetime_allocated, actual_size);
[11290355]202      current_depth = malloc_stats.lifetime_allocated - malloc_stats.lifetime_freed;
203      if (current_depth > malloc_stats.max_depth)
204          malloc_stats.max_depth = current_depth;
205  }
206#endif
[1f94ed6b]207
208#ifdef MALLOC_DIRTY
209  (void) memset(return_this, 0xCF, size);
210#endif
211
[ac7d5ef0]212  return return_this;
213}
214
215void *calloc(
216  size_t nelem,
217  size_t elsize
218)
219{
220  register char *cptr;
221  int length;
222
[11290355]223  MSBUMP(calloc_calls, 1);
224
[ac7d5ef0]225  length = nelem * elsize;
226  cptr = malloc( length );
227  if ( cptr )
228    memset( cptr, '\0', length );
229
[1f94ed6b]230  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
231
[ac7d5ef0]232  return cptr;
233}
234
235void *realloc(
236  void *ptr,
237  size_t size
238)
239{
240  rtems_unsigned32  old_size;
241  rtems_status_code status;
242  char *new_area;
243
[11290355]244  MSBUMP(realloc_calls, 1);
245
[ac7d5ef0]246  if ( !ptr )
247    return malloc( size );
248
249  if ( !size ) {
250    free( ptr );
251    return (void *) 0;
252  }
253
254  new_area = malloc( size );
[8b2ecf85]255 
256  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
257
[ac7d5ef0]258  if ( !new_area ) {
259    free( ptr );
260    return (void *) 0;
261  }
262
[11290355]263  status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &old_size );
264  if ( status != RTEMS_SUCCESSFUL ) {
265    errno = EINVAL;
266    return (void *) 0;
267  }
268
[ac7d5ef0]269  memcpy( new_area, ptr, (size < old_size) ? size : old_size );
270  free( ptr );
271
272  return new_area;
273
274}
275
276void free(
277  void *ptr
278)
279{
280  rtems_status_code status;
281
[11290355]282  MSBUMP(free_calls, 1);
283
[ac7d5ef0]284  if ( !ptr )
285    return;
286
[11290355]287#ifdef MALLOC_STATS
288  {
289      unsigned32        size;
290      status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &size );
291      if ( status == RTEMS_SUCCESSFUL ) {
292          MSBUMP(lifetime_freed, size);
293      }
294  }
295#endif
296 
[ac7d5ef0]297  status = rtems_region_return_segment( RTEMS_Malloc_Heap, ptr );
298  if ( status != RTEMS_SUCCESSFUL ) {
299    errno = EINVAL;
300    assert( 0 );
301  }
302}
303
[11290355]304#ifdef MALLOC_STATS
305/*
306 * Dump the malloc statistics
307 * May be called via atexit()  (installable by our bsp) or
308 * at any time by user
309 */
310
311void malloc_dump(void)
312{
313    unsigned32 allocated = malloc_stats.lifetime_allocated - malloc_stats.lifetime_freed;
314
315    printf("Malloc stats\n");
316    printf("  avail:%uk  allocated:%uk (%d%%) max:%uk (%d%%) lifetime:%Luk freed:%Luk\n",
317           (unsigned int) malloc_stats.space_available / 1024,
318           (unsigned int) allocated / 1024,
319           /* avoid float! */
320           (allocated * 100) / malloc_stats.space_available,
321           (unsigned int) malloc_stats.max_depth / 1024,
322           (malloc_stats.max_depth * 100) / malloc_stats.space_available,
323           (unsigned long long) malloc_stats.lifetime_allocated / 1024,
324           (unsigned long long) malloc_stats.lifetime_freed / 1024);
325    printf("  Call counts:   malloc:%d   free:%d   realloc:%d   calloc:%d\n",
326           malloc_stats.malloc_calls,
327           malloc_stats.free_calls,
328           malloc_stats.realloc_calls,
329           malloc_stats.calloc_calls);
330}       
331#endif
332
[ac7d5ef0]333/*
334 *  "Reentrant" versions of the above routines implemented above.
335 */
336
337#ifdef RTEMS_NEWLIB
338void *malloc_r(
339  struct _reent *ignored,
340  size_t  size
341)
342{
343  return malloc( size );
344}
345
346void *calloc_r(
347  size_t nelem,
348  size_t elsize
349)
350{
351  return calloc( nelem, elsize );
352}
353
354void *realloc_r(
355  void *ptr,
356  size_t size
357)
358{
359  return realloc_r( ptr, size );
360}
361
362void free_r(
363  void *ptr
364)
365{
366  free( ptr );
367}
368#endif
369
Note: See TracBrowser for help on using the repository browser.