aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_alloc.h
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/emulator/beam/erl_alloc.h
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/emulator/beam/erl_alloc.h')
-rw-r--r--erts/emulator/beam/erl_alloc.h564
1 files changed, 564 insertions, 0 deletions
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
new file mode 100644
index 0000000000..e7a203002f
--- /dev/null
+++ b/erts/emulator/beam/erl_alloc.h
@@ -0,0 +1,564 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2002-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%
+ */
+
+#ifndef ERL_ALLOC_H__
+#define ERL_ALLOC_H__
+
+#include "erl_alloc_types.h"
+#include "erl_alloc_util.h"
+#ifdef USE_THREADS
+#include "erl_threads.h"
+#endif
+
+#ifdef DEBUG
+# undef ERTS_ALC_WANT_INLINE
+# define ERTS_ALC_WANT_INLINE 0
+#endif
+
+#ifndef ERTS_ALC_WANT_INLINE
+# define ERTS_ALC_WANT_INLINE 1
+#endif
+
+#if ERTS_CAN_INLINE && ERTS_ALC_WANT_INLINE
+# define ERTS_ALC_DO_INLINE 1
+# define ERTS_ALC_INLINE static ERTS_INLINE
+#else
+# define ERTS_ALC_DO_INLINE 0
+# define ERTS_ALC_INLINE
+#endif
+
+#define ERTS_FIX_CORE_ALLOCATOR ERTS_ALC_A_LONG_LIVED
+extern ErtsAlcType_t erts_fix_core_allocator_ix;
+
+typedef struct {
+ Uint total;
+ Uint used;
+} ErtsFixInfo;
+
+void erts_sys_alloc_init(void);
+void *erts_sys_alloc(ErtsAlcType_t, void *, Uint);
+void *erts_sys_realloc(ErtsAlcType_t, void *, void *, Uint);
+void erts_sys_free(ErtsAlcType_t, void *, void *);
+
+
+void erts_init_fix_alloc(Uint, void *(*)(Uint));
+Uint erts_get_fix_size(ErtsAlcType_t);
+void erts_set_fix_size(ErtsAlcType_t, Uint);
+void erts_fix_info(ErtsAlcType_t, ErtsFixInfo *);
+void *erts_fix_alloc(ErtsAlcType_t, void *, Uint);
+void *erts_fix_realloc(ErtsAlcType_t, void *, void*, Uint);
+void erts_fix_free(ErtsAlcType_t, void *, void*);
+
+
+Eterm erts_memory(int *, void *, void *, Eterm);
+Eterm erts_allocated_areas(int *, void *, void *);
+
+Eterm erts_alloc_util_allocators(void *proc);
+void erts_allocator_info(int, void *);
+Eterm erts_allocator_info_term(void *proc, Eterm which_alloc, int only_sz);
+Eterm erts_allocator_options(void *proc);
+
+#define ERTS_ALLOC_INIT_DEF_OPTS_INITER {0}
+typedef struct {
+ int dummy;
+} ErtsAllocInitOpts;
+
+void erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop);
+
+#if defined(GET_ERTS_ALC_TEST) || defined(ERTS_ALC_INTERNAL__)
+/* Only for testing */
+unsigned long erts_alc_test(unsigned long,
+ unsigned long,
+ unsigned long,
+ unsigned long);
+#endif
+
+#define ERTS_ALC_O_ALLOC 0
+#define ERTS_ALC_O_REALLOC 1
+#define ERTS_ALC_O_FREE 2
+
+#define ERTS_ALC_E_NOTSUP 0
+#define ERTS_ALC_E_NOMEM 1
+#define ERTS_ALC_E_NOALLCTR 2
+
+#define ERTS_ALC_MIN_LONG_LIVED_TIME (10*60*1000)
+
+typedef struct {
+ int alloc_util;
+ int enabled;
+ int thr_spec;
+ void *extra;
+} ErtsAllocatorInfo_t;
+
+typedef struct {
+ void * (*alloc) (ErtsAlcType_t, void *, Uint);
+ void * (*realloc) (ErtsAlcType_t, void *, void *, Uint);
+ void (*free) (ErtsAlcType_t, void *, void *);
+ void *extra;
+} ErtsAllocatorFunctions_t;
+
+extern ErtsAllocatorFunctions_t erts_allctrs[ERTS_ALC_A_MAX+1];
+extern ErtsAllocatorInfo_t erts_allctrs_info[ERTS_ALC_A_MAX+1];
+
+typedef struct {
+ int enabled;
+ int all_thr_safe;
+ int size;
+ Allctr_t **allctr;
+} ErtsAllocatorThrSpec_t;
+
+extern ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
+
+int erts_alc_get_thr_ix(void);
+void erts_alloc_reg_scheduler_id(Uint id);
+
+__decl_noreturn void erts_alloc_enomem(ErtsAlcType_t,Uint)
+ __noreturn;
+__decl_noreturn void erts_alloc_n_enomem(ErtsAlcType_t,Uint)
+ __noreturn;
+__decl_noreturn void erts_realloc_enomem(ErtsAlcType_t,void*,Uint)
+ __noreturn;
+__decl_noreturn void erts_realloc_n_enomem(ErtsAlcType_t,void*,Uint)
+ __noreturn;
+__decl_noreturn void erts_alc_fatal_error(int,int,ErtsAlcType_t,...)
+ __noreturn;
+
+/* --- DO *NOT* USE THESE DEPRECATED FUNCTIONS --- Instead use: */
+void *safe_alloc(Uint) __deprecated; /* erts_alloc() */
+void *safe_realloc(void *, Uint) __deprecated; /* erts_realloc() */
+void sys_free(void *) __deprecated; /* erts_free() */
+void *sys_alloc(Uint ) __deprecated; /* erts_alloc_fnf() */
+void *sys_realloc(void *, Uint) __deprecated; /* erts_realloc_fnf() */
+
+/*
+ * erts_alloc[_fnf](), erts_realloc[_fnf](), erts_free() works as
+ * malloc(), realloc(), and free() with the following exceptions:
+ *
+ * * They take an extra type argument as first argument which is
+ * the memory type to operate on. Memory types are generated
+ * (as ERTS_ALC_T_[SOMETHING] defines) from the erl_alloc.types
+ * configuration file.
+ * * The erts_alloc() and erts_realloc() functions terminate the
+ * emulator if memory cannot be obtained. The _fnf (Failure Not
+ * Fatal) suffixed versions return NULL if memory cannot be
+ * obtained.
+ * * They may be static functions so function pointers to "the same"
+ * function may differ.
+ *
+ * IMPORTANT: Memory allocated or reallocated as type X, can only
+ * be reallocated or deallocated as type X.
+ */
+
+#if !ERTS_ALC_DO_INLINE
+
+void *erts_alloc(ErtsAlcType_t type, Uint size);
+void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size);
+void erts_free(ErtsAlcType_t type, void *ptr);
+void *erts_alloc_fnf(ErtsAlcType_t type, Uint size);
+void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size);
+
+#endif /* #if !ERTS_ALC_DO_INLINE */
+
+#if ERTS_ALC_DO_INLINE || defined(ERTS_ALC_INTERNAL__)
+
+ERTS_ALC_INLINE
+void *erts_alloc(ErtsAlcType_t type, Uint size)
+{
+ void *res;
+ res = (*erts_allctrs[ERTS_ALC_T2A(type)].alloc)(
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ size);
+ if (!res)
+ erts_alloc_n_enomem(ERTS_ALC_T2N(type), size);
+ return res;
+}
+
+ERTS_ALC_INLINE
+void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size)
+{
+ void *res;
+ res = (*erts_allctrs[ERTS_ALC_T2A(type)].realloc)(
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ ptr,
+ size);
+ if (!res)
+ erts_realloc_n_enomem(ERTS_ALC_T2N(type), ptr, size);
+ return res;
+}
+
+ERTS_ALC_INLINE
+void erts_free(ErtsAlcType_t type, void *ptr)
+{
+ (*erts_allctrs[ERTS_ALC_T2A(type)].free)(
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ ptr);
+}
+
+
+ERTS_ALC_INLINE
+void *erts_alloc_fnf(ErtsAlcType_t type, Uint size)
+{
+ return (*erts_allctrs[ERTS_ALC_T2A(type)].alloc)(
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ size);
+}
+
+
+ERTS_ALC_INLINE
+void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size)
+{
+ return (*erts_allctrs[ERTS_ALC_T2A(type)].realloc)(
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ ptr,
+ size);
+}
+
+#endif /* #if ERTS_ALC_DO_INLINE || defined(ERTS_ALC_INTERNAL__) */
+
+#ifndef ERTS_CACHE_LINE_SIZE
+/* Assume a cache line size of 64 bytes */
+# define ERTS_CACHE_LINE_SIZE ((Uint) 64)
+# define ERTS_CACHE_LINE_MASK (ERTS_CACHE_LINE_SIZE - 1)
+#endif
+
+#define ERTS_ALC_CACHE_LINE_ALIGN_SIZE(SZ) \
+ (((((SZ) - 1) / ERTS_CACHE_LINE_SIZE) + 1) * ERTS_CACHE_LINE_SIZE)
+
+#define ERTS_QUALLOC_IMPL(NAME, TYPE, PASZ, ALCT) \
+ERTS_QUICK_ALLOC_IMPL(NAME, TYPE, PASZ, ALCT, \
+ (void) 0, (void) 0, (void) 0)
+
+#define ERTS_SMP_QUALLOC_IMPL(NAME, TYPE, PASZ, ALCT) \
+static erts_smp_spinlock_t NAME##_lck; \
+ERTS_QUICK_ALLOC_IMPL(NAME, TYPE, PASZ, ALCT, \
+ erts_smp_spinlock_init(&NAME##_lck, #NAME "_alloc_lock"),\
+ erts_smp_spin_lock(&NAME##_lck), \
+ erts_smp_spin_unlock(&NAME##_lck))
+
+#ifdef ERTS_SMP
+
+#define ERTS_TS_QUALLOC_IMPL(NAME, TYPE, PASZ, ALCT) \
+ERTS_SMP_QUALLOC_IMPL(NAME, TYPE, PASZ, ALCT)
+
+#else /* !ERTS_SMP */
+
+#define ERTS_TS_QUALLOC_IMPL(NAME, TYPE, PASZ, ALCT) \
+static erts_mtx_t NAME##_lck; \
+ERTS_QUICK_ALLOC_IMPL(NAME, TYPE, PASZ, ALCT, \
+ erts_mtx_init(NAME##_lck, #NAME "_alloc_lock"), \
+ erts_mtx_lock(&NAME##_lck), \
+ erts_mtx_unlock(&NAME##_lck))
+
+
+#endif
+
+#define ERTS_PALLOC_IMPL(NAME, TYPE, PASZ) \
+ERTS_PRE_ALLOC_IMPL(NAME, TYPE, PASZ, (void) 0, (void) 0, (void) 0)
+
+#define ERTS_TS_PALLOC_IMPL(NAME, TYPE, PASZ) \
+static erts_spinlock_t NAME##_lck; \
+ERTS_PRE_ALLOC_IMPL(NAME, TYPE, PASZ, \
+ erts_spinlock_init(&NAME##_lck, #NAME "_alloc_lock"),\
+ erts_spin_lock(&NAME##_lck), \
+ erts_spin_unlock(&NAME##_lck))
+
+#ifdef ERTS_SMP
+
+#define ERTS_SMP_PALLOC_IMPL(NAME, TYPE, PASZ) \
+ ERTS_TS_PALLOC_IMPL(NAME, TYPE, PASZ)
+
+#else /* !ERTS_SMP */
+
+#define ERTS_SMP_PALLOC_IMPL(NAME, TYPE, PASZ) \
+ ERTS_PALLOC_IMPL(NAME, TYPE, PASZ)
+
+#endif
+
+#define ERTS_QUICK_ALLOC_IMPL(NAME, TYPE, PASZ, ALCT, ILCK, LCK, ULCK) \
+ERTS_PRE_ALLOC_IMPL(NAME##_pre, TYPE, PASZ, ILCK, LCK, ULCK) \
+static void \
+init_##NAME##_alloc(void) \
+{ \
+ init_##NAME##_pre_alloc(); \
+} \
+static ERTS_INLINE TYPE * \
+NAME##_alloc(void) \
+{ \
+ TYPE *res = NAME##_pre_alloc(); \
+ if (!res) \
+ res = erts_alloc(ALCT, sizeof(TYPE)); \
+ return res; \
+} \
+static ERTS_INLINE void \
+NAME##_free(TYPE *p) \
+{ \
+ if (!NAME##_pre_free(p)) \
+ erts_free(ALCT, (void *) p); \
+}
+
+#ifdef ERTS_SMP
+#define ERTS_SCHED_PREF_PALLOC_IMPL(NAME, TYPE, PASZ) \
+ ERTS_SCHED_PREF_PRE_ALLOC_IMPL(NAME, TYPE, PASZ)
+#else
+#define ERTS_SCHED_PREF_PALLOC_IMPL(NAME, TYPE, PASZ) \
+ ERTS_PRE_ALLOC_IMPL(NAME, TYPE, PASZ, (void) 0, (void) 0, (void) 0)
+#endif
+
+#ifdef ERTS_SMP
+#define ERTS_SCHED_PREF_AUX(NAME, TYPE, PASZ) \
+ERTS_SCHED_PREF_PRE_ALLOC_IMPL(NAME##_pre, TYPE, PASZ)
+#else
+#define ERTS_SCHED_PREF_AUX(NAME, TYPE, PASZ) \
+ERTS_PRE_ALLOC_IMPL(NAME##_pre, TYPE, PASZ, (void) 0, (void) 0, (void) 0)
+#endif
+
+#define ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(NAME, TYPE, PASZ, ALCT) \
+ERTS_SCHED_PREF_AUX(NAME, TYPE, PASZ) \
+static void \
+init_##NAME##_alloc(void) \
+{ \
+ init_##NAME##_pre_alloc(); \
+} \
+static ERTS_INLINE TYPE * \
+NAME##_alloc(void) \
+{ \
+ TYPE *res = NAME##_pre_alloc(); \
+ if (!res) \
+ res = erts_alloc(ALCT, sizeof(TYPE)); \
+ return res; \
+} \
+static ERTS_INLINE void \
+NAME##_free(TYPE *p) \
+{ \
+ if (!NAME##_pre_free(p)) \
+ erts_free(ALCT, (void *) p); \
+}
+
+#ifdef DEBUG
+#define ERTS_PRE_ALLOC_SIZE(SZ) 2
+#define ERTS_PRE_ALLOC_CLOBBER(P, T) memset((void *) (P), 0xfd, sizeof(T))
+#else
+#define ERTS_PRE_ALLOC_SIZE(SZ) ((SZ) > 1 ? (SZ) : 1)
+#define ERTS_PRE_ALLOC_CLOBBER(P, T)
+#endif
+
+#define ERTS_PRE_ALLOC_IMPL(NAME, TYPE, PASZ, ILCK, LCK, ULCK) \
+union erts_qa_##NAME##__ { \
+ TYPE type; \
+ union erts_qa_##NAME##__ *next; \
+}; \
+static union erts_qa_##NAME##__ \
+ qa_prealcd_##NAME[ERTS_PRE_ALLOC_SIZE((PASZ))]; \
+static union erts_qa_##NAME##__ *qa_freelist_##NAME; \
+static void \
+init_##NAME##_alloc(void) \
+{ \
+ int i; \
+ qa_freelist_##NAME = &qa_prealcd_##NAME[0]; \
+ for (i = 1; i < ERTS_PRE_ALLOC_SIZE((PASZ)); i++) { \
+ ERTS_PRE_ALLOC_CLOBBER(&qa_prealcd_##NAME[i-1], \
+ union erts_qa_##NAME##__); \
+ qa_prealcd_##NAME[i-1].next = &qa_prealcd_##NAME[i]; \
+ } \
+ ERTS_PRE_ALLOC_CLOBBER(&qa_prealcd_##NAME[ERTS_PRE_ALLOC_SIZE((PASZ))-1],\
+ union erts_qa_##NAME##__); \
+ qa_prealcd_##NAME[ERTS_PRE_ALLOC_SIZE((PASZ))-1].next = NULL; \
+ ILCK; \
+} \
+static ERTS_INLINE TYPE * \
+NAME##_alloc(void) \
+{ \
+ TYPE *res; \
+ LCK; \
+ if (!qa_freelist_##NAME) \
+ res = NULL; \
+ else { \
+ res = &qa_freelist_##NAME->type; \
+ qa_freelist_##NAME = qa_freelist_##NAME->next; \
+ } \
+ ULCK; \
+ return res; \
+} \
+static ERTS_INLINE int \
+NAME##_free(TYPE *p) \
+{ \
+ union erts_qa_##NAME##__ * up; \
+ up = ((union erts_qa_##NAME##__ *) \
+ (((char *) p) \
+ - ((char *) &((union erts_qa_##NAME##__ *) 0)->type))); \
+ if (up > &qa_prealcd_##NAME[ERTS_PRE_ALLOC_SIZE((PASZ))-1] \
+ || up < &qa_prealcd_##NAME[0]) \
+ return 0; \
+ else { \
+ LCK; \
+ ERTS_PRE_ALLOC_CLOBBER(up, union erts_qa_##NAME##__); \
+ up->next = qa_freelist_##NAME; \
+ qa_freelist_##NAME = up; \
+ ULCK; \
+ return 1; \
+ } \
+}
+
+typedef struct {
+ void *start;
+ void *end;
+ int chunks_mem_size;
+} erts_sched_pref_quick_alloc_data_t;
+
+#ifdef DEBUG
+#define ERTS_SPPA_DBG_CHK_IN_CHNK(A, C, P) \
+do { \
+ ASSERT((void *) (C) < (void *) (P)); \
+ ASSERT((void *) (P) \
+ < (void *) (((char *) (C)) + (A)->chunks_mem_size)); \
+} while (0)
+#else
+#define ERTS_SPPA_DBG_CHK_IN_CHNK(A, C, P)
+#endif
+
+#define ERTS_SCHED_PREF_PRE_ALLOC_IMPL(NAME, TYPE, PASZ) \
+union erts_qa_##NAME##__ { \
+ TYPE type; \
+ union erts_qa_##NAME##__ *next; \
+}; \
+typedef struct { \
+ erts_smp_spinlock_t lock; \
+ union erts_qa_##NAME##__ *freelist; \
+ union erts_qa_##NAME##__ pre_alloced[1]; \
+} erts_qa_##NAME##_chunk__; \
+static erts_sched_pref_quick_alloc_data_t *qa_data_##NAME##__; \
+static ERTS_INLINE erts_qa_##NAME##_chunk__ * \
+get_##NAME##_chunk_ix(int cix) \
+{ \
+ char *ptr = (char *) qa_data_##NAME##__->start; \
+ ptr += cix*qa_data_##NAME##__->chunks_mem_size; \
+ return (erts_qa_##NAME##_chunk__ *) ptr; \
+} \
+static ERTS_INLINE erts_qa_##NAME##_chunk__ * \
+get_##NAME##_chunk_ptr(void *ptr) \
+{ \
+ int cix; \
+ size_t diff; \
+ if (ptr < qa_data_##NAME##__->start || qa_data_##NAME##__->end <= ptr)\
+ return NULL; \
+ diff = ((char *) ptr) - ((char *) qa_data_##NAME##__->start); \
+ cix = diff / qa_data_##NAME##__->chunks_mem_size; \
+ return get_##NAME##_chunk_ix(cix); \
+} \
+static void \
+init_##NAME##_alloc(void) \
+{ \
+ size_t tot_size; \
+ size_t chunk_mem_size; \
+ char *chunk_start; \
+ int cix; \
+ int no_blocks = ERTS_PRE_ALLOC_SIZE((PASZ)); \
+ int no_blocks_per_chunk = 2*((no_blocks-1)/erts_no_schedulers + 1); \
+ no_blocks = no_blocks_per_chunk * erts_no_schedulers; \
+ chunk_mem_size = sizeof(erts_qa_##NAME##_chunk__); \
+ chunk_mem_size += (sizeof(union erts_qa_##NAME##__) \
+ * (no_blocks_per_chunk - 1)); \
+ chunk_mem_size = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(chunk_mem_size); \
+ tot_size = sizeof(erts_sched_pref_quick_alloc_data_t); \
+ tot_size += ERTS_CACHE_LINE_SIZE - 1; \
+ tot_size += chunk_mem_size*erts_no_schedulers; \
+ qa_data_##NAME##__ = erts_alloc(ERTS_ALC_T_PRE_ALLOC_DATA,tot_size);\
+ chunk_start = (((char *) qa_data_##NAME##__) \
+ + sizeof(erts_sched_pref_quick_alloc_data_t)); \
+ if ((((Uint) chunk_start) & ERTS_CACHE_LINE_MASK) != ((Uint) 0)) \
+ chunk_start = ((char *) \
+ ((((Uint) chunk_start) & ~ERTS_CACHE_LINE_MASK) \
+ + ERTS_CACHE_LINE_SIZE)); \
+ qa_data_##NAME##__->chunks_mem_size = chunk_mem_size; \
+ qa_data_##NAME##__->start = (void *) chunk_start; \
+ qa_data_##NAME##__->end = (chunk_start \
+ + chunk_mem_size*erts_no_schedulers); \
+ for (cix = 0; cix < erts_no_schedulers; cix++) { \
+ int i; \
+ erts_qa_##NAME##_chunk__ *chunk = get_##NAME##_chunk_ix(cix); \
+ erts_smp_spinlock_init(&chunk->lock, #NAME "_alloc_lock"); \
+ chunk->freelist = &chunk->pre_alloced[0]; \
+ for (i = 1; i < no_blocks_per_chunk; i++) { \
+ ERTS_PRE_ALLOC_CLOBBER(&chunk->pre_alloced[i-1], \
+ union erts_qa_##NAME##__); \
+ chunk->pre_alloced[i-1].next = &chunk->pre_alloced[i]; \
+ } \
+ ERTS_PRE_ALLOC_CLOBBER(&chunk->pre_alloced[no_blocks_per_chunk-1],\
+ union erts_qa_##NAME##__); \
+ chunk->pre_alloced[no_blocks_per_chunk-1].next = NULL; \
+ } \
+} \
+static ERTS_INLINE TYPE * \
+NAME##_alloc(void) \
+{ \
+ int cix = ((int) erts_get_scheduler_id()) - 1; \
+ TYPE *res; \
+ if (cix < 0) \
+ res = NULL; \
+ else { \
+ erts_qa_##NAME##_chunk__ *chunk = get_##NAME##_chunk_ix(cix); \
+ erts_smp_spin_lock(&chunk->lock); \
+ if (!chunk->freelist) \
+ res = NULL; \
+ else { \
+ res = &chunk->freelist->type; \
+ chunk->freelist = chunk->freelist->next; \
+ ERTS_SPPA_DBG_CHK_IN_CHNK(qa_data_##NAME##__, chunk, res); \
+ } \
+ erts_smp_spin_unlock(&chunk->lock); \
+ } \
+ return res; \
+} \
+static ERTS_INLINE int \
+NAME##_free(TYPE *p) \
+{ \
+ erts_qa_##NAME##_chunk__ *chunk; \
+ chunk = get_##NAME##_chunk_ptr((void *) p); \
+ if (!chunk) \
+ return 0; \
+ else { \
+ union erts_qa_##NAME##__ *up; \
+ ERTS_SPPA_DBG_CHK_IN_CHNK(qa_data_##NAME##__, chunk, p); \
+ up = ((union erts_qa_##NAME##__ *) \
+ (((char *) p) \
+ - ((char *) &((union erts_qa_##NAME##__ *) 0)->type))); \
+ erts_smp_spin_lock(&chunk->lock); \
+ ERTS_PRE_ALLOC_CLOBBER(up, union erts_qa_##NAME##__); \
+ up->next = chunk->freelist; \
+ chunk->freelist = up; \
+ erts_smp_spin_unlock(&chunk->lock); \
+ return 1; \
+ } \
+}
+
+#ifdef DEBUG
+#define ERTS_ALC_DBG_BLK_SZ(PTR) (*(((Uint *) (PTR)) - 2))
+#endif /* #ifdef DEBUG */
+
+#undef ERTS_ALC_INLINE
+#undef ERTS_ALC_ATTRIBUTES
+
+#endif /* #ifndef ERL_ALLOC_H__ */
+
+