source: rtems/c/src/exec/libcsupport/src/malloc.c @ 289ad86

4.104.114.84.95
Last change on this file since 289ad86 was 289ad86, checked in by Joel Sherrill <joel.sherrill@…>, on 12/05/95 at 15:29:53

bug fix in statistics from Tony Bennett (tbennett@…)

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