aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/alloc_SUITE_data
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/alloc_SUITE_data')
-rw-r--r--erts/emulator/test/alloc_SUITE_data/Makefile.src41
-rw-r--r--erts/emulator/test/alloc_SUITE_data/allocator_test.h131
-rw-r--r--erts/emulator/test/alloc_SUITE_data/basic.c61
-rw-r--r--erts/emulator/test/alloc_SUITE_data/bucket_index.c114
-rw-r--r--erts/emulator/test/alloc_SUITE_data/bucket_mask.c147
-rw-r--r--erts/emulator/test/alloc_SUITE_data/coalesce.c318
-rw-r--r--erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c102
-rw-r--r--erts/emulator/test/alloc_SUITE_data/rbtree.c386
-rw-r--r--erts/emulator/test/alloc_SUITE_data/realloc_copy.c279
-rw-r--r--erts/emulator/test/alloc_SUITE_data/testcase_driver.c260
-rw-r--r--erts/emulator/test/alloc_SUITE_data/testcase_driver.h51
-rw-r--r--erts/emulator/test/alloc_SUITE_data/threads.c447
12 files changed, 2337 insertions, 0 deletions
diff --git a/erts/emulator/test/alloc_SUITE_data/Makefile.src b/erts/emulator/test/alloc_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..035415d73e
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/Makefile.src
@@ -0,0 +1,41 @@
+# ``The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved via the world wide web at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+# AB. All Rights Reserved.''
+#
+# $Id$
+#
+
+TEST_DRVS = basic@dll@ \
+ coalesce@dll@ \
+ threads@dll@ \
+ realloc_copy@dll@ \
+ bucket_index@dll@ \
+ bucket_mask@dll@ \
+ rbtree@dll@ \
+ mseg_clear_cache@dll@
+
+CC = @CC@
+LD = @LD@
+CFLAGS = @SHLIB_CFLAGS@ -I@erl_include@ @DEFS@
+SHLIB_EXTRA_LDLIBS = testcase_driver@obj@
+
+all: $(TEST_DRVS)
+
+@SHLIB_RULES@
+
+testcase_driver@obj@: testcase_driver.c testcase_driver.h
+$(TEST_DRVS): testcase_driver@obj@ allocator_test.h
+
+
+
diff --git a/erts/emulator/test/alloc_SUITE_data/allocator_test.h b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
new file mode 100644
index 0000000000..b869a4079c
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/allocator_test.h
@@ -0,0 +1,131 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#ifndef ALLOCATOR_TEST_H__
+#define ALLOCATOR_TEST_H__
+
+typedef unsigned long Ulong;
+
+#ifndef __WIN32__
+Ulong erts_alc_test(Ulong, Ulong, Ulong, Ulong);
+#endif
+
+#define UNDEF__ ~((Ulong) 0)
+
+#define ALC_TEST0(OP) \
+ erts_alc_test((Ulong) (OP), UNDEF__, UNDEF__, UNDEF__)
+#define ALC_TEST1(OP, A1) \
+ erts_alc_test((Ulong) (OP), (Ulong) (A1), UNDEF__, UNDEF__)
+#define ALC_TEST2(OP, A1, A2) \
+ erts_alc_test((Ulong) (OP), (Ulong) (A1), (Ulong) (A2), UNDEF__)
+#define ALC_TEST3(OP, A1, A2, A3) \
+ erts_alc_test((Ulong) (OP), (Ulong) (A1), (Ulong) (A2), (Ulong) (A3))
+
+typedef Ulong Block_t;
+typedef Ulong Carrier_t;
+typedef Ulong Allctr_t;
+typedef Ulong RBT_t;
+typedef Ulong RBTL_t;
+typedef void* erts_thread;
+typedef void* erts_mutex;
+typedef void* erts_cond;
+
+/* From erl_alloc_util.c */
+
+#define BLK_SZ(B) ((Ulong) ALC_TEST1(0x000, (B)))
+#define UMEM_SZ(B) ((Ulong) ALC_TEST1(0x001, (B)))
+#define IS_PREV_FREE_BLK(B) ((Ulong) ALC_TEST1(0x002, (B)))
+#define IS_FREE_BLK(B) ((Ulong) ALC_TEST1(0x003, (B)))
+#define IS_LAST_BLK(B) ((Ulong) ALC_TEST1(0x004, (B)))
+#define UMEM2BLK(U) ((Block_t *) ALC_TEST1(0x005, (U)))
+#define BLK2UMEM(B) ((void *) ALC_TEST1(0x006, (B)))
+#define IS_SBC(C) ((Ulong) ALC_TEST1(0x007, (C)))
+#define IS_SBC_BLK(B) ((Ulong) ALC_TEST1(0x008, (B)))
+#define IS_MBC(C) ((Ulong) ALC_TEST1(0x009, (C)))
+#define IS_MMAP_C(C) ((Ulong) ALC_TEST1(0x00a, (C)))
+#define C_SZ(C) ((Ulong) ALC_TEST1(0x00b, (C)))
+#define SBC2BLK(A, C) ((Block_t *) ALC_TEST2(0x00c, (A), (C)))
+#define BLK2SBC(A, B) ((Carrier_t *) ALC_TEST2(0x00d, (A), (B)))
+#define MBC2FBLK(A, C) ((Block_t *) ALC_TEST2(0x00e, (A), (C)))
+#define FBLK2MBC(A, B) ((Carrier_t *) ALC_TEST2(0x00f, (A), (B)))
+#define FIRST_MBC(A) ((Carrier_t *) ALC_TEST1(0x010, (A)))
+#define LAST_MBC(A) ((Carrier_t *) ALC_TEST1(0x011, (A)))
+#define FIRST_SBC(A) ((Carrier_t *) ALC_TEST1(0x012, (A)))
+#define LAST_SBC(A) ((Carrier_t *) ALC_TEST1(0x013, (A)))
+#define NEXT_C(C) ((Carrier_t *) ALC_TEST1(0x014, (C)))
+#define PREV_C(C) ((Carrier_t *) ALC_TEST1(0x015, (C)))
+#define ABLK_HDR_SZ ((Ulong) ALC_TEST0(0x016))
+#define MIN_BLK_SZ(A) ((Ulong) ALC_TEST1(0x017, (A)))
+#define NXT_BLK(B) ((Block_t *) ALC_TEST1(0x018, (B)))
+#define PREV_BLK(B) ((Block_t *) ALC_TEST1(0x019, (B)))
+#define IS_FIRST_BLK(B) ((Ulong) ALC_TEST1(0x01a, (B)))
+#define UNIT_SZ ((Ulong) ALC_TEST0(0x01b))
+
+/* From erl_goodfit_alloc.c */
+#define BKT_IX(A, S) ((Ulong) ALC_TEST2(0x100, (A), (S)))
+#define BKT_MIN_SZ(A, I) ((Ulong) ALC_TEST2(0x101, (A), (I)))
+#define NO_OF_BKTS ((Ulong) ALC_TEST0(0x102))
+#define FIND_BKT(A, I) ((int) ALC_TEST2(0x103, (A), (I)))
+
+/* From erl_bestfit_alloc.c */
+#define IS_AOBF(A) ((Ulong) ALC_TEST1(0x200, (A)))
+#define RBT_ROOT(A) ((RBT_t *) ALC_TEST1(0x201, (A)))
+#define RBT_PARENT(T) ((RBT_t *) ALC_TEST1(0x202, (T)))
+#define RBT_LEFT(T) ((RBT_t *) ALC_TEST1(0x203, (T)))
+#define RBT_RIGHT(T) ((RBT_t *) ALC_TEST1(0x204, (T)))
+#define RBT_NEXT(T) ((RBTL_t *) ALC_TEST1(0x205, (T)))
+#define RBT_IS_BLACK(T) ((Ulong) ALC_TEST1(0x206, (T)))
+#define RBT_IS_TREE(T) ((Ulong) ALC_TEST1(0x207, (T)))
+
+/* From erl_mseg.c */
+#define HAVE_MSEG() ((int) ALC_TEST0(0x400))
+#define MSEG_ALLOC(SP) ((void *) ALC_TEST1(0x401, (SP)))
+#define MSEG_DEALLOC(P, S) ((void) ALC_TEST2(0x402, (P), (S)))
+#define MSEG_REALLOC(P, OS, SP) ((void *) ALC_TEST3(0x403, (P), (OS), \
+ (SP)))
+#define MSEG_CLEAR_CACHE() ((void) ALC_TEST0(0x404))
+#define MSEG_NO() ((Ulong) ALC_TEST0(0x405))
+#define MSEG_CACHE_SIZE() ((Ulong) ALC_TEST0(0x406))
+
+/* From erl_alloc.c */
+
+#undef ALLOC
+#undef REALLOC
+#undef FREE
+
+#define ALLOC(A, S) ((void *) ALC_TEST2(0xf00, (A), (S)))
+#define REALLOC(A, P, S) ((void *) ALC_TEST3(0xf01, (A), (P), (S)))
+#define FREE(A, P) ((void) ALC_TEST2(0xf02, (A), (P)))
+#define START_ALC(N, T, A) ((Allctr_t *) ALC_TEST3(0xf03, (N), (T), (A)))
+#define STOP_ALC(A) ((void) ALC_TEST1(0xf04, (A)))
+#define IS_THREADS_ENABLED ((int) ALC_TEST0(0xf05))
+#define IS_ALLOC_THREAD_SAFE(A) ((int) ALC_TEST1(0xf06, (A)))
+#define IS_ALLOC_FORK_SAFE(A) ((int) ALC_TEST1(0xf07, (A)))
+#define THR_MTX_CREATE() ((erts_mutex) ALC_TEST0(0xf08))
+#define THR_MTX_DESTROY(M) ((void) ALC_TEST1(0xf09, (M)))
+#define THR_MTX_LOCK(M) ((void) ALC_TEST1(0xf0a, (M)))
+#define THR_MTX_UNLOCK(M) ((void) ALC_TEST1(0xf0b, (M)))
+#define THR_COND_CREATE() ((erts_cond) ALC_TEST0(0xf0c))
+#define THR_COND_DESTROY(C) ((void) ALC_TEST1(0xf0d, (C)))
+#define THR_COND_BCAST(C) ((void) ALC_TEST1(0xf0e, (C)))
+#define THR_COND_WAIT(C, M) ((void) ALC_TEST2(0xf0f, (C), (M)))
+#define THR_CREATE(F, A) ((erts_thread) ALC_TEST2(0xf10, (F), (A)))
+#define THR_JOIN(T) ((void) ALC_TEST1(0xf11, (T)))
+#define THR_EXIT(R) ((void) ALC_TEST1(0xf12, (R)))
+
+#endif
diff --git a/erts/emulator/test/alloc_SUITE_data/basic.c b/erts/emulator/test/alloc_SUITE_data/basic.c
new file mode 100644
index 0000000000..4a5e888161
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/basic.c
@@ -0,0 +1,61 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+
+char *
+testcase_name(void)
+{
+ return "basic";
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ Carrier_t *c;
+ Block_t *blk;
+ void *p;
+ Allctr_t *a = START_ALC("basic_", 0, NULL);
+ tcs->extra = (void *) a;
+
+ ASSERT(tcs, a);
+
+ p = ALLOC(a, 10);
+ ASSERT(tcs, p);
+ p = REALLOC(a, p, 15);
+ ASSERT(tcs, p);
+ FREE(a, p);
+
+ c = FIRST_MBC(a);
+ ASSERT(tcs, !NEXT_C(c));
+ blk = MBC2FBLK(a, c);
+ ASSERT(tcs, IS_LAST_BLK(blk));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+
+ STOP_ALC((Allctr_t *) a);
+ tcs->extra = NULL;
+
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra)
+ STOP_ALC((Allctr_t *) tcs->extra);
+}
diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_index.c b/erts/emulator/test/alloc_SUITE_data/bucket_index.c
new file mode 100644
index 0000000000..32fd16fc10
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/bucket_index.c
@@ -0,0 +1,114 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+#include <stdio.h>
+
+#define MAX_TEST_SIZE 100000000
+
+char *
+testcase_name(void)
+{
+ return "bucket_index";
+}
+
+void test_it(TestCaseState_t *tcs, unsigned sbct);
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ testcase_printf(tcs, "No of buckets = %lu:\n\n", NO_OF_BKTS);
+
+ test_it(tcs, 1);
+ test_it(tcs, 0);
+ test_it(tcs, 1024);
+ test_it(tcs, 10240);
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra) {
+ STOP_ALC(tcs->extra);
+ tcs->extra = NULL;
+ }
+}
+
+void
+test_it(TestCaseState_t *tcs, unsigned sbct)
+{
+ Ulong max_cont_test_sz;
+ char sbct_buf[21];
+ char *argv[] = {"-tas", "gf", "-tsbct", NULL, NULL};
+ int no_changes;
+ Ulong bi;
+ Ulong min_sz;
+ Ulong prev_bi;
+ Ulong sz;
+ Allctr_t *a;
+
+ no_changes = 0;
+ prev_bi = -1;
+
+ if (sbct) {
+ sprintf(sbct_buf, "%d", sbct);
+ argv[3] = sbct_buf;
+ }
+ else
+ argv[2] = NULL;
+
+ max_cont_test_sz = 2*sbct*1024;
+ if (max_cont_test_sz < 1000000)
+ max_cont_test_sz = 1000000;
+
+ testcase_printf(tcs, "Testing with sbct = %s\n",
+ sbct ? sbct_buf : "default");
+ a = START_ALC("bkt_ix_", 0, argv);
+ tcs->extra = (void *) a;
+ ASSERT(tcs, a);
+
+ sz = MIN_BLK_SZ(a);
+ while(sz < ((((Ulong)1) << 31) - 1)) {
+ bi = BKT_IX(a, sz);
+ if (prev_bi != bi) {
+ ASSERT(tcs, prev_bi + 1 == bi);
+
+ min_sz = BKT_MIN_SZ(a, bi);
+
+ ASSERT(tcs, sz == min_sz);
+
+ testcase_printf(tcs, "sz=%d->ix=%d ", sz, bi);
+ no_changes++;
+ }
+ prev_bi = bi;
+ if (sz < max_cont_test_sz)
+ sz++;
+ else
+ sz += 100000000;
+ }
+ testcase_printf(tcs, "\n\n");
+ ASSERT(tcs, no_changes == NO_OF_BKTS);
+
+ STOP_ALC(a);
+ tcs->extra = NULL;
+
+ testcase_printf(tcs, "Test with sbct=%s succeeded\n",
+ sbct ? sbct_buf : "default");
+}
+
diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c
new file mode 100644
index 0000000000..13af7d861a
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c
@@ -0,0 +1,147 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+#include <stdio.h>
+
+#define SBCT (512*1024)
+
+char *
+testcase_name(void)
+{
+ return "bucket_mask";
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra) {
+ STOP_ALC(tcs->extra);
+ tcs->extra = NULL;
+ }
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ void *tmp;
+ void **fence;
+ void **blk;
+ Ulong sz;
+ Ulong smbcs;
+ int i;
+ int bi;
+ int bi_tests;
+ Ulong sbct = (SBCT/1024)*1024;
+ Ulong min_blk_sz;
+ Ulong ablk_hdr_sz = ABLK_HDR_SZ;
+ char smbcs_buf[30];
+ char sbct_buf[30];
+ int no_bkts = (int) NO_OF_BKTS;
+ char *argv1[] = {"-tasgf", "-tmmbcs0", sbct_buf, NULL};
+ char *argv2[] = {"-tasgf", "-tmmbcs0", sbct_buf, NULL, NULL};
+ Allctr_t *a;
+
+ sprintf(sbct_buf, "-tsbct%lu", sbct/1024);
+
+ a = START_ALC("bkt_mask_1_", 0, argv1);
+ tcs->extra = (void *) a;
+ ASSERT(tcs, a);
+
+ min_blk_sz = MIN_BLK_SZ(a);
+ smbcs = 2*(no_bkts*sizeof(void *) + min_blk_sz) + min_blk_sz;
+ for (i = 0; i < no_bkts; i++) {
+ sz = BKT_MIN_SZ(a, i);
+ if (sz >= sbct)
+ break;
+ smbcs += sz + min_blk_sz;
+ }
+
+ bi_tests = i;
+ testcase_printf(tcs, "Will test %d buckets\n", bi_tests);
+
+ STOP_ALC(a);
+ tcs->extra = NULL;
+
+ smbcs /= 1024;
+ smbcs++;
+
+ testcase_printf(tcs, "smbcs = %lu\n", smbcs);
+ sprintf(smbcs_buf, "-tsmbcs%lu", smbcs);
+ argv2[3] = smbcs_buf;
+
+ a = START_ALC("bkt_mask_2_", 0, argv2);
+ tcs->extra = (void *) a;
+ ASSERT(tcs, a);
+
+ blk = (void **) ALLOC(a, no_bkts*sizeof(void *));
+ fence = (void **) ALLOC(a, no_bkts*sizeof(void *));
+
+ ASSERT(tcs, blk && fence);
+
+ testcase_printf(tcs, "Allocating blocks and fences\n");
+ for (i = 0; i < bi_tests; i++) {
+ sz = BKT_MIN_SZ(a, i);
+ blk[i] = ALLOC(a, sz - ablk_hdr_sz);
+ fence[i] = ALLOC(a, 1);
+ ASSERT(tcs, blk[i] && fence[i]);
+ }
+
+ tmp = (void *) UMEM2BLK(fence[bi_tests - 1]);
+ tmp = (void *) NXT_BLK((Block_t *) tmp);
+ ASSERT(tcs, IS_LAST_BLK(tmp));
+ sz = BLK_SZ((Block_t *) tmp);
+ testcase_printf(tcs, "Allocating leftover size = %lu\n", sz);
+ tmp = ALLOC(a, sz - ablk_hdr_sz);
+ ASSERT(tcs, tmp);
+
+ bi = FIND_BKT(a, 0);
+ ASSERT(tcs, bi < 0);
+
+ for (i = 0; i < bi_tests; i++) {
+ sz = BKT_MIN_SZ(a, i);
+ testcase_printf(tcs, "Testing bucket %d\n", i);
+ FREE(a, blk[i]);
+ bi = FIND_BKT(a, i);
+ ASSERT(tcs, bi == i);
+ blk[i] = ALLOC(a, sz - ablk_hdr_sz);
+ bi = FIND_BKT(a, i);
+ ASSERT(tcs, bi != i);
+ }
+
+ for (i = 0; i < bi_tests; i++) {
+ FREE(a, blk[i]);
+ FREE(a, fence[i]);
+ }
+
+ FREE(a, (void *) blk);
+ FREE(a, (void *) fence);
+
+ bi = FIND_BKT(a, 0);
+ ASSERT(tcs, bi == no_bkts - 1);
+
+ FREE(a, tmp);
+
+ bi = FIND_BKT(a, 0);
+ ASSERT(tcs, bi < 0);
+
+ STOP_ALC(a);
+ tcs->extra = NULL;
+}
+
diff --git a/erts/emulator/test/alloc_SUITE_data/coalesce.c b/erts/emulator/test/alloc_SUITE_data/coalesce.c
new file mode 100644
index 0000000000..c84da97d35
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/coalesce.c
@@ -0,0 +1,318 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+#include <string.h>
+
+#define CEILING(X, U) ((((X)+(U)-1)/(U))*(U))
+
+void
+check_ablk(TestCaseState_t *tcs, Allctr_t *a, void *ptr, Ulong umem_sz)
+{
+ Ulong unit_sz = UNIT_SZ;
+ Block_t *blk = UMEM2BLK(ptr);
+ Block_t *nxt_blk = NXT_BLK(blk);
+ Ulong real_sz = ((Ulong) nxt_blk) - ((Ulong) (blk));
+ ASSERT(tcs, real_sz == BLK_SZ(blk));
+ ASSERT(tcs, !IS_FREE_BLK(blk));
+ ASSERT(tcs, real_sz >= CEILING(ABLK_HDR_SZ + umem_sz, unit_sz));
+ if (real_sz > MIN_BLK_SZ(a)
+ && real_sz > CEILING(ABLK_HDR_SZ+umem_sz, unit_sz)) {
+ ASSERT(tcs,
+ real_sz <= CEILING(MIN_BLK_SZ(a)+ABLK_HDR_SZ+umem_sz,
+ unit_sz));
+ ASSERT(tcs, IS_LAST_BLK(blk) || !IS_FREE_BLK(nxt_blk));
+ }
+}
+
+void
+setup_sequence(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz, int no,
+ void *res[])
+{
+ Carrier_t *c;
+ Block_t *blk;
+ int i;
+
+ testcase_printf(tcs,
+ "Setting up a sequence of %d blocks of size %lu\n",
+ no, bsz);
+ c = FIRST_MBC(a);
+ ASSERT(tcs, !NEXT_C(c));
+ blk = MBC2FBLK(a, c);
+ ASSERT(tcs, IS_LAST_BLK(blk));
+
+ for (i = 0; i < no; i++)
+ res[i] = ALLOC(a, bsz);
+ for (i = 0; i < no; i++)
+ ASSERT(tcs, res[i]);
+
+ testcase_printf(tcs, "Checking that sequence was set up as expected\n");
+
+ for (i = 1; i < no; i++)
+ ASSERT(tcs, NXT_BLK(UMEM2BLK(res[i-1])) == UMEM2BLK(res[i]));
+
+ blk = NXT_BLK(UMEM2BLK(res[no-1]));
+ ASSERT(tcs, IS_LAST_BLK(blk));
+
+ testcase_printf(tcs, "Sequence ok\n");
+
+ /* If we fail in setup_sequence(), it doesn't mean that something is
+ wrong. It is just a faulty assumption in setup_sequence() about
+ how blocks are going to be placed.
+ Fix setup_sequence()... */
+}
+
+static void
+test_free(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz)
+{
+ Block_t *blk;
+ void *p[7];
+
+ testcase_printf(tcs," --- Testing free() with block size %lu ---\n",bsz);
+
+ setup_sequence(tcs, a, bsz, 7, p);
+
+ check_ablk(tcs, a, p[0], bsz);
+ check_ablk(tcs, a, p[1], bsz);
+ check_ablk(tcs, a, p[2], bsz);
+ check_ablk(tcs, a, p[3], bsz);
+ check_ablk(tcs, a, p[4], bsz);
+ check_ablk(tcs, a, p[5], bsz);
+ check_ablk(tcs, a, p[6], bsz);
+
+ /* Coalescing with previous block */
+ FREE(a, p[2]);
+ FREE(a, p[3]);
+
+ blk = NXT_BLK(UMEM2BLK(p[1]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[4]));
+
+ /* Coalescing with next block */
+
+ FREE(a, p[1]);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[4]));
+
+ /* Coalescing with next and previous block */
+
+ FREE(a, p[5]);
+ FREE(a, p[4]);
+
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[6]));
+
+ /* Cleanup */
+
+ FREE(a, p[0]);
+ FREE(a, p[6]);
+
+ testcase_printf(tcs," --- free() with block size %lu succeded ---\n",bsz);
+}
+
+static void
+test_realloc(TestCaseState_t *tcs, Allctr_t *a, Ulong bsz)
+{
+ Block_t *blk;
+ void *ptr;
+ void *p[3];
+ Ulong nbsz;
+
+ testcase_printf(tcs," --- Testing realloc() with block size %lu ---\n",
+ bsz);
+
+ setup_sequence(tcs, a, bsz, 3, p);
+
+ check_ablk(tcs, a, p[0], bsz);
+ check_ablk(tcs, a, p[1], bsz);
+ check_ablk(tcs, a, p[2], bsz);
+
+ /* Grow to the end of the carrier */
+ blk = NXT_BLK(UMEM2BLK(p[2]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, IS_LAST_BLK(blk));
+ nbsz = bsz + BLK_SZ(blk);
+ ptr = REALLOC(a, p[2], nbsz);
+ ASSERT(tcs, p[2] == ptr);
+ check_ablk(tcs, a, p[2], nbsz);
+ blk = UMEM2BLK(p[2]);
+ ASSERT(tcs, IS_LAST_BLK(blk));
+
+ /* Shrink from the end of the carrier */
+ ptr = REALLOC(a, p[2], bsz);
+ ASSERT(tcs, p[2] == ptr);
+ blk = UMEM2BLK(p[2]);
+ ASSERT(tcs, !IS_LAST_BLK(blk));
+ blk = NXT_BLK(blk);
+ ASSERT(tcs, IS_LAST_BLK(blk));
+ check_ablk(tcs, a, p[2], bsz);
+
+ /* Shrink and coalecse with next free */
+
+ FREE(a, p[1]);
+
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+
+ nbsz = bsz/2;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+
+ check_ablk(tcs, a, p[0], nbsz);
+
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2]));
+
+ /* Grow into next free; but leave free block at end */
+
+ nbsz *= 3;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+
+ check_ablk(tcs, a, p[0], nbsz);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2]));
+
+ /* Grow upto next alloced block by allocating just enough so that no
+ free block fits between them */
+ nbsz = BLK_SZ(blk) + UMEM_SZ(UMEM2BLK(p[0]));
+ nbsz -= MIN_BLK_SZ(a) - 1;
+
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+ check_ablk(tcs, a, p[0], nbsz);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, !IS_FREE_BLK(blk));
+ ASSERT(tcs, blk == UMEM2BLK(p[2]));
+
+ /* Grow into unused part at end */
+ nbsz += MIN_BLK_SZ(a) - 1;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+ check_ablk(tcs, a, p[0], nbsz);
+ ASSERT(tcs, !IS_FREE_BLK(blk));
+ ASSERT(tcs, blk == UMEM2BLK(p[2]));
+
+ /* Shrink *almost* as much so that a free block would fit between the
+ allocated blocks, and make sure that we don't get a free block
+ in between */
+ nbsz -= MIN_BLK_SZ(a) - 1;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+ check_ablk(tcs, a, p[0], nbsz);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, !IS_FREE_BLK(blk));
+ ASSERT(tcs, blk == UMEM2BLK(p[2]));
+
+ /* Shrink just as much so that a free block can fit between
+ the alloced blocks */
+ nbsz -= 1;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+ check_ablk(tcs, a, p[0], nbsz);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, blk < UMEM2BLK(p[2]));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2]));
+
+ /* Shrink so little that no free block would fit between allocated
+ blocks, and make sure that we shrink the allocated block and
+ coalesce the extra free part with the next free block. */
+ nbsz -= MIN_BLK_SZ(a) - 1;
+ ptr = REALLOC(a, p[0], nbsz);
+ ASSERT(tcs, p[0] == ptr);
+ check_ablk(tcs, a, p[0], nbsz);
+ blk = NXT_BLK(UMEM2BLK(p[0]));
+ ASSERT(tcs, IS_FREE_BLK(blk));
+ ASSERT(tcs, blk < UMEM2BLK(p[2]));
+ ASSERT(tcs, NXT_BLK(blk) == UMEM2BLK(p[2]));
+
+ /* Cleanup */
+ FREE(a, p[0]);
+ FREE(a, p[2]);
+
+ testcase_printf(tcs, " --- realloc() with block size %lu succeded ---\n",
+ bsz);
+
+}
+
+char *
+testcase_name(void)
+{
+ return "coalesce";
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ char *argv_org[] = {"-tmmbcs1024", "-tsbct2048", "-trmbcmt100", "-tas", NULL, NULL};
+ char *alg[] = {"af", "gf", "bf", "aobf", NULL};
+ int i;
+
+ for (i = 0; alg[i]; i++) {
+ Ulong sz;
+ Allctr_t *a;
+ char *argv[sizeof(argv_org)/sizeof(argv_org[0])];
+ memcpy((void *) argv, (void *) argv_org, sizeof(argv_org));
+
+ argv[4] = alg[i];
+ testcase_printf(tcs, " *** Starting \"%s\" allocator *** \n", alg[i]);
+ a = START_ALC("coalesce_", 0, argv);
+ ASSERT(tcs, a);
+ tcs->extra = (void *) a;
+
+ sz = MIN_BLK_SZ(a) - ABLK_HDR_SZ;
+ test_free(tcs, a, sz);
+ sz += 1;
+ test_free(tcs, a, sz);
+ sz *= 4;
+ test_free(tcs, a, sz);
+ sz += 1;
+ test_free(tcs, a, sz);
+ sz *= 10;
+ test_free(tcs, a, sz);
+
+ sz = MIN_BLK_SZ(a)*4 - ABLK_HDR_SZ;
+ test_realloc(tcs, a, sz);
+ sz += 1;
+ test_realloc(tcs, a, sz);
+ sz *= 4;
+ test_realloc(tcs, a, sz);
+ sz += 1;
+ test_realloc(tcs, a, sz);
+ sz *= 10;
+ test_realloc(tcs, a, sz);
+
+ testcase_printf(tcs, " *** Stopping \"%s\" allocator *** \n", alg[i]);
+ STOP_ALC(a);
+ tcs->extra = NULL;
+ }
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra)
+ STOP_ALC((Allctr_t *) tcs->extra);
+}
diff --git a/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c
new file mode 100644
index 0000000000..0277616bd0
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/mseg_clear_cache.c
@@ -0,0 +1,102 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+
+#define MAX_SEGS 10
+
+typedef struct {
+ void *ptr;
+ Ulong size;
+} seg_t;
+
+char *
+testcase_name(void)
+{
+ return "mseg_clear_cache";
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ int i;
+ Ulong n;
+ seg_t *seg;
+
+ if (!HAVE_MSEG())
+ testcase_skipped(tcs, "No mseg_alloc; nothing to test");
+
+ seg = (seg_t *) testcase_alloc(sizeof(seg_t)*(MAX_SEGS+1));
+
+ ASSERT(tcs, seg);
+
+ for (i = 0; i <= MAX_SEGS; i++)
+ seg[i].ptr = NULL;
+
+ tcs->extra = &seg[0];
+
+ for (i = 0; i < MAX_SEGS; i++) {
+ seg[i].size = 1000;
+ seg[i].ptr = MSEG_ALLOC(&seg[i].size);
+ ASSERT(tcs, seg[i].ptr);
+ ASSERT(tcs, seg[i].size >= 1000);
+ }
+
+ n = MSEG_NO();
+ testcase_printf(tcs, "MSEG_NO() = %lu\n", n);
+
+ ASSERT(tcs, n >= MAX_SEGS);
+
+ testcase_printf(tcs, "Deallocating half of the segments\n");
+ for (i = MAX_SEGS-1; i >= MAX_SEGS/2; i--) {
+ MSEG_DEALLOC(seg[i].ptr, seg[i].size);
+ seg[i].ptr = NULL;
+ }
+
+ n = MSEG_NO();
+ testcase_printf(tcs, "MSEG_NO() = %lu\n", n);
+
+ ASSERT(tcs, n >= MAX_SEGS/2);
+
+ n = MSEG_CACHE_SIZE();
+ testcase_printf(tcs, "MSEG_CACHE_SIZE() = %lu\n", n);
+ ASSERT(tcs, n > 0);
+
+ testcase_printf(tcs, "MSEG_CLEAR_CACHE()\n");
+ MSEG_CLEAR_CACHE();
+
+ n = MSEG_CACHE_SIZE();
+ testcase_printf(tcs, "MSEG_CACHE_SIZE() = %lu\n", n);
+
+ ASSERT(tcs, n == 0);
+
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra) {
+ seg_t *seg = (seg_t *) tcs->extra;
+ int i;
+ for (i = 0; seg[i].ptr; i++)
+ MSEG_DEALLOC(seg[i].ptr, seg[i].size);
+ testcase_free((void *) seg);
+ tcs->extra = NULL;
+ }
+}
diff --git a/erts/emulator/test/alloc_SUITE_data/rbtree.c b/erts/emulator/test/alloc_SUITE_data/rbtree.c
new file mode 100644
index 0000000000..c97e0aac1a
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/rbtree.c
@@ -0,0 +1,386 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+
+#define NO_BLOCKS 100000
+
+#define RIGHT_VISITED (1 << 0)
+#define LEFT_VISITED (1 << 1)
+
+typedef struct {
+ Allctr_t *allocator;
+ void **blk;
+ void **fence;
+} rbtree_test_data;
+
+#if 0
+#define PRINT_TREE
+#endif
+
+#ifdef PRINT_TREE
+
+#define INDENT_STEP 5
+
+#include <stdio.h>
+static void
+print_tree_aux(TestCaseState_t *tcs, RBT_t *x, int indent)
+{
+ if (!x) {
+ char frmt[20];
+ sprintf(frmt, "%%%ds%%s\n", indent);
+ testcase_printf(tcs, frmt, "", "BLACK: nil");
+ }
+ else {
+ print_tree_aux(tcs, RBT_RIGHT(x), indent + INDENT_STEP);
+ {
+ char frmt[40];
+ sprintf(frmt, "%%%ds%%s: sz=%%lu addr=0x%%lx\n", indent);
+ testcase_printf(tcs,
+ frmt,
+ "",
+ RBT_IS_BLACK(x) ? "BLACK" : "RED",
+ BLK_SZ(x),
+ (Ulong) x);
+ }
+ print_tree_aux(tcs, RBT_LEFT(x), indent + INDENT_STEP);
+ }
+}
+
+
+static void
+print_tree(TestCaseState_t *tcs, RBT_t *root, int aobf)
+{
+ char *type = aobf ? "Size-Adress" : "Size";
+ testcase_printf(tcs, " --- %s tree begin ---\r\n", type);
+ print_tree_aux(tcs, root, 0);
+ testcase_printf(tcs, " --- %s tree end ---\r\n", type);
+}
+
+#endif
+
+static RBT_t *
+check_tree(TestCaseState_t *tcs, Allctr_t *alc, Ulong size)
+{
+ int i, max_i, address_order;
+ char stk[128];
+ RBT_t *root, *x, *y, *res;
+ Ulong x_sz, y_sz, is_x_black;
+ long blacks, curr_blacks;
+
+ res = NULL;
+
+ address_order = IS_AOBF(alc);
+ root = RBT_ROOT(alc);
+
+#ifdef PRINT_TREE
+ print_tree(tcs, root, address_order);
+#endif
+
+ max_i = i = -1;
+ curr_blacks = 0;
+ blacks = -1;
+
+ if (!root)
+ goto done;
+
+ stk[++i] = 0;
+
+ ASSERT(tcs, RBT_IS_BLACK(root));
+ ASSERT(tcs, !RBT_PARENT(root));
+ x = root;
+ curr_blacks++;
+
+ while (x) {
+
+ ASSERT(tcs, i <= 128);
+
+ if (!(stk[i] & LEFT_VISITED)) {
+ stk[i] |= LEFT_VISITED;
+ y = RBT_LEFT(x);
+ if (RBT_IS_BLACK(y))
+ curr_blacks++;
+ if (y) {
+ x = y;
+ stk[++i] = 0;
+ continue;
+ }
+ else {
+ if (blacks < 0)
+ blacks = curr_blacks;
+ ASSERT(tcs, blacks == curr_blacks);
+ curr_blacks--;
+ }
+ }
+
+ if (!(stk[i] & RIGHT_VISITED)) {
+ stk[i] |= RIGHT_VISITED;
+ y = RBT_RIGHT(x);
+ if (RBT_IS_BLACK(y))
+ curr_blacks++;
+ if (y) {
+ x = y;
+ stk[++i] = 0;
+ continue;
+ }
+ else {
+ if (blacks < 0)
+ blacks = curr_blacks;
+ ASSERT(tcs, blacks == curr_blacks);
+ curr_blacks--;
+ }
+ }
+
+
+ /* Check x ... */
+
+ is_x_black = RBT_IS_BLACK(x);
+ x_sz = BLK_SZ(x);
+
+
+ if (!is_x_black) {
+ ASSERT(tcs, RBT_IS_BLACK(RBT_RIGHT(x)));
+ ASSERT(tcs, RBT_IS_BLACK(RBT_LEFT(x)));
+ }
+
+ ASSERT(tcs, RBT_PARENT(x) || x == root);
+
+ y = RBT_LEFT(x);
+ if (y) {
+ y_sz = BLK_SZ(y);
+ ASSERT(tcs, RBT_PARENT(y) == x);
+ if (address_order) {
+ ASSERT(tcs, y_sz < x_sz || (y_sz == x_sz && y < x));
+ }
+ else {
+ ASSERT(tcs, RBT_IS_TREE(y));
+ ASSERT(tcs, y_sz < x_sz);
+ }
+ }
+
+ y = RBT_RIGHT(x);
+ if (y) {
+ y_sz = BLK_SZ(y);
+ ASSERT(tcs, RBT_PARENT(y) == x);
+ if (address_order) {
+ ASSERT(tcs, y_sz > x_sz || (y_sz == x_sz && y > x));
+ }
+ else {
+ ASSERT(tcs, RBT_IS_TREE(y));
+ ASSERT(tcs, y_sz > x_sz);
+ }
+ }
+
+ if (!address_order) {
+ Ulong l_sz;
+ RBTL_t *l = RBT_NEXT(x);
+ for (l = RBT_NEXT(x); l; l = RBT_NEXT(l)) {
+ l_sz = BLK_SZ(l);
+ ASSERT(tcs, l_sz == x_sz);
+ ASSERT(tcs, !RBT_IS_TREE(l));
+ }
+ }
+
+ if (size && x_sz >= size) {
+ if (!res)
+ res = x;
+ else {
+ y_sz = BLK_SZ(res);
+ if (address_order) {
+ if (x_sz < y_sz || (x_sz == y_sz && x < res))
+ res = x;
+ }
+ else {
+ if (!res || x_sz < y_sz)
+ res = x;
+ }
+ }
+ }
+
+ if (max_i < i)
+ max_i = i;
+ if (is_x_black)
+ curr_blacks--;
+ x = RBT_PARENT(x);
+ i--;
+ }
+
+ done:
+ ASSERT(tcs, curr_blacks == 0);
+ ASSERT(tcs, i == -1);
+
+ testcase_printf(tcs, "Red-Black Tree OK! Max depth = %d; "
+ "Black depth = %d\n", max_i+1, blacks < 0 ? 0 : blacks);
+
+ return res;
+
+}
+
+static void
+do_check(TestCaseState_t *tcs, Allctr_t *a, Ulong size)
+{
+ Ulong sz = ((size + 7) / 8)*8;
+ void *tmp;
+ Block_t *x, *y;
+
+ x = (Block_t *) check_tree(tcs, a, sz);
+ tmp = ALLOC(a, sz - ABLK_HDR_SZ);
+ ASSERT(tcs, tmp);
+ y = UMEM2BLK(tmp);
+ if (IS_AOBF(a)) {
+ ASSERT(tcs, x == y);
+ }
+ else {
+ ASSERT(tcs, BLK_SZ(x) == BLK_SZ(y));
+ }
+ FREE(a, tmp);
+}
+
+
+static void
+test_it(TestCaseState_t *tcs)
+{
+ int i;
+ Allctr_t a = ((rbtree_test_data *) tcs->extra)->allocator;
+ void **blk = ((rbtree_test_data *) tcs->extra)->blk;
+ void **fence = ((rbtree_test_data *) tcs->extra)->fence;
+ Ulong min_blk_sz;
+
+ min_blk_sz = MIN_BLK_SZ(a);
+
+ for (i = 0; i < NO_BLOCKS; i++) {
+ blk[i] = ALLOC(a, min_blk_sz + i % 500);
+ fence[i] = ALLOC(a, 1);
+ ASSERT(tcs, blk[i] && fence[i]);
+ }
+
+ for (i = 0; i < NO_BLOCKS; i++) {
+ if (i % 3 == 0) {
+ FREE(a, blk[i]);
+ blk[i] = NULL;
+ }
+ if (i % (NO_BLOCKS/2) == 0)
+ do_check(tcs, a, 50);
+ }
+
+ for (i = 0; i < NO_BLOCKS; i++) {
+ if (i % 5 == 0 && blk[i]) {
+ FREE(a, blk[i]);
+ blk[i] = NULL;
+ }
+ if (i % (NO_BLOCKS/2) == 0)
+ do_check(tcs, a, 200);
+ }
+
+ for (i = 0; i < NO_BLOCKS; i++) {
+ if (blk[i]) {
+ FREE(a, blk[i]);
+ blk[i] = NULL;
+ }
+ if (i % (NO_BLOCKS/2) == 0)
+ do_check(tcs, a, 100);
+ }
+
+ do_check(tcs, a, 250);
+
+ for (i = 0; i < NO_BLOCKS; i++) {
+ FREE(a, fence[i]);
+ if (i % (NO_BLOCKS/3) == 0)
+ do_check(tcs, a, 300);
+ }
+
+ ASSERT(tcs, RBT_ROOT(a));
+ ASSERT(tcs, !RBT_LEFT(RBT_ROOT(a)));
+ ASSERT(tcs, !RBT_RIGHT(RBT_ROOT(a)));
+}
+
+
+char *
+testcase_name(void)
+{
+ return "rbtree";
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra) {
+ rbtree_test_data *td = tcs->extra;
+ tcs->extra = NULL;
+ if (td->allocator)
+ STOP_ALC(td->allocator);
+ if (td->blk)
+ testcase_free((void *) td->blk);
+ if (td->fence)
+ testcase_free((void *) td->fence);
+ testcase_free((void *) td);
+ }
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ char *argv1[] = {"-tasbf", NULL};
+ char *argv2[] = {"-tasaobf", NULL};
+ Allctr_t *a;
+ rbtree_test_data *td;
+
+ /* Best fit... */
+
+ testcase_printf(tcs, "Setup...\n");
+
+ td = (rbtree_test_data *) testcase_alloc(sizeof(rbtree_test_data));
+ ASSERT(tcs, td);
+ tcs->extra = (void *) td;
+ td->allocator = NULL;
+ td->blk = (void **) testcase_alloc(sizeof(void *)*NO_BLOCKS);
+ td->fence = (void **) testcase_alloc(sizeof(void *)*NO_BLOCKS);
+ ASSERT(tcs, td->blk && td->fence);
+
+ testcase_printf(tcs, "Starting test of best fit...\n");
+
+ td->allocator = a = START_ALC("rbtree_bf_", 0, argv1);
+
+ ASSERT(tcs, a);
+ ASSERT(tcs, !IS_AOBF(a));
+
+ test_it(tcs);
+
+ STOP_ALC(a);
+ td->allocator = NULL;
+
+ testcase_printf(tcs, "Best fit test succeeded!\n");
+
+ /* Address order best fit... */
+
+ testcase_printf(tcs, "Starting test of address order best fit...\n");
+
+ td->allocator = a = START_ALC("rbtree_aobf_", 0, argv2);
+
+ ASSERT(tcs, a);
+ ASSERT(tcs, IS_AOBF(a));
+
+ test_it(tcs);
+
+ STOP_ALC(a);
+ td->allocator = NULL;
+
+ testcase_printf(tcs, "Address order best fit test succeeded!\n");
+
+}
diff --git a/erts/emulator/test/alloc_SUITE_data/realloc_copy.c b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c
new file mode 100644
index 0000000000..12454c75e4
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/realloc_copy.c
@@ -0,0 +1,279 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include "allocator_test.h"
+#include <stdio.h>
+#include <string.h>
+
+#if 1
+#define PRINT_ALLOC_OPS
+#endif
+
+#define SBC_THRESHOLD 8192
+#define NO_OF_BLOCKS 7
+#define NO_OF_ALLOC_OPS_PER_BLOCK 700
+
+typedef struct {
+ unsigned char *p;
+ Ulong s;
+ int i;
+ Ulong *as;
+} block;
+
+Ulong alloc_seq_1[] = {
+ SBC_THRESHOLD, /* mmap */
+ SBC_THRESHOLD*4, /* mmap to new mmap */
+ SBC_THRESHOLD/50, /* mmap to malloc */
+ SBC_THRESHOLD, /* malloc to mmap */
+ 0
+};
+
+
+Ulong alloc_seq_2[] = {
+ 1,
+ SBC_THRESHOLD/10,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/10,
+ 1,
+ 0
+};
+
+Ulong alloc_seq_3[] = {
+ SBC_THRESHOLD*11,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/10,
+ 1,
+ SBC_THRESHOLD/10,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*10,
+ 0
+};
+
+Ulong alloc_seq_4[] = {
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD*1,
+ 0
+};
+
+Ulong alloc_seq_5[] = {
+ SBC_THRESHOLD/50,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD/50,
+ 0
+};
+
+Ulong alloc_seq_6[] = {
+ SBC_THRESHOLD/50,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD/50,
+ SBC_THRESHOLD*10,
+ 0
+};
+
+Ulong alloc_seq_7[] = {
+ 1,
+ SBC_THRESHOLD/50,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD/50,
+ 0
+};
+
+
+block blocks[NO_OF_BLOCKS] = {{NULL, 0, 0, alloc_seq_1},
+ {NULL, 0, 0, alloc_seq_2},
+ {NULL, 0, 0, alloc_seq_3},
+ {NULL, 0, 0, alloc_seq_4},
+ {NULL, 0, 0, alloc_seq_5},
+ {NULL, 0, 0, alloc_seq_6},
+ {NULL, 0, 0, alloc_seq_7}};
+
+#define CHECK_BLOCK_DATA(T, P, S, D) \
+ check_block_data(__FILE__, __LINE__, (T), (P), (S), (D))
+
+static void
+check_block_data(char *file, int line,
+ TestCaseState_t *tcs, unsigned char *p, Ulong sz, int d)
+{
+ Ulong i;
+ for (i = 0; i < sz; i++)
+ if (p[i] != (unsigned char) d)
+ testcase_failed(tcs, "%s:%d: Data clobbered! found id=%d; "
+ "expected id=%d\n", file, line, (int) p[i], d);
+}
+
+
+static void
+alloc_op(TestCaseState_t *tcs, Allctr_t *a, block *bp, int id, int clean_up)
+{
+ if(bp->p)
+ CHECK_BLOCK_DATA(tcs, bp->p, bp->s, id);
+
+ if(bp->as[bp->i] == 0 || clean_up) {
+ FREE(a, bp->p);
+#ifdef PRINT_ALLOC_OPS
+ testcase_printf(tcs, "FREE(0x%lx) [id=%d]\n", (Ulong) bp->p, id);
+#endif
+ bp->p = NULL;
+ bp->s = 0;
+ bp->i = 0; /* start from the beginning again */
+ return;
+ }
+
+ if(!bp->p) {
+ bp->s = bp->as[bp->i];
+ bp->p = (unsigned char *) ALLOC(a, bp->s);
+#ifdef PRINT_ALLOC_OPS
+ testcase_printf(tcs, "0x%lx = ALLOC(%lu) [id=%d]\n",
+ (Ulong) bp->p, bp->s, id);
+#endif
+ if(!bp->p)
+ testcase_failed(tcs, "ALLOC(%lu) failed [id=%d])\n", bp->s, id);
+ memset((void *) bp->p, id, (size_t) bp->s);
+ }
+ else {
+ unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]);
+#ifdef PRINT_ALLOC_OPS
+ testcase_printf(tcs, "0x%lx = REALLOC(0x%lx, %lu) [id=%d]\n",
+ (Ulong) p, (Ulong) bp->p, bp->as[bp->i], id);
+#endif
+ if(!p) {
+ testcase_failed(tcs, "REALLOC(0x%lx, %lu) failed [id=%d]\n",
+ (Ulong) bp->p, bp->as[bp->i], id);
+ }
+
+ if(bp->s < bp->as[bp->i]) {
+ CHECK_BLOCK_DATA(tcs, p, bp->s, id);
+ memset((void *) p, id, (size_t) bp->as[bp->i]);
+ }
+ else
+ CHECK_BLOCK_DATA(tcs, p, bp->as[bp->i], id);
+
+ bp->s = bp->as[bp->i];
+ bp->p = p;
+ }
+
+ bp->i++;
+}
+
+char *
+testcase_name(void)
+{
+ return "realloc_copy";
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ int i, j;
+ char sbct_buf[20];
+ char *argv[] = {"-tmmsbc", "5000", "-tsbct", &sbct_buf[0], NULL};
+ Allctr_t *a;
+
+ sprintf(sbct_buf, "%d", SBC_THRESHOLD/1024);
+
+ a = START_ALC("realloc_copy_", 0, argv);
+ ASSERT(tcs, a);
+ tcs->extra = (void *) a;
+
+ for(i = 0; i < NO_OF_ALLOC_OPS_PER_BLOCK; i++)
+ for(j = 0; j < NO_OF_BLOCKS; j++)
+ alloc_op(tcs, a, &blocks[j], j + 1, 0);
+
+ for(j = 0; j < NO_OF_BLOCKS; j++)
+ alloc_op(tcs, a, &blocks[j], j + 1, 1);
+
+ STOP_ALC((Allctr_t *) tcs->extra);
+ tcs->extra = NULL;
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ if (tcs->extra)
+ STOP_ALC((Allctr_t *) tcs->extra);
+}
+
diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.c b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c
new file mode 100644
index 0000000000..1e98844838
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.c
@@ -0,0 +1,260 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include "testcase_driver.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <string.h>
+
+#ifdef __WIN32__
+#undef HAVE_VSNPRINTF
+#define HAVE_VSNPRINTF 1
+#define vsnprintf _vsnprintf
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#define HAVE_VSNPRINTF 0
+#endif
+
+#define COMMENT_BUF_SZ 4096
+
+#define TESTCASE_FAILED 0
+#define TESTCASE_SKIPPED 1
+#define TESTCASE_SUCCEEDED 2
+
+typedef struct {
+ TestCaseState_t visible;
+ ErlDrvPort port;
+ int result;
+ jmp_buf done_jmp_buf;
+ char *comment;
+ char comment_buf[COMMENT_BUF_SZ];
+} InternalTestCaseState_t;
+
+ErlDrvData testcase_drv_start(ErlDrvPort port, char *command);
+void testcase_drv_stop(ErlDrvData drv_data);
+void testcase_drv_run(ErlDrvData drv_data, char *buf, int len);
+
+static ErlDrvEntry testcase_drv_entry = {
+ NULL,
+ testcase_drv_start,
+ testcase_drv_stop,
+ testcase_drv_run
+};
+
+
+DRIVER_INIT(testcase_drv)
+{
+ testcase_drv_entry.driver_name = testcase_name();
+ return &testcase_drv_entry;
+}
+
+ErlDrvData
+testcase_drv_start(ErlDrvPort port, char *command)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *)
+ driver_alloc(sizeof(InternalTestCaseState_t));
+ if (!itcs) {
+ return ERL_DRV_ERROR_GENERAL;
+ }
+
+ itcs->visible.testcase_name = testcase_name();
+ itcs->visible.extra = NULL;
+ itcs->port = port;
+ itcs->result = TESTCASE_FAILED;
+ itcs->comment = "";
+
+ return (ErlDrvData) itcs;
+}
+
+void
+testcase_drv_stop(ErlDrvData drv_data)
+{
+ testcase_cleanup((TestCaseState_t *) drv_data);
+ driver_free((void *) drv_data);
+}
+
+void
+testcase_drv_run(ErlDrvData drv_data, char *buf, int len)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) drv_data;
+ ErlDrvTermData result_atom;
+ ErlDrvTermData msg[12];
+
+ itcs->visible.command = buf;
+ itcs->visible.command_len = len;
+
+ if (setjmp(itcs->done_jmp_buf) == 0) {
+ testcase_run((TestCaseState_t *) itcs);
+ itcs->result = TESTCASE_SUCCEEDED;
+ }
+
+ switch (itcs->result) {
+ case TESTCASE_SUCCEEDED:
+ result_atom = driver_mk_atom("succeeded");
+ break;
+ case TESTCASE_SKIPPED:
+ result_atom = driver_mk_atom("skipped");
+ break;
+ case TESTCASE_FAILED:
+ default:
+ result_atom = driver_mk_atom("failed");
+ break;
+ }
+
+ msg[0] = ERL_DRV_ATOM;
+ msg[1] = (ErlDrvTermData) result_atom;
+
+ msg[2] = ERL_DRV_PORT;
+ msg[3] = driver_mk_port(itcs->port);
+
+ msg[4] = ERL_DRV_ATOM;
+ msg[5] = driver_mk_atom(itcs->visible.testcase_name);
+
+ msg[6] = ERL_DRV_STRING;
+ msg[7] = (ErlDrvTermData) itcs->comment;
+ msg[8] = (ErlDrvTermData) strlen(itcs->comment);
+
+ msg[9] = ERL_DRV_TUPLE;
+ msg[10] = (ErlDrvTermData) 4;
+
+ driver_output_term(itcs->port, msg, 11);
+}
+
+int
+testcase_assertion_failed(TestCaseState_t *tcs,
+ char *file, int line, char *assertion)
+{
+ testcase_failed(tcs, "%s:%d: Assertion failed: \"%s\"",
+ file, line, assertion);
+ return 0;
+}
+
+void
+testcase_printf(TestCaseState_t *tcs, char *frmt, ...)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
+ ErlDrvTermData msg[12];
+ va_list va;
+ va_start(va, frmt);
+#if HAVE_VSNPRINTF
+ vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
+#else
+ vsprintf(itcs->comment_buf, frmt, va);
+#endif
+ va_end(va);
+
+ msg[0] = ERL_DRV_ATOM;
+ msg[1] = (ErlDrvTermData) driver_mk_atom("print");
+
+ msg[2] = ERL_DRV_PORT;
+ msg[3] = driver_mk_port(itcs->port);
+
+ msg[4] = ERL_DRV_ATOM;
+ msg[5] = driver_mk_atom(itcs->visible.testcase_name);
+
+ msg[6] = ERL_DRV_STRING;
+ msg[7] = (ErlDrvTermData) itcs->comment_buf;
+ msg[8] = (ErlDrvTermData) strlen(itcs->comment_buf);
+
+ msg[9] = ERL_DRV_TUPLE;
+ msg[10] = (ErlDrvTermData) 4;
+
+ driver_output_term(itcs->port, msg, 11);
+}
+
+
+void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
+ va_list va;
+ va_start(va, frmt);
+#if HAVE_VSNPRINTF
+ vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
+#else
+ vsprintf(itcs->comment_buf, frmt, va);
+#endif
+ va_end(va);
+
+ itcs->result = TESTCASE_SUCCEEDED;
+ itcs->comment = itcs->comment_buf;
+
+ longjmp(itcs->done_jmp_buf, 1);
+}
+
+void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
+ va_list va;
+ va_start(va, frmt);
+#if HAVE_VSNPRINTF
+ vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
+#else
+ vsprintf(itcs->comment_buf, frmt, va);
+#endif
+ va_end(va);
+
+ itcs->result = TESTCASE_SKIPPED;
+ itcs->comment = itcs->comment_buf;
+
+ longjmp(itcs->done_jmp_buf, 1);
+}
+
+void testcase_failed(TestCaseState_t *tcs, char *frmt, ...)
+{
+ InternalTestCaseState_t *itcs = (InternalTestCaseState_t *) tcs;
+ char buf[10];
+ size_t bufsz = sizeof(buf);
+ va_list va;
+ va_start(va, frmt);
+#if HAVE_VSNPRINTF
+ vsnprintf(itcs->comment_buf, COMMENT_BUF_SZ, frmt, va);
+#else
+ vsprintf(itcs->comment_buf, frmt, va);
+#endif
+ va_end(va);
+
+ itcs->result = TESTCASE_FAILED;
+ itcs->comment = itcs->comment_buf;
+
+ if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0
+ && strcmp("true", buf) == 0) {
+ fprintf(stderr, "Testcase \"%s\" failed: %s\n",
+ itcs->visible.testcase_name, itcs->comment);
+ abort();
+ }
+
+ longjmp(itcs->done_jmp_buf, 1);
+}
+
+void *testcase_alloc(size_t size)
+{
+ return driver_alloc(size);
+}
+
+void *testcase_realloc(void *ptr, size_t size)
+{
+ return driver_realloc(ptr, size);
+}
+
+void testcase_free(void *ptr)
+{
+ driver_free(ptr);
+}
diff --git a/erts/emulator/test/alloc_SUITE_data/testcase_driver.h b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h
new file mode 100644
index 0000000000..66d567cb44
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/testcase_driver.h
@@ -0,0 +1,51 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#ifndef TESTCASE_DRIVER_H__
+#define TESTCASE_DRIVER_H__
+
+#include "erl_driver.h"
+#include <stdlib.h>
+
+typedef struct {
+ char *testcase_name;
+ char *command;
+ int command_len;
+ void *extra;
+} TestCaseState_t;
+
+#define ASSERT(TCS, B) \
+ ((void) ((B) ? 1 : testcase_assertion_failed((TCS), __FILE__, __LINE__, #B)))
+
+
+void testcase_printf(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_succeeded(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_skipped(TestCaseState_t *tcs, char *frmt, ...);
+void testcase_failed(TestCaseState_t *tcs, char *frmt, ...);
+int testcase_assertion_failed(TestCaseState_t *tcs, char *file, int line,
+ char *assertion);
+void *testcase_alloc(size_t size);
+void *testcase_realloc(void *ptr, size_t size);
+void testcase_free(void *ptr);
+
+
+char *testcase_name(void);
+void testcase_run(TestCaseState_t *tcs);
+void testcase_cleanup(TestCaseState_t *tcs);
+
+#endif
diff --git a/erts/emulator/test/alloc_SUITE_data/threads.c b/erts/emulator/test/alloc_SUITE_data/threads.c
new file mode 100644
index 0000000000..1247e5d7dd
--- /dev/null
+++ b/erts/emulator/test/alloc_SUITE_data/threads.c
@@ -0,0 +1,447 @@
+/* ``The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved via the world wide web at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+
+#ifndef __WIN32__
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include "testcase_driver.h"
+#include "allocator_test.h"
+
+#ifdef __WIN32__
+#undef HAVE_VSNPRINTF
+#define HAVE_VSNPRINTF 1
+#define vsnprintf _vsnprintf
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#define HAVE_VSNPRINTF 0
+#endif
+
+#define NO_OF_ALLOC_SEQS 6
+#define NO_OF_THREADS (18)
+#define NO_OF_BLOCKS 10
+#define NO_OF_OPS_PER_BL 200
+#define SBC_THRESHOLD 8192
+
+#define BLOCK_ID(TN, BN) ((TN) << 4 | (BN))
+
+#define ERR_BUF_SZ 4096
+static char err_buf[ERR_BUF_SZ];
+static volatile int tc_failed;
+static int dead_thread_no;
+static erts_mutex tc_mutex;
+static erts_cond tc_cond;
+
+static void exit_thread(int t_no, int do_lock)
+{
+ if (do_lock)
+ THR_MTX_LOCK(tc_mutex);
+
+ while (dead_thread_no >= 0)
+ THR_COND_WAIT(tc_cond, tc_mutex);
+ dead_thread_no = t_no;
+
+ THR_COND_BCAST(tc_cond);
+ THR_MTX_UNLOCK(tc_mutex);
+ THR_EXIT(NULL);
+}
+
+static void fail(int t_no, char *frmt, ...)
+{
+ char buf[10];
+ size_t bufsz = sizeof(buf);
+ va_list va;
+
+ THR_MTX_LOCK(tc_mutex);
+
+ va_start(va, frmt);
+#if HAVE_VSNPRINTF
+ vsnprintf(err_buf, ERR_BUF_SZ, frmt, va);
+#else
+ vsprintf(err_buf, frmt, va);
+#endif
+ va_end(va);
+
+ tc_failed = 1;
+
+ if (erl_drv_getenv("ERL_ABORT_ON_FAILURE", buf, &bufsz) == 0
+ && strcmp("true", buf) == 0) {
+ fprintf(stderr, "Testcase \"%s\" failed: %s\n",
+ testcase_name(), err_buf);
+ abort();
+ }
+
+ exit_thread(t_no, 0);
+}
+
+static Allctr_t *alloc_not_ts = NULL;
+static Allctr_t *alloc_ts_1 = NULL;
+static Allctr_t *alloc_ts_2 = NULL;
+
+static void stop_allocators(void)
+{
+ if (alloc_not_ts) {
+ STOP_ALC(alloc_not_ts);
+ alloc_not_ts = NULL;
+ }
+ if (alloc_ts_1) {
+ STOP_ALC(alloc_ts_1);
+ alloc_ts_1 = NULL;
+ }
+ if (alloc_ts_2) {
+ STOP_ALC(alloc_ts_2);
+ alloc_ts_2 = NULL;
+ }
+}
+
+
+void *thread_func(void *arg);
+
+typedef struct {
+ Allctr_t *a;
+ int t_no;
+ int no_ops_per_bl;
+} ThreadData;
+
+
+char *
+testcase_name(void)
+{
+ return "threads";
+}
+
+void
+testcase_cleanup(TestCaseState_t *tcs)
+{
+ stop_allocators();
+}
+
+void
+testcase_run(TestCaseState_t *tcs)
+{
+ struct {
+ erts_thread tid;
+ ThreadData arg;
+ } threads[NO_OF_THREADS+1] = {{0}};
+ int no_threads;
+ int i;
+ char sbct_buf[10];
+ char *argv_org[] = {"-tasaobf", "-tmmsbc5000", "-tmmmbc5000", "-tsbct",
+ &sbct_buf[0], NULL};
+ char *argv[sizeof(argv_org)/sizeof(argv_org[0])];
+
+ if (!IS_THREADS_ENABLED)
+ testcase_skipped(tcs, "Threads not enabled");
+
+ alloc_not_ts = NULL;
+ alloc_ts_1 = NULL;
+ alloc_ts_2 = NULL;
+
+ err_buf[0] = '\0';
+
+ sprintf(sbct_buf, "%d", SBC_THRESHOLD/1024);
+
+ memcpy((void *) argv, argv_org, sizeof(argv_org));
+ alloc_not_ts = START_ALC("threads_not_ts", 0, argv);
+ ASSERT(tcs, alloc_not_ts);
+ memcpy((void *) argv, argv_org, sizeof(argv_org));
+ alloc_ts_1 = START_ALC("threads_ts_1", 1, argv);
+ ASSERT(tcs, alloc_ts_1);
+ memcpy((void *) argv, argv_org, sizeof(argv_org));
+ alloc_ts_2 = START_ALC("threads_ts_2", 1, argv);
+ ASSERT(tcs, alloc_ts_2);
+
+ ASSERT(tcs, !IS_ALLOC_THREAD_SAFE(alloc_not_ts));
+ ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_1));
+ ASSERT(tcs, IS_ALLOC_THREAD_SAFE(alloc_ts_2));
+
+ tc_mutex = THR_MTX_CREATE();
+ tc_cond = THR_COND_CREATE();
+
+ THR_MTX_LOCK(tc_mutex);
+
+ dead_thread_no = -1;
+ no_threads = 0;
+
+ for(i = 1; i <= NO_OF_THREADS; i++) {
+ char *alc;
+ int res;
+
+ threads[i].arg.no_ops_per_bl = NO_OF_OPS_PER_BL;
+
+ if (i == 1) {
+ alc = "threads_not_ts";
+ threads[i].arg.no_ops_per_bl *= 2;
+ threads[i].arg.a = alloc_not_ts;
+ }
+ else if (i % 2 == 0) {
+ alc = "threads_ts_1";
+ threads[i].arg.a = alloc_ts_1;
+ }
+ else {
+ alc = "threads_ts_2";
+ threads[i].arg.a = alloc_ts_2;
+ }
+ threads[i].arg.t_no = i;
+
+ threads[i].tid = THR_CREATE(thread_func, (void *) &threads[i].arg);
+ if (threads[i].tid) {
+ testcase_printf(tcs, "Successfully created thread %d "
+ "using %s_alloc\n", i, alc);
+ no_threads++;
+ }
+ else {
+ tc_failed = 1;
+ sprintf(err_buf, "Failed to create thread %d\n", i);
+ break;
+ }
+
+ }
+
+ while (no_threads) {
+ THR_COND_WAIT(tc_cond, tc_mutex);
+ if (dead_thread_no >= 0) {
+ no_threads--;
+ THR_JOIN(threads[dead_thread_no].tid);
+ testcase_printf(tcs, "Thread %d died\n", dead_thread_no);
+ dead_thread_no = -1;
+ THR_COND_BCAST(tc_cond);
+ }
+ }
+
+ THR_MTX_UNLOCK(tc_mutex);
+ THR_MTX_DESTROY(tc_mutex);
+ THR_COND_DESTROY(tc_cond);
+
+ stop_allocators();
+
+ if (tc_failed)
+ testcase_failed(tcs, "%s", err_buf);
+}
+
+Ulong alloc_seq_1[] = {
+ 17,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*20,
+ SBC_THRESHOLD*2,
+ 17,
+ 0
+};
+
+Ulong alloc_seq_2[] = {
+ SBC_THRESHOLD*20,
+ SBC_THRESHOLD*2,
+ 17,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*20,
+ 0
+};
+
+Ulong alloc_seq_3[] = {
+ 1,
+ SBC_THRESHOLD/10,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/1,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD*9,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/9,
+ SBC_THRESHOLD/10,
+ 1,
+ 0
+};
+
+Ulong alloc_seq_4[] = {
+ SBC_THRESHOLD*2,
+ SBC_THRESHOLD*3,
+ SBC_THRESHOLD*7,
+ SBC_THRESHOLD*8,
+ SBC_THRESHOLD*5,
+ SBC_THRESHOLD*6,
+ SBC_THRESHOLD*1,
+ SBC_THRESHOLD*10,
+ SBC_THRESHOLD*4,
+ SBC_THRESHOLD*2,
+ 0
+};
+
+Ulong alloc_seq_5[] = {
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/1,
+ SBC_THRESHOLD/10,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/2,
+ SBC_THRESHOLD/3,
+ SBC_THRESHOLD/7,
+ SBC_THRESHOLD/8,
+ SBC_THRESHOLD/5,
+ SBC_THRESHOLD/6,
+ SBC_THRESHOLD/1,
+ SBC_THRESHOLD/10,
+ SBC_THRESHOLD/4,
+ SBC_THRESHOLD/2,
+ 0
+};
+
+Ulong alloc_seq_6[] = {
+ 1, 50, 100, 50, 23, 46, 2345, 23, 54, 2, 0
+};
+
+Ulong *alloc_seqs[NO_OF_ALLOC_SEQS] = {
+ alloc_seq_1,
+ alloc_seq_2,
+ alloc_seq_3,
+ alloc_seq_4,
+ alloc_seq_5,
+ alloc_seq_6
+};
+
+typedef struct {
+ unsigned char *p;
+ Ulong s;
+ int i;
+ Ulong *as;
+} block;
+
+#define CHECK_BLOCK_DATA(T, P, S, D) \
+ check_block_data(__FILE__, __LINE__, (T), (P), (S), (D))
+
+static void
+check_block_data(char *file, int line, int t_no,
+ unsigned char *p, Ulong sz, int d)
+{
+ Ulong i;
+ for (i = 0; i < sz; i++)
+ if (p[i] != (unsigned char) d)
+ fail(t_no, "%s:%d: Thread no %d found clobbered data! "
+ "found id=%d; expected id=%d\n",
+ file, line, t_no, (int) p[i], d);
+}
+
+static void
+alloc_op(int t_no, Allctr_t *a, block *bp, int id, int clean_up)
+{
+ if (tc_failed)
+ exit_thread(t_no, 1);
+
+ if(bp->p)
+ CHECK_BLOCK_DATA(t_no, bp->p, bp->s, id);
+
+ if(bp->as[bp->i] == 0 || clean_up) {
+ FREE(a, bp->p);
+ bp->p = NULL;
+ bp->s = 0;
+ bp->i = 0; /* start from the beginning again */
+ return;
+ }
+
+ if(!bp->p) {
+ bp->s = bp->as[bp->i];
+ bp->p = (unsigned char *) ALLOC(a, bp->s);
+ if(!bp->p)
+ fail(t_no, "ALLOC(%lu) failed [id=%d])\n", bp->s, id);
+ memset((void *) bp->p, id, (size_t) bp->s);
+ }
+ else {
+ unsigned char *p = (unsigned char *) REALLOC(a, bp->p, bp->as[bp->i]);
+ if(!p)
+ fail(t_no, "REALLOC(0x%lx, %lu) failed [id=%d]\n",
+ (Ulong) bp->p, bp->as[bp->i], id);
+
+ if(bp->s < bp->as[bp->i]) {
+ CHECK_BLOCK_DATA(t_no, p, bp->s, id);
+ memset((void *) p, id, (size_t) bp->as[bp->i]);
+ }
+ else
+ CHECK_BLOCK_DATA(t_no, p, bp->as[bp->i], id);
+
+ bp->s = bp->as[bp->i];
+ bp->p = p;
+ }
+
+ bp->i++;
+}
+
+
+void *
+thread_func(void *arg)
+{
+ int i, j;
+ ThreadData *td = ((ThreadData *) arg);
+ block bs[NO_OF_BLOCKS];
+
+ for(i = 0; i < NO_OF_BLOCKS; i++) {
+ bs[i].p = NULL;
+ bs[i].s = 0;
+ bs[i].i = 0;
+ bs[i].as = alloc_seqs[i % NO_OF_ALLOC_SEQS];
+ }
+
+ for(i = 0; i < td->no_ops_per_bl; i++) {
+
+ for(j = 0; j < NO_OF_BLOCKS; j++)
+ alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 0);
+ }
+
+ for(j = 0; j < NO_OF_BLOCKS; j++)
+ alloc_op(td->t_no, td->a, &bs[j], BLOCK_ID(td->t_no, j), 1);
+
+ exit_thread(td->t_no, 1);
+ return NULL;
+}