Skip to content

Commit a4c2062

Browse files
committed
Backported malloc and realloc from avr-libc 1.8.0 (without test code)
See #857
1 parent 01a8b4e commit a4c2062

File tree

4 files changed

+276
-132
lines changed

4 files changed

+276
-132
lines changed

hardware/arduino/cores/arduino/malloc.c renamed to hardware/arduino/cores/arduino/avr-libc/malloc.c

Lines changed: 19 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
Copyright (c) 2010 Gerben van den Broeke
33
All rights reserved.
44
5-
malloc, free, realloc from avr-libc 1.7.0
6-
with minor modifications, by Paul Stoffregen
7-
85
Redistribution and use in source and binary forms, with or without
96
modification, are permitted provided that the following conditions are met:
107
@@ -33,20 +30,14 @@
3330
POSSIBILITY OF SUCH DAMAGE.
3431
*/
3532

33+
34+
/* $Id: malloc.c 2149 2010-06-09 20:45:37Z joerg_wunsch $ */
3635

3736
#include <stdlib.h>
38-
#include <inttypes.h>
39-
#include <string.h>
40-
#include <avr/io.h>
41-
42-
43-
#define __MALLOC_MARGIN__ 120
37+
#include "sectionname.h"
38+
#include "stdlib_private.h"
4439

45-
46-
struct __freelist {
47-
size_t sz;
48-
struct __freelist *nx;
49-
};
40+
#include <avr/io.h>
5041

5142
/*
5243
* Exported interface:
@@ -59,13 +50,16 @@ struct __freelist {
5950
* with the data segment.
6051
*/
6152

53+
/* May be changed by the user only before the first malloc() call. */
54+
55+
size_t __malloc_margin = 32;
56+
char *__malloc_heap_start = &__heap_start;
57+
char *__malloc_heap_end = &__heap_end;
6258

63-
#define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG)
64-
extern char __heap_start;
65-
char *__brkval = &__heap_start; // first location not yet allocated
66-
struct __freelist *__flp; // freelist pointer (head of freelist)
67-
char *__brkval_maximum = 100;
59+
char *__brkval;
60+
struct __freelist *__flp;
6861

62+
ATTRIBUTE_CLIB_SECTION
6963
void *
7064
malloc(size_t len)
7165
{
@@ -160,7 +154,11 @@ malloc(size_t len)
160154
* Since we don't have an operating system, just make sure
161155
* that we don't collide with the stack.
162156
*/
163-
cp = STACK_POINTER() - __MALLOC_MARGIN__;
157+
if (__brkval == 0)
158+
__brkval = __malloc_heap_start;
159+
cp = __malloc_heap_end;
160+
if (cp == 0)
161+
cp = STACK_POINTER() - __malloc_margin;
164162
if (cp <= __brkval)
165163
/*
166164
* Memory exhausted.
@@ -173,7 +171,6 @@ malloc(size_t len)
173171
if (avail >= len && avail >= len + sizeof(size_t)) {
174172
fp1 = (struct __freelist *)__brkval;
175173
__brkval += len + sizeof(size_t);
176-
__brkval_maximum = __brkval;
177174
fp1->sz = len;
178175
return &(fp1->nx);
179176
}
@@ -184,6 +181,7 @@ malloc(size_t len)
184181
}
185182

186183

184+
ATTRIBUTE_CLIB_SECTION
187185
void
188186
free(void *p)
189187
{
@@ -267,114 +265,3 @@ free(void *p)
267265
}
268266
}
269267

270-
271-
272-
void *
273-
realloc(void *ptr, size_t len)
274-
{
275-
struct __freelist *fp1, *fp2, *fp3, *ofp3;
276-
char *cp, *cp1;
277-
void *memp;
278-
size_t s, incr;
279-
280-
/* Trivial case, required by C standard. */
281-
if (ptr == 0)
282-
return malloc(len);
283-
284-
cp1 = (char *)ptr;
285-
cp1 -= sizeof(size_t);
286-
fp1 = (struct __freelist *)cp1;
287-
288-
cp = (char *)ptr + len; /* new next pointer */
289-
if (cp < cp1)
290-
/* Pointer wrapped across top of RAM, fail. */
291-
return 0;
292-
293-
/*
294-
* See whether we are growing or shrinking. When shrinking,
295-
* we split off a chunk for the released portion, and call
296-
* free() on it. Therefore, we can only shrink if the new
297-
* size is at least sizeof(struct __freelist) smaller than the
298-
* previous size.
299-
*/
300-
if (len <= fp1->sz) {
301-
/* The first test catches a possible unsigned int
302-
* rollover condition. */
303-
if (fp1->sz <= sizeof(struct __freelist) ||
304-
len > fp1->sz - sizeof(struct __freelist))
305-
return ptr;
306-
fp2 = (struct __freelist *)cp;
307-
fp2->sz = fp1->sz - len - sizeof(size_t);
308-
fp1->sz = len;
309-
free(&(fp2->nx));
310-
return ptr;
311-
}
312-
313-
/*
314-
* If we get here, we are growing. First, see whether there
315-
* is space in the free list on top of our current chunk.
316-
*/
317-
incr = len - fp1->sz;
318-
cp = (char *)ptr + fp1->sz;
319-
fp2 = (struct __freelist *)cp;
320-
for (s = 0, ofp3 = 0, fp3 = __flp;
321-
fp3;
322-
ofp3 = fp3, fp3 = fp3->nx) {
323-
if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) {
324-
/* found something that fits */
325-
if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) {
326-
/* split off a new freelist entry */
327-
cp = (char *)ptr + len;
328-
fp2 = (struct __freelist *)cp;
329-
fp2->nx = fp3->nx;
330-
fp2->sz = fp3->sz - incr;
331-
fp1->sz = len;
332-
} else {
333-
/* it just fits, so use it entirely */
334-
fp1->sz += fp3->sz + sizeof(size_t);
335-
fp2 = fp3->nx;
336-
}
337-
if (ofp3)
338-
ofp3->nx = fp2;
339-
else
340-
__flp = fp2;
341-
return ptr;
342-
}
343-
/*
344-
* Find the largest chunk on the freelist while
345-
* walking it.
346-
*/
347-
if (fp3->sz > s)
348-
s = fp3->sz;
349-
}
350-
/*
351-
* If we are the topmost chunk in memory, and there was no
352-
* large enough chunk on the freelist that could be re-used
353-
* (by a call to malloc() below), quickly extend the
354-
* allocation area if possible, without need to copy the old
355-
* data.
356-
*/
357-
if (__brkval == (char *)ptr + fp1->sz && len > s) {
358-
cp = (char *)ptr + len;
359-
cp1 = STACK_POINTER() - __MALLOC_MARGIN__;
360-
if (cp < cp1) {
361-
__brkval = cp;
362-
__brkval_maximum = cp;
363-
fp1->sz = len;
364-
return ptr;
365-
}
366-
/* If that failed, we are out of luck. */
367-
return 0;
368-
}
369-
370-
/*
371-
* Call malloc() for a new chunk, then copy over the data, and
372-
* release the old region.
373-
*/
374-
if ((memp = malloc(len)) == 0)
375-
return 0;
376-
memcpy(memp, ptr, fp1->sz);
377-
free(ptr);
378-
return memp;
379-
}
380-
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/* Copyright (c) 2004, 2010 Joerg Wunsch
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
10+
* Redistributions in binary form must reproduce the above copyright
11+
notice, this list of conditions and the following disclaimer in
12+
the documentation and/or other materials provided with the
13+
distribution.
14+
15+
* Neither the name of the copyright holders nor the names of
16+
contributors may be used to endorse or promote products derived
17+
from this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
/* $Id: realloc.c 2127 2010-06-07 14:49:37Z joerg_wunsch $ */
32+
33+
#include <stdlib.h>
34+
#include <string.h>
35+
#include "sectionname.h"
36+
#include "stdlib_private.h"
37+
38+
#include <avr/io.h>
39+
40+
ATTRIBUTE_CLIB_SECTION
41+
void *
42+
realloc(void *ptr, size_t len)
43+
{
44+
struct __freelist *fp1, *fp2, *fp3, *ofp3;
45+
char *cp, *cp1;
46+
void *memp;
47+
size_t s, incr;
48+
49+
/* Trivial case, required by C standard. */
50+
if (ptr == 0)
51+
return malloc(len);
52+
53+
cp1 = (char *)ptr;
54+
cp1 -= sizeof(size_t);
55+
fp1 = (struct __freelist *)cp1;
56+
57+
cp = (char *)ptr + len; /* new next pointer */
58+
if (cp < cp1)
59+
/* Pointer wrapped across top of RAM, fail. */
60+
return 0;
61+
62+
/*
63+
* See whether we are growing or shrinking. When shrinking,
64+
* we split off a chunk for the released portion, and call
65+
* free() on it. Therefore, we can only shrink if the new
66+
* size is at least sizeof(struct __freelist) smaller than the
67+
* previous size.
68+
*/
69+
if (len <= fp1->sz) {
70+
/* The first test catches a possible unsigned int
71+
* rollover condition. */
72+
if (fp1->sz <= sizeof(struct __freelist) ||
73+
len > fp1->sz - sizeof(struct __freelist))
74+
return ptr;
75+
fp2 = (struct __freelist *)cp;
76+
fp2->sz = fp1->sz - len - sizeof(size_t);
77+
fp1->sz = len;
78+
free(&(fp2->nx));
79+
return ptr;
80+
}
81+
82+
/*
83+
* If we get here, we are growing. First, see whether there
84+
* is space in the free list on top of our current chunk.
85+
*/
86+
incr = len - fp1->sz;
87+
cp = (char *)ptr + fp1->sz;
88+
fp2 = (struct __freelist *)cp;
89+
for (s = 0, ofp3 = 0, fp3 = __flp;
90+
fp3;
91+
ofp3 = fp3, fp3 = fp3->nx) {
92+
if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) {
93+
/* found something that fits */
94+
if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) {
95+
/* split off a new freelist entry */
96+
cp = (char *)ptr + len;
97+
fp2 = (struct __freelist *)cp;
98+
fp2->nx = fp3->nx;
99+
fp2->sz = fp3->sz - incr;
100+
fp1->sz = len;
101+
} else {
102+
/* it just fits, so use it entirely */
103+
fp1->sz += fp3->sz + sizeof(size_t);
104+
fp2 = fp3->nx;
105+
}
106+
if (ofp3)
107+
ofp3->nx = fp2;
108+
else
109+
__flp = fp2;
110+
return ptr;
111+
}
112+
/*
113+
* Find the largest chunk on the freelist while
114+
* walking it.
115+
*/
116+
if (fp3->sz > s)
117+
s = fp3->sz;
118+
}
119+
/*
120+
* If we are the topmost chunk in memory, and there was no
121+
* large enough chunk on the freelist that could be re-used
122+
* (by a call to malloc() below), quickly extend the
123+
* allocation area if possible, without need to copy the old
124+
* data.
125+
*/
126+
if (__brkval == (char *)ptr + fp1->sz && len > s) {
127+
cp1 = __malloc_heap_end;
128+
cp = (char *)ptr + len;
129+
if (cp1 == 0)
130+
cp1 = STACK_POINTER() - __malloc_margin;
131+
if (cp < cp1) {
132+
__brkval = cp;
133+
fp1->sz = len;
134+
return ptr;
135+
}
136+
/* If that failed, we are out of luck. */
137+
return 0;
138+
}
139+
140+
/*
141+
* Call malloc() for a new chunk, then copy over the data, and
142+
* release the old region.
143+
*/
144+
if ((memp = malloc(len)) == 0)
145+
return 0;
146+
memcpy(memp, ptr, fp1->sz);
147+
free(ptr);
148+
return memp;
149+
}
150+

0 commit comments

Comments
 (0)