aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_alloc_util.c
diff options
context:
space:
mode:
authorSverker Eriksson <sverker@erlang.org>2012-11-29 19:25:07 +0100
committerBjörn-Egil Dahlberg <egil@erlang.org>2012-12-14 15:12:58 +0100
commitb27bb5275d58b0abeadc4664ed27febe625f8ff0 (patch)
treea8cd69367c64bc82143a00197ac07880fe8dce7f /erts/emulator/beam/erl_alloc_util.c
parent971d054018d94dd89c2323e237f9c6c3afa91e3b (diff)
downloadotp-b27bb5275d58b0abeadc4664ed27febe625f8ff0.tar.gz
otp-b27bb5275d58b0abeadc4664ed27febe625f8ff0.tar.bz2
otp-b27bb5275d58b0abeadc4664ed27febe625f8ff0.zip
erts: Fix bug when allocating size near sbc_threshold
A block larger than sbc_threshold can be allocated in MBC if the subsequent "residue block" is smaller than min_block_size. Solved by lowering sbc_threshold to ("hard limit" - min_block_size).
Diffstat (limited to 'erts/emulator/beam/erl_alloc_util.c')
-rw-r--r--erts/emulator/beam/erl_alloc_util.c24
1 files changed, 18 insertions, 6 deletions
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index e6aa93b9d8..f4e6f0bba0 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -1404,6 +1404,7 @@ mbc_alloc_finalize(Allctr_t *allctr,
ASSERT(FBLK_TO_MBC(nxt_blk) == crr);
}
else {
+ ASSERT(org_blk_sz <= MBC_ABLK_SZ_MASK);
blk_sz = org_blk_sz;
if (flags & LAST_BLK_HDR_FLG) {
if (valid_blk_info)
@@ -4163,12 +4164,6 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->ramv = init->ramv;
allctr->main_carrier_size = init->mmbcs;
- allctr->sbc_threshold = init->sbct;
-#ifndef ARCH_64
- if (allctr->sbc_threshold > MBC_ABLK_SZ_MASK - ABLK_HDR_SZ) {
- allctr->sbc_threshold = MBC_ABLK_SZ_MASK - ABLK_HDR_SZ + 1;
- }
-#endif
#if HAVE_ERTS_MSEG
allctr->mseg_opt.abs_shrink_th = init->asbcst;
@@ -4210,6 +4205,23 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
}
#endif
+ allctr->sbc_threshold = init->sbct;
+#ifndef ARCH_64
+ if (allctr->sbc_threshold > 0) {
+ Uint max_mbc_block_sz = UNIT_CEILING(allctr->sbc_threshold - 1 + ABLK_HDR_SZ);
+ if (max_mbc_block_sz + UNIT_FLOOR(allctr->min_block_size - 1) > MBC_ABLK_SZ_MASK
+ || max_mbc_block_sz < allctr->sbc_threshold) { /* wrap around */
+ /*
+ * By limiting sbc_threshold to (hard limit - min_block_size)
+ * we avoid having to split off free "residue blocks"
+ * smaller than min_block_size.
+ */
+ max_mbc_block_sz = MBC_ABLK_SZ_MASK - UNIT_FLOOR(allctr->min_block_size - 1);
+ allctr->sbc_threshold = max_mbc_block_sz - ABLK_HDR_SZ + 1;
+ }
+ }
+#endif
+
allctr->sbmbc_threshold = init->sbmbct;