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 #pragma weak _sbrk = sbrk
28 #pragma weak _brk = brk
33 #include <sys/isa_defs.h>
34 #include <sys/types.h>
35 #include <sys/sysmacros.h>
42 mutex_t __sbrk_lock
= DEFAULTMUTEX
;
44 extern intptr_t _brk_unlocked(void *);
45 void *_sbrk_unlocked(intptr_t);
48 * The break must always be at least 8-byte aligned
50 #if (_MAX_ALIGNMENT < 8)
53 #define ALIGNSZ _MAX_ALIGNMENT
56 #define BRKALIGN(x) (caddr_t)P2ROUNDUP((uintptr_t)(x), ALIGNSZ)
63 if (!primary_link_map
) {
67 lmutex_lock(&__sbrk_lock
);
68 result
= _sbrk_unlocked(addend
);
69 lmutex_unlock(&__sbrk_lock
);
75 * _sbrk_unlocked() aligns the old break, adds the addend, aligns
76 * the new break, and calls _brk_unlocked() to set the new break.
77 * We must align the old break because _nd may begin life misaligned.
78 * The addend can be either positive or negative, so there are two
79 * overflow/underflow edge conditions to reject:
81 * - the addend is negative and brk + addend < 0.
82 * - the addend is positive and brk + addend > ULONG_MAX
85 _sbrk_unlocked(intptr_t addend
)
91 _nd
= (void *)_brk_unlocked(0);
94 old_brk
= BRKALIGN(_nd
);
95 new_brk
= BRKALIGN(old_brk
+ addend
);
97 if ((addend
> 0 && new_brk
< old_brk
) ||
98 (addend
< 0 && new_brk
> old_brk
)) {
102 if (_brk_unlocked(new_brk
) != 0)
109 * _sbrk_grow_aligned() aligns the old break to a low_align boundry,
110 * adds min_size, aligns to a high_align boundry, and calls _brk_unlocked()
111 * to set the new break. The low_aligned-aligned value is returned, and
112 * the actual space allocated is returned through actual_size.
114 * Unlike sbrk(2), _sbrk_grow_aligned takes an unsigned size, and does
115 * not allow shrinking the heap.
118 _sbrk_grow_aligned(size_t min_size
, size_t low_align
, size_t high_align
,
127 if (!primary_link_map
) {
131 if ((low_align
& (low_align
- 1)) != 0 ||
132 (high_align
& (high_align
- 1)) != 0) {
136 low_align
= MAX(low_align
, ALIGNSZ
);
137 high_align
= MAX(high_align
, ALIGNSZ
);
139 lmutex_lock(&__sbrk_lock
);
142 _nd
= (void *)_brk_unlocked(0);
144 old_brk
= (uintptr_t)BRKALIGN(_nd
);
145 ret_brk
= P2ROUNDUP(old_brk
, low_align
);
146 high_brk
= ret_brk
+ min_size
;
147 new_brk
= P2ROUNDUP(high_brk
, high_align
);
152 if (ret_brk
< old_brk
|| high_brk
< ret_brk
|| new_brk
< high_brk
) {
153 lmutex_unlock(&__sbrk_lock
);
158 if ((brk_result
= _brk_unlocked((void *)new_brk
)) == 0)
159 _nd
= (void *)new_brk
;
160 lmutex_unlock(&__sbrk_lock
);
165 if (actual_size
!= NULL
)
166 *actual_size
= (new_brk
- ret_brk
);
167 return ((void *)ret_brk
);
176 * brk(2) will return the current brk if given an argument of 0, so we
177 * need to fail it here
184 if (!primary_link_map
) {
189 * Need to align this here; _brk_unlocked won't do it for us.
191 new_brk
= BRKALIGN(new_brk
);
193 lmutex_lock(&__sbrk_lock
);
194 if ((result
= _brk_unlocked(new_brk
)) == 0)
196 lmutex_unlock(&__sbrk_lock
);