source: rtems/c/src/lib/libc/malloc.c @ 5a36154a

4.104.114.84.95
Last change on this file since 5a36154a was 1f94ed6b, checked in by Joel Sherrill <joel.sherrill@…>, on 04/22/96 at 16:50:17

Updates from Tony Bennett.

  • Property mode set to 100644
File size: 7.8 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#include <unistd.h>    /* sbrk(2) */
29
30rtems_id RTEMS_Malloc_Heap;
31size_t RTEMS_Malloc_Sbrk_amount;
32
33#ifdef RTEMS_DEBUG
34#define MALLOC_STATS
35#define MALLOC_DIRTY
36#endif
37
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
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;
64  rtems_unsigned32    old_address;
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;
74  RTEMS_Malloc_Sbrk_amount = sbrk_amount;
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)) {
85      old_address = u32_address;
86      u32_address = (u32_address + CPU_ALIGNMENT) & ~(CPU_ALIGNMENT-1);
87
88       /*
89        * adjust the length by whatever we aligned by
90        */
91
92      length -= u32_address - old_address;
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,
108    CPU_ALIGNMENT,
109    RTEMS_DEFAULT_ATTRIBUTES,
110    &RTEMS_Malloc_Heap
111  );
112  if ( status != RTEMS_SUCCESSFUL )
113    rtems_fatal_error_occurred( status );
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);
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
133  MSBUMP(malloc_calls, 1);
134
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    }
179   
180    MSBUMP(space_available, the_size);
181
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
195#ifdef MALLOC_STATS
196  if (return_this)
197  {
198      unsigned32 actual_size;
199      unsigned32 current_depth;
200      status = rtems_region_get_segment_size(RTEMS_Malloc_Heap, return_this, &actual_size);
201      MSBUMP(lifetime_allocated, actual_size);
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
207
208#ifdef MALLOC_DIRTY
209  (void) memset(return_this, 0xCF, size);
210#endif
211
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
223  MSBUMP(calloc_calls, 1);
224
225  length = nelem * elsize;
226  cptr = malloc( length );
227  if ( cptr )
228    memset( cptr, '\0', length );
229
230  MSBUMP(malloc_calls, -1);   /* subtract off the malloc */
231
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
244  MSBUMP(realloc_calls, 1);
245
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 );
255  if ( !new_area ) {
256    free( ptr );
257    return (void *) 0;
258  }
259
260  status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &old_size );
261  if ( status != RTEMS_SUCCESSFUL ) {
262    errno = EINVAL;
263    return (void *) 0;
264  }
265
266  memcpy( new_area, ptr, (size < old_size) ? size : old_size );
267  free( ptr );
268
269  return new_area;
270
271}
272
273void free(
274  void *ptr
275)
276{
277  rtems_status_code status;
278
279  MSBUMP(free_calls, 1);
280
281  if ( !ptr )
282    return;
283
284#ifdef MALLOC_STATS
285  {
286      unsigned32        size;
287      status = rtems_region_get_segment_size( RTEMS_Malloc_Heap, ptr, &size );
288      if ( status == RTEMS_SUCCESSFUL ) {
289          MSBUMP(lifetime_freed, size);
290      }
291  }
292#endif
293 
294  status = rtems_region_return_segment( RTEMS_Malloc_Heap, ptr );
295  if ( status != RTEMS_SUCCESSFUL ) {
296    errno = EINVAL;
297    assert( 0 );
298  }
299}
300
301#ifdef MALLOC_STATS
302/*
303 * Dump the malloc statistics
304 * May be called via atexit()  (installable by our bsp) or
305 * at any time by user
306 */
307
308void malloc_dump(void)
309{
310    unsigned32 allocated = malloc_stats.lifetime_allocated - malloc_stats.lifetime_freed;
311
312    printf("Malloc stats\n");
313    printf("  avail:%uk  allocated:%uk (%d%%) max:%uk (%d%%) lifetime:%Luk freed:%Luk\n",
314           (unsigned int) malloc_stats.space_available / 1024,
315           (unsigned int) allocated / 1024,
316           /* avoid float! */
317           (allocated * 100) / malloc_stats.space_available,
318           (unsigned int) malloc_stats.max_depth / 1024,
319           (malloc_stats.max_depth * 100) / malloc_stats.space_available,
320           (unsigned long long) malloc_stats.lifetime_allocated / 1024,
321           (unsigned long long) malloc_stats.lifetime_freed / 1024);
322    printf("  Call counts:   malloc:%d   free:%d   realloc:%d   calloc:%d\n",
323           malloc_stats.malloc_calls,
324           malloc_stats.free_calls,
325           malloc_stats.realloc_calls,
326           malloc_stats.calloc_calls);
327}       
328#endif
329
330/*
331 *  "Reentrant" versions of the above routines implemented above.
332 */
333
334#ifdef RTEMS_NEWLIB
335void *malloc_r(
336  struct _reent *ignored,
337  size_t  size
338)
339{
340  return malloc( size );
341}
342
343void *calloc_r(
344  size_t nelem,
345  size_t elsize
346)
347{
348  return calloc( nelem, elsize );
349}
350
351void *realloc_r(
352  void *ptr,
353  size_t size
354)
355{
356  return realloc_r( ptr, size );
357}
358
359void free_r(
360  void *ptr
361)
362{
363  free( ptr );
364}
365#endif
366
Note: See TracBrowser for help on using the repository browser.