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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
32 #include <sys/types.h>
36 * Simplified version of malloc(), free() and realloc(), to be linked with
37 * utilities that use [s]brk() and do not define their own version of the
40 * The algorithm used to get extra memory space by mmap'ing /dev/zero. This
41 * breaks if the application closes the open descriptor, so now it uses
42 * mmap's MAP_ANON feature.
44 * Each call to mmap() creates a page. The pages are linked in a list.
45 * Each page is divided in blocks. There is at least one block in a page.
46 * New memory chunks are allocated on a first-fit basis.
47 * Freed blocks are joined in larger blocks. Free pages are unmapped.
50 #include <sys/types.h>
60 static mutex_t lock
= DEFAULTMUTEX
;
63 size_t size
; /* Space available for user */
64 struct page
*page
; /* Backwards reference to page */
71 size_t size
; /* Total page size (incl. header) */
73 struct block block
[1];
79 #define HDR_BLOCK (sizeof (struct block) - sizeof (void *))
80 #define HDR_PAGE (sizeof (struct page) - sizeof (void *))
81 #define MINSZ sizeof (double)
88 struct page
*memstart
;
90 static void defrag(struct page
*);
91 static void split(struct block
*, size_t);
92 static void *malloc_unlocked(size_t);
93 static size_t align(size_t, int);
99 (void) mutex_lock(&lock
);
100 retval
= malloc_unlocked(size
);
101 (void) mutex_unlock(&lock
);
107 malloc_unlocked(size_t size
)
113 pagesize
= (int)sysconf(_SC_PAGESIZE
);
115 size
= align(size
, MINSZ
);
118 * Try to locate necessary space
120 for (page
= memstart
; page
; page
= page
->next
) {
121 for (block
= page
->block
; block
; block
= block
->next
) {
122 if (block
->status
== FREE
&& block
->size
>= size
)
129 * Need to allocate a new page
132 size_t totsize
= size
+ HDR_PAGE
;
133 size_t totpage
= align(totsize
, pagesize
);
135 if ((page
= mmap(NULL
, totpage
,
136 PROT_READ
|PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
, -1, 0))
140 page
->next
= memstart
;
142 page
->size
= totpage
;
145 block
->status
= FREE
;
146 block
->size
= totpage
- HDR_PAGE
;
152 block
->status
= BUSY
;
153 return (&block
->memstart
);
157 realloc(void *ptr
, size_t size
)
163 (void) mutex_lock(&lock
);
165 newptr
= malloc_unlocked(size
);
166 (void) mutex_unlock(&lock
);
169 block
= (struct block
*)((char *)ptr
- HDR_BLOCK
);
170 size
= align(size
, MINSZ
);
174 * Join block with next one if it is free
176 if (block
->next
&& block
->next
->status
== FREE
) {
177 block
->size
+= block
->next
->size
+ HDR_BLOCK
;
178 block
->next
= block
->next
->next
;
181 if (size
<= block
->size
) {
183 (void) mutex_unlock(&lock
);
187 newptr
= malloc_unlocked(size
);
188 (void) memcpy(newptr
, ptr
, osize
);
189 block
->status
= FREE
;
191 (void) mutex_unlock(&lock
);
200 (void) mutex_lock(&lock
);
202 (void) mutex_unlock(&lock
);
205 block
= (struct block
*)((char *)ptr
- HDR_BLOCK
);
206 block
->status
= FREE
;
209 (void) mutex_unlock(&lock
);
213 * Align size on an appropriate boundary
216 align(size_t size
, int bound
)
219 return ((size_t)bound
);
221 return (size
+ bound
- 1 - (size
+ bound
- 1) % bound
);
225 split(struct block
*block
, size_t size
)
227 if (block
->size
> size
+ sizeof (struct block
)) {
228 struct block
*newblock
;
229 newblock
= (struct block
*)((char *)block
+ HDR_BLOCK
+ size
);
230 newblock
->next
= block
->next
;
231 block
->next
= newblock
;
232 newblock
->status
= FREE
;
233 newblock
->page
= block
->page
;
234 newblock
->size
= block
->size
- size
- HDR_BLOCK
;
243 defrag(struct page
*page
)
247 for (block
= page
->block
; block
; block
= block
->next
) {
248 struct block
*block2
;
250 if (block
->status
== BUSY
)
252 for (block2
= block
->next
; block2
&& block2
->status
== FREE
;
253 block2
= block2
->next
) {
254 block
->next
= block2
->next
;
255 block
->size
+= block2
->size
+ HDR_BLOCK
;
262 if (page
->block
->size
== page
->size
- HDR_PAGE
) {
263 if (page
== memstart
)
264 memstart
= page
->next
;
267 for (page2
= memstart
; page2
->next
;
268 page2
= page2
->next
) {
269 if (page2
->next
== page
) {
270 page2
->next
= page
->next
;
275 (void) munmap((caddr_t
)page
, page
->size
);
282 (void) mutex_lock(&lock
);
288 (void) mutex_unlock(&lock
);
291 #pragma init(malloc_init)
295 (void) pthread_atfork(malloc_prepare
, malloc_release
, malloc_release
);