source: rtems/cpukit/libcsupport/src/malloc.c @ 421dfef6

4.104.114.84.95
Last change on this file since 421dfef6 was 421dfef6, checked in by Joel Sherrill <joel.sherrill@…>, on 01/30/98 at 20:59:22

Corrected Linux port for glibc2

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