source: rtems/c/src/exec/libcsupport/src/malloc.c @ 4fd61795

4.104.114.84.95
Last change on this file since 4fd61795 was 4fd61795, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 21, 1997 at 4:17:12 PM

Added casts and fixed line break.

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