4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 1988 AT&T
33 * Simplified version of malloc(), calloc() and free(), to be linked with
34 * utilities that use [s]brk() and do not define their own version of the
36 * The algorithm maps /dev/zero to get extra memory space.
37 * Each call to mmap() creates a page. The pages are linked in a list.
38 * Each page is divided in blocks. There is at least one block in a page.
39 * New memory chunks are allocated on a first-fit basis.
40 * Freed blocks are joined in larger blocks. Free pages are unmapped.
44 #include <sys/types.h>
46 #include <sys/debug.h>
52 size_t size
; /* Space available for user */
53 struct page
*page
; /* Backwards reference to page */
60 size_t size
; /* Total page size (incl. header) */
62 struct block block
[1];
68 #define HDR_BLOCK (sizeof (struct block) - sizeof (void *))
69 #define HDR_PAGE (sizeof (struct page) - sizeof (void *))
71 static struct page
*memstart
;
75 * When built for debugging, scribble a pattern over newly allocated and
82 const ulong_t patterns
[] = {
83 (ulong_t
)0xbaddcafebaddcafeULL
, (ulong_t
)0xdeadbeefdeadbeefULL
87 scribble(ulong_t
*membgn
, int pattern
, size_t size
)
89 size_t memsize
= size
/ sizeof (ulong_t
);
92 if (pattern
== FREMEM
)
93 ASSERT(*membgn
!= patterns
[pattern
]);
94 *membgn
++ = patterns
[pattern
];
108 for (APLIST_TRAVERSE(free_alp
, idx
, page
)) {
111 for (block
= page
->block
; block
; block
= block
->next
) {
112 struct block
*block2
;
114 if (block
->status
== BUSY
)
116 for (block2
= block
->next
; block2
&&
117 block2
->status
== FREE
; block2
= block2
->next
) {
118 block
->next
= block2
->next
;
119 block
->size
+= block2
->size
+ HDR_BLOCK
;
124 * If a page becomes free, leave it, and save the unmapping
125 * expense, as we'll probably come back and reclaim the page
126 * for later malloc activity.
128 * Free the defrag index.
130 aplist_delete(free_alp
, &idx
);
135 split(struct block
*block
, size_t size
)
137 if (block
->size
> size
+ sizeof (struct block
)) {
138 struct block
*newblock
;
140 newblock
= (struct block
*)
141 ((char *)block
+ HDR_BLOCK
+ size
);
142 newblock
->next
= block
->next
;
143 block
->next
= newblock
;
144 newblock
->status
= FREE
;
145 newblock
->page
= block
->page
;
146 newblock
->size
= block
->size
- size
- HDR_BLOCK
;
154 * Replace both malloc() and lmalloc() (libc's private memory allocator).
155 * They are both private here.
157 #pragma weak lmalloc = malloc
164 size
= S_DROUND(size
);
167 * Try to locate necessary space
169 for (page
= memstart
; page
; page
= page
->next
) {
170 for (block
= page
->block
; block
; block
= block
->next
) {
171 if ((block
->status
== FREE
) && (block
->size
>= size
))
177 * Need to allocate a new page
180 size_t totsize
= size
+ HDR_PAGE
;
181 size_t totpage
= S_ROUND(totsize
, syspagsz
);
183 if ((page
= dz_map(0, 0, totpage
,
184 PROT_READ
| PROT_WRITE
| PROT_EXEC
,
185 MAP_PRIVATE
)) == MAP_FAILED
)
188 page
->next
= memstart
;
190 page
->size
= totpage
;
193 block
->status
= FREE
;
194 block
->size
= totpage
- HDR_PAGE
;
200 scribble((ulong_t
*)&block
->memstart
, NEWMEM
, block
->size
);
202 block
->status
= BUSY
;
203 return (&block
->memstart
);
207 calloc(size_t num
, size_t size
)
212 if (num
== 0 || size
== 0) {
217 /* check for overflow */
218 if ((total
/ num
) != size
) {
224 if ((mp
= malloc(total
)) == NULL
)
226 (void) memset(mp
, 0, total
);
231 realloc(void *ptr
, size_t size
)
238 return (malloc(size
));
241 block
= (struct block
*)((char *)ptr
- HDR_BLOCK
);
242 size
= S_DROUND(size
);
246 * Join block with next one if it is free
248 if (block
->next
&& block
->next
->status
== FREE
) {
249 block
->size
+= block
->next
->size
+ HDR_BLOCK
;
250 block
->next
= block
->next
->next
;
253 if (size
<= block
->size
) {
256 if (block
->size
> osize
)
257 scribble((ulong_t
*)((char *)ptr
+ osize
), NEWMEM
,
258 (block
->size
- osize
));
263 if ((newptr
= malloc(size
)) == NULL
)
265 (void) memcpy(newptr
, ptr
, osize
);
266 block
->status
= FREE
;
269 * Add the free block to the free APlist for later defragmentation.
270 * However, this addition can only be achieved if there is room on the
271 * free APlist. The APlist can't be allowed to grow, as the growth
272 * requires a realloc(), which would recurse back here, resulting in an
273 * infinite loop. If the free APlist is full, defrag() now. This
274 * defragmentation might not be able to collapse any free space, but
275 * the free APlist will be cleared as part of the processing, ensuring
276 * room for the addition.
278 if (free_alp
&& (aplist_nitems(free_alp
) >= aplist_arritems(free_alp
)))
280 (void) aplist_test(&free_alp
, block
->page
, AL_CNT_FREELIST
);
285 * Replace both free() and lfree() (libc's private memory allocator).
286 * They are both private here.
297 block
= (struct block
*)((char *)ptr
- HDR_BLOCK
);
298 block
->status
= FREE
;
300 scribble((ulong_t
*)&block
->memstart
, FREMEM
, block
->size
);
302 (void) aplist_test(&free_alp
, block
->page
, AL_CNT_FREELIST
);
307 lfree(void *ptr
, size_t size
)
313 * We can use any memory after ld.so.1's .bss up until the next page boundary
314 * as allocatable memory.
317 addfree(void *ptr
, size_t bytes
)
322 if (bytes
<= sizeof (struct page
))
325 page
->next
= memstart
;
330 block
->status
= FREE
;
331 block
->size
= bytes
- HDR_PAGE
;