aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_afit_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/beam/erl_afit_alloc.c')
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
new file mode 100644
index 0000000000..e8b594bb47
--- /dev/null
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -0,0 +1,256 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * 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 online 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.
+ *
+ * %CopyrightEnd%
+ */
+
+
+/*
+ * Description: A fast allocator intended for temporary allocation.
+ * When allocating, only the first block in the free list
+ * is inspected, if this block doesn't fit a new carrier
+ * is created. NOTE: this allocator can behave really bad
+ * if misused.
+ *
+ * This module is a callback-module for erl_alloc_util.c
+ *
+ * Author: Rickard Green
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "global.h"
+#define GET_ERL_AF_ALLOC_IMPL
+#include "erl_afit_alloc.h"
+
+
+#define MIN_MBC_SZ (16*1024)
+#define MIN_MBC_FIRST_FREE_SZ (4*1024)
+
+/* Prototypes of callback functions */
+static Block_t * get_free_block (Allctr_t *, Uint,
+ Block_t *, Uint);
+static void link_free_block (Allctr_t *, Block_t *);
+static void unlink_free_block (Allctr_t *, Block_t *);
+
+
+static Eterm info_options (Allctr_t *, char *, int *,
+ void *arg, Uint **, Uint *);
+static void init_atoms (void);
+
+static int atoms_initialized = 0;
+
+void
+erts_afalc_init(void)
+{
+ atoms_initialized = 0;
+}
+
+Allctr_t *
+erts_afalc_start(AFAllctr_t *afallctr,
+ AFAllctrInit_t *afinit,
+ AllctrInit_t *init)
+{
+ AFAllctr_t nulled_state = {{0}};
+ /* {{0}} is used instead of {0}, in order to avoid (an incorrect) gcc
+ warning. gcc warns if {0} is used as initializer of a struct when
+ the first member is a struct (not if, for example, the third member
+ is a struct). */
+ Allctr_t *allctr = (Allctr_t *) afallctr;
+
+ sys_memcpy((void *) afallctr, (void *) &nulled_state, sizeof(AFAllctr_t));
+
+ allctr->mbc_header_size = sizeof(Carrier_t);
+ allctr->min_mbc_size = MIN_MBC_SZ;
+ allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
+ allctr->min_block_size = sizeof(AFFreeBlock_t);
+ allctr->vsn_str = ERTS_ALC_AF_ALLOC_VSN_STR;
+
+ /* Callback functions */
+ allctr->get_free_block = get_free_block;
+ allctr->link_free_block = link_free_block;
+ allctr->unlink_free_block = unlink_free_block;
+ allctr->info_options = info_options;
+
+ allctr->get_next_mbc_size = NULL;
+ allctr->creating_mbc = NULL;
+ allctr->destroying_mbc = NULL;
+ allctr->init_atoms = init_atoms;
+
+#ifdef ERTS_ALLOC_UTIL_HARD_DEBUG
+ allctr->check_block = NULL;
+ allctr->check_mbc = NULL;
+#endif
+
+ allctr->atoms_initialized = 0;
+
+ if (!erts_alcu_start(allctr, init))
+ return NULL;
+
+ return allctr;
+}
+
+static Block_t *
+get_free_block(Allctr_t *allctr, Uint size, Block_t *cand_blk, Uint cand_size)
+{
+ AFAllctr_t *afallctr = (AFAllctr_t *) allctr;
+
+ ASSERT(!cand_blk || cand_size >= size);
+
+ if (afallctr->free_list && BLK_SZ(afallctr->free_list) >= size) {
+ AFFreeBlock_t *res = afallctr->free_list;
+ afallctr->free_list = res->next;
+ if (res->next)
+ res->next->prev = NULL;
+ return (Block_t *) res;
+ }
+ else
+ return NULL;
+}
+
+static void
+link_free_block(Allctr_t *allctr, Block_t *block)
+{
+ AFFreeBlock_t *blk = (AFFreeBlock_t *) block;
+ AFAllctr_t *afallctr = (AFAllctr_t *) allctr;
+
+ if (afallctr->free_list && BLK_SZ(afallctr->free_list) > BLK_SZ(blk)) {
+ blk->next = afallctr->free_list->next;
+ blk->prev = afallctr->free_list;
+ afallctr->free_list->next = blk;
+ }
+ else {
+ blk->next = afallctr->free_list;
+ blk->prev = NULL;
+ afallctr->free_list = blk;
+ }
+
+ if (blk->next)
+ blk->next->prev = blk;
+}
+
+static void
+unlink_free_block(Allctr_t *allctr, Block_t *block)
+{
+ AFFreeBlock_t *blk = (AFFreeBlock_t *) block;
+ AFAllctr_t *afallctr = (AFAllctr_t *) allctr;
+
+ if (blk->prev)
+ blk->prev->next = blk->next;
+ else
+ afallctr->free_list = blk->next;
+ if (blk->next)
+ blk->next->prev = blk->prev;
+}
+
+
+static struct {
+ Eterm as;
+ Eterm af;
+#ifdef DEBUG
+ Eterm end_of_atoms;
+#endif
+} am;
+
+static void ERTS_INLINE atom_init(Eterm *atom, char *name)
+{
+ *atom = am_atom_put(name, strlen(name));
+}
+#define AM_INIT(AM) atom_init(&am.AM, #AM)
+
+static void
+init_atoms(void)
+{
+#ifdef DEBUG
+ Eterm *atom;
+#endif
+
+ if (atoms_initialized)
+ return;
+
+#ifdef DEBUG
+ for (atom = (Eterm *) &am; atom <= &am.end_of_atoms; atom++) {
+ *atom = THE_NON_VALUE;
+ }
+#endif
+
+ AM_INIT(as);
+ AM_INIT(af);
+
+#ifdef DEBUG
+ for (atom = (Eterm *) &am; atom < &am.end_of_atoms; atom++) {
+ ASSERT(*atom != THE_NON_VALUE);
+ }
+#endif
+
+ atoms_initialized = 1;
+}
+
+
+#define bld_uint erts_bld_uint
+#define bld_cons erts_bld_cons
+#define bld_tuple erts_bld_tuple
+
+static ERTS_INLINE void
+add_2tup(Uint **hpp, Uint *szp, Eterm *lp, Eterm el1, Eterm el2)
+{
+ *lp = bld_cons(hpp, szp, bld_tuple(hpp, szp, 2, el1, el2), *lp);
+}
+
+static Eterm
+info_options(Allctr_t *allctr,
+ char *prefix,
+ int *print_to_p,
+ void *print_to_arg,
+ Uint **hpp,
+ Uint *szp)
+{
+ Eterm res = THE_NON_VALUE;
+
+ if (print_to_p) {
+ erts_print(*print_to_p, print_to_arg, "%sas: af\n", prefix);
+ }
+
+ if (hpp || szp) {
+
+ if (!atoms_initialized)
+ erl_exit(1, "%s:%d: Internal error: Atoms not initialized",
+ __FILE__, __LINE__);;
+
+ res = NIL;
+ add_2tup(hpp, szp, &res, am.as, am.af);
+ }
+
+ return res;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
+ * NOTE: erts_afalc_test() is only supposed to be used for testing. *
+ * *
+ * Keep alloc_SUITE_data/allocator_test.h updated if changes are made *
+ * to erts_afalc_test() *
+\* */
+
+unsigned long
+erts_afalc_test(unsigned long op, unsigned long a1, unsigned long a2)
+{
+ switch (op) {
+ default: ASSERT(0); return ~((unsigned long) 0);
+ }
+}