1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
/*
This is a version (aka dlmalloc) of malloc/free/realloc written by
Doug Lea and released to the public domain. Use, modify, and
redistribute this code without permission or acknowledgement in any
way you wish. Send questions, comments, complaints, performance
data, etc to dl@cs.oswego.edu
VERSION 2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
Note: There may be an updated version of this malloc obtainable at
ftp://gee.cs.oswego.edu/pub/misc/malloc.c
Check before installing!
Hacked up for uClibc by Erik Andersen <andersen@codepoet.org>
*/
#include "malloc.h"
libc_hidden_proto(mremap)
libc_hidden_proto(memcpy)
/* ------------------------------ realloc ------------------------------ */
void* realloc(void* oldmem, size_t bytes)
{
mstate av;
size_t nb; /* padded request size */
mchunkptr oldp; /* chunk corresponding to oldmem */
size_t oldsize; /* its size */
mchunkptr newp; /* chunk to return */
size_t newsize; /* its size */
void* newmem; /* corresponding user mem */
mchunkptr next; /* next contiguous chunk after oldp */
mchunkptr remainder; /* extra space at end of newp */
unsigned long remainder_size; /* its size */
mchunkptr bck; /* misc temp for linking */
mchunkptr fwd; /* misc temp for linking */
unsigned long copysize; /* bytes to copy */
unsigned int ncopies; /* size_t words to copy */
size_t* s; /* copy source */
size_t* d; /* copy destination */
/* Check for special cases. */
if (! oldmem)
return malloc(bytes);
if (! bytes) {
free (oldmem);
return malloc(bytes);
}
LOCK;
av = get_malloc_state();
checked_request2size(bytes, nb);
oldp = mem2chunk(oldmem);
oldsize = chunksize(oldp);
check_inuse_chunk(oldp);
if (!chunk_is_mmapped(oldp)) {
if ((unsigned long)(oldsize) >= (unsigned long)(nb)) {
/* already big enough; split below */
newp = oldp;
newsize = oldsize;
}
else {
next = chunk_at_offset(oldp, oldsize);
/* Try to expand forward into top */
if (next == av->top &&
(unsigned long)(newsize = oldsize + chunksize(next)) >=
(unsigned long)(nb + MINSIZE)) {
set_head_size(oldp, nb);
av->top = chunk_at_offset(oldp, nb);
set_head(av->top, (newsize - nb) | PREV_INUSE);
UNLOCK;
return chunk2mem(oldp);
}
/* Try to expand forward into next chunk; split off remainder below */
else if (next != av->top &&
!inuse(next) &&
(unsigned long)(newsize = oldsize + chunksize(next)) >=
(unsigned long)(nb)) {
newp = oldp;
unlink(next, bck, fwd);
}
/* allocate, copy, free */
else {
newmem = malloc(nb - MALLOC_ALIGN_MASK);
if (newmem == 0) {
UNLOCK;
return 0; /* propagate failure */
}
newp = mem2chunk(newmem);
newsize = chunksize(newp);
/*
Avoid copy if newp is next chunk after oldp.
*/
if (newp == next) {
newsize += oldsize;
newp = oldp;
}
else {
/*
Unroll copy of <= 36 bytes (72 if 8byte sizes)
We know that contents have an odd number of
size_t-sized words; minimally 3.
*/
copysize = oldsize - (sizeof(size_t));
s = (size_t*)(oldmem);
d = (size_t*)(newmem);
ncopies = copysize / sizeof(size_t);
assert(ncopies >= 3);
if (ncopies > 9)
memcpy(d, s, copysize);
else {
*(d+0) = *(s+0);
*(d+1) = *(s+1);
*(d+2) = *(s+2);
if (ncopies > 4) {
*(d+3) = *(s+3);
*(d+4) = *(s+4);
if (ncopies > 6) {
*(d+5) = *(s+5);
*(d+6) = *(s+6);
if (ncopies > 8) {
*(d+7) = *(s+7);
*(d+8) = *(s+8);
}
}
}
}
free(oldmem);
check_inuse_chunk(newp);
UNLOCK;
return chunk2mem(newp);
}
}
}
/* If possible, free extra space in old or extended chunk */
assert((unsigned long)(newsize) >= (unsigned long)(nb));
remainder_size = newsize - nb;
if (remainder_size < MINSIZE) { /* not enough extra to split off */
set_head_size(newp, newsize);
set_inuse_bit_at_offset(newp, newsize);
}
else { /* split remainder */
remainder = chunk_at_offset(newp, nb);
set_head_size(newp, nb);
set_head(remainder, remainder_size | PREV_INUSE);
/* Mark remainder as inuse so free() won't complain */
set_inuse_bit_at_offset(remainder, remainder_size);
free(chunk2mem(remainder));
}
check_inuse_chunk(newp);
UNLOCK;
return chunk2mem(newp);
}
/*
Handle mmap cases
*/
else {
size_t offset = oldp->prev_size;
size_t pagemask = av->pagesize - 1;
char *cp;
unsigned long sum;
/* Note the extra (sizeof(size_t)) overhead */
newsize = (nb + offset + (sizeof(size_t)) + pagemask) & ~pagemask;
/* don't need to remap if still within same page */
if (oldsize == newsize - offset) {
UNLOCK;
return oldmem;
}
cp = (char*)mremap((char*)oldp - offset, oldsize + offset, newsize, 1);
if (cp != (char*)MORECORE_FAILURE) {
newp = (mchunkptr)(cp + offset);
set_head(newp, (newsize - offset)|IS_MMAPPED);
assert(aligned_OK(chunk2mem(newp)));
assert((newp->prev_size == offset));
/* update statistics */
sum = av->mmapped_mem += newsize - oldsize;
if (sum > (unsigned long)(av->max_mmapped_mem))
av->max_mmapped_mem = sum;
sum += av->sbrked_mem;
if (sum > (unsigned long)(av->max_total_mem))
av->max_total_mem = sum;
UNLOCK;
return chunk2mem(newp);
}
/* Note the extra (sizeof(size_t)) overhead. */
if ((unsigned long)(oldsize) >= (unsigned long)(nb + (sizeof(size_t))))
newmem = oldmem; /* do nothing */
else {
/* Must alloc, copy, free. */
newmem = malloc(nb - MALLOC_ALIGN_MASK);
if (newmem != 0) {
memcpy(newmem, oldmem, oldsize - 2*(sizeof(size_t)));
free(oldmem);
}
}
UNLOCK;
return newmem;
}
}
|