summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorRickard Green <rickard@erlang.org>2020-07-23 17:46:25 +0200
committerRickard Green <rickard@erlang.org>2020-11-03 12:47:49 +0100
commit9f4c1a9ccd33063e64661c287faea780d9db419f (patch)
tree4046a19bf50e9956e81cd732c2d7e228878f61d0 /erts
parentc7b50c83af7ce4e3b111ad2b21897ec5bd57d31c (diff)
downloaderlang-9f4c1a9ccd33063e64661c287faea780d9db419f.tar.gz
Introduce internal references containing pid of creator
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/bif.c27
-rw-r--r--erts/emulator/beam/copy.c2
-rw-r--r--erts/emulator/beam/erl_alloc.c2
-rw-r--r--erts/emulator/beam/erl_alloc.types4
-rw-r--r--erts/emulator/beam/erl_bif_unique.c289
-rw-r--r--erts/emulator/beam/erl_bif_unique.h113
-rw-r--r--erts/emulator/beam/erl_db_util.c5
-rw-r--r--erts/emulator/beam/erl_gc.c4
-rw-r--r--erts/emulator/beam/erl_lock_check.c1
-rw-r--r--erts/emulator/beam/erl_monitor_link.c28
-rw-r--r--erts/emulator/beam/erl_monitor_link.h2
-rw-r--r--erts/emulator/beam/erl_node_container_utils.h9
-rw-r--r--erts/emulator/beam/erl_port.h4
-rw-r--r--erts/emulator/beam/erl_port_task.c2
-rw-r--r--erts/emulator/beam/erl_term.c2
-rw-r--r--erts/emulator/beam/erl_term.h135
-rw-r--r--erts/emulator/beam/external.c82
-rw-r--r--erts/emulator/beam/utils.c2
-rw-r--r--erts/emulator/test/ref_SUITE.erl110
19 files changed, 695 insertions, 128 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 5beab81b98..8256dd5d48 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4341,17 +4341,30 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1)
if (n != ERTS_REF_NUMBERS) goto bad;
sid = erts_get_ref_numbers_thr_id(refn);
if (sid > erts_no_schedulers) goto bad;
- mb = erts_magic_ref_lookup_bin(refn);
- if (mb) {
- hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE);
- res = erts_mk_magic_ref(&hp, &BIF_P->off_heap,
- (Binary *) mb);
- }
- else {
+ if (erts_is_ordinary_ref_numbers(refn)) {
+ make_ordinary_internal_ref:
hp = HAlloc(BIF_P, ERTS_REF_THING_SIZE);
write_ref_thing(hp, refn[0], refn[1], refn[2]);
res = make_internal_ref(hp);
}
+ else {
+ /* Check if it is a pid reference... */
+ Eterm pid = erts_pid_ref_lookup(refn);
+ if (is_internal_pid(pid)) {
+ hp = HAlloc(BIF_P, ERTS_PID_REF_THING_SIZE);
+ write_pid_ref_thing(hp, refn[0], refn[1], refn[2], pid);
+ res = make_internal_ref(hp);
+ }
+ else {
+ /* Check if it is a magic reference... */
+ mb = erts_magic_ref_lookup_bin(refn);
+ if (!mb)
+ goto make_ordinary_internal_ref;
+ hp = HAlloc(BIF_P, ERTS_MAGIC_REF_THING_SIZE);
+ res = erts_mk_magic_ref(&hp, &BIF_P->off_heap,
+ (Binary *) mb);
+ }
+ }
}
else {
ExternalThing *etp;
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index bf7fa6104a..9d13b6eca3 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -2054,7 +2054,7 @@ move_one_frag(Eterm** hpp, ErlHeapFragment* frag, ErlOffHeap* off_heap, int lite
ptr = move_boxed(ptr, val, &hp, &dummy_ref);
switch (val & _HEADER_SUBTAG_MASK) {
case REF_SUBTAG:
- if (is_ordinary_ref_thing(hdr))
+ if (!is_magic_ref_thing(hdr))
break;
case REFC_BINARY_SUBTAG:
case FUN_SUBTAG:
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 47150b2aea..dbfc64cc32 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -664,6 +664,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
= erts_timer_type_size(ERTS_ALC_T_BIF_TIMER);
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_MREF_NSCHED_ENT)]
= sizeof(ErtsNSchedMagicRefTableEntry);
+ fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_PREF_NSCHED_ENT)]
+ = sizeof(ErtsNSchedPidRefTableEntry);
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_MINDIRECTION)]
= ERTS_MAGIC_BIN_UNALIGNED_SIZE(sizeof(ErtsMagicIndirectionWord));
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 48afa71583..1261379afa 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -248,6 +248,10 @@ type MREF_NSCHED_ENT FIXED_SIZE SYSTEM nsched_magic_ref_entry
type MREF_ENT STANDARD SYSTEM magic_ref_entry
type MREF_TAB_BKTS STANDARD SYSTEM magic_ref_table_buckets
type MREF_TAB LONG_LIVED SYSTEM magic_ref_table
+type PREF_NSCHED_ENT FIXED_SIZE SYSTEM nsched_pid_ref_entry
+type PREF_ENT STANDARD SYSTEM pid_ref_entry
+type PREF_TAB_BKTS STANDARD SYSTEM pid_ref_table_buckets
+type PREF_TAB LONG_LIVED SYSTEM pid_ref_table
type MINDIRECTION FIXED_SIZE SYSTEM magic_indirection
type BINARY_FIND SHORT_LIVED PROCESSES binary_find
type CRASH_DUMP STANDARD SYSTEM crash_dump
diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c
index 19d46537f9..90820124f0 100644
--- a/erts/emulator/beam/erl_bif_unique.c
+++ b/erts/emulator/beam/erl_bif_unique.c
@@ -62,6 +62,7 @@ static Uint32 max_thr_id;
#endif
static void init_magic_ref_tables(void);
+static void init_pid_ref_tables(void);
static Uint64 ref_init_value;
@@ -83,6 +84,7 @@ init_reference(void)
erts_atomic64_init_nob(&global_reference.count,
(erts_aint64_t) ref_init_value);
init_magic_ref_tables();
+ init_pid_ref_tables();
}
static ERTS_INLINE void
@@ -144,6 +146,32 @@ Eterm erts_make_ref(Process *c_p)
return make_internal_ref(hp);
}
+static void pid_ref_save(Uint32 refn[ERTS_REF_NUMBERS], Eterm pid);
+
+Eterm erts_make_pid_ref(Process *c_p)
+{
+ Eterm* hp;
+ Uint32 ref[ERTS_REF_NUMBERS];
+ Eterm pid;
+
+ ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(c_p));
+
+ hp = HAlloc(c_p, ERTS_PID_REF_THING_SIZE);
+
+ make_ref_in_array(ref);
+
+ ASSERT(!(ref[1] & ERTS_REF1_PID_MARKER_BIT__));
+ ref[1] |= ERTS_REF1_PID_MARKER_BIT__;
+
+ pid = c_p->common.id;
+
+ write_pid_ref_thing(hp, ref[0], ref[1], ref[2], pid);
+
+ pid_ref_save(ref, pid);
+
+ return make_internal_ref(hp);
+}
+
/*
* Magic reference tables
*/
@@ -412,6 +440,267 @@ void erts_ref_bin_free(ErtsMagicBinary *mb)
}
+/*
+ * Pid reference tables.
+ *
+ * These tables are intended to be temporary until huge
+ * references (containing the pid) can be mandatory in
+ * the external format.
+ */
+
+typedef struct {
+ HashBucket hash;
+ Eterm pid;
+ Uint64 value;
+ Uint32 thr_id;
+} ErtsPidRefTableEntry;
+
+typedef struct {
+ erts_rwmtx_t rwmtx;
+ Hash hash;
+ char name[32];
+} ErtsPidRefTable;
+
+typedef struct {
+ union {
+ ErtsPidRefTable table;
+ char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsPidRefTable))];
+ } u;
+} ErtsAlignedPidRefTable;
+
+ErtsAlignedPidRefTable *pid_ref_table;
+
+Eterm
+erts_pid_ref_lookup__(Uint32 refn[ERTS_REF_NUMBERS])
+{
+ ErtsPidRefTableEntry tmpl;
+ ErtsPidRefTableEntry *tep;
+ ErtsPidRefTable *tblp;
+ Eterm pid;
+
+ ASSERT(erts_is_pid_ref_numbers(refn));
+
+ tmpl.value = erts_get_ref_numbers_value(refn);
+ tmpl.thr_id = erts_get_ref_numbers_thr_id(refn);
+ if (tmpl.thr_id > erts_no_schedulers)
+ tblp = &pid_ref_table[0].u.table;
+ else
+ tblp = &pid_ref_table[tmpl.thr_id].u.table;
+
+ erts_rwmtx_rlock(&tblp->rwmtx);
+
+ tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl);
+ pid = tep ? tep->pid : THE_NON_VALUE;
+
+ erts_rwmtx_runlock(&tblp->rwmtx);
+
+ return pid;
+}
+
+static void
+pid_ref_save(Uint32 refn[ERTS_REF_NUMBERS], Eterm pid)
+{
+ ErtsPidRefTableEntry tmpl;
+ ErtsPidRefTableEntry *tep;
+ ErtsPidRefTable *tblp;
+
+ ASSERT(erts_is_pid_ref_numbers(refn));
+
+ tmpl.value = erts_get_ref_numbers_value(refn);
+ tmpl.thr_id = erts_get_ref_numbers_thr_id(refn);
+ tmpl.pid = pid;
+
+ if (tmpl.thr_id > erts_no_schedulers)
+ tblp = &pid_ref_table[0].u.table;
+ else
+ tblp = &pid_ref_table[tmpl.thr_id].u.table;
+
+ erts_rwmtx_rlock(&tblp->rwmtx);
+
+ tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl);
+
+ erts_rwmtx_runlock(&tblp->rwmtx);
+
+ if (!tep) {
+ ErtsPidRefTableEntry *used_tep;
+
+ ASSERT(tmpl.value == erts_get_ref_numbers_value(refn));
+ ASSERT(tmpl.thr_id == erts_get_ref_numbers_thr_id(refn));
+
+ if (tblp != &pid_ref_table[0].u.table) {
+ tep = erts_alloc(ERTS_ALC_T_PREF_NSCHED_ENT,
+ sizeof(ErtsNSchedPidRefTableEntry));
+ }
+ else {
+ tep = erts_alloc(ERTS_ALC_T_PREF_ENT,
+ sizeof(ErtsPidRefTableEntry));
+ tep->thr_id = tmpl.thr_id;
+ }
+
+ tep->value = tmpl.value;
+ tep->pid = pid;
+
+ erts_rwmtx_rwlock(&tblp->rwmtx);
+
+ used_tep = hash_put(&tblp->hash, tep);
+
+ erts_rwmtx_rwunlock(&tblp->rwmtx);
+
+ if (used_tep != tep) {
+ if (tblp != &pid_ref_table[0].u.table)
+ erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep);
+ else
+ erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep);
+ }
+ }
+}
+
+void
+erts_pid_ref_delete(Eterm ref)
+{
+ ErtsPidRefTableEntry tmpl;
+ ErtsPidRefTableEntry *tep;
+ ErtsPidRefTable *tblp;
+ Uint32 *refn;
+
+ ASSERT(is_internal_pid_ref(ref));
+
+ refn = internal_pid_ref_numbers(ref);
+
+ ASSERT(erts_is_pid_ref_numbers(refn));
+
+ tmpl.value = erts_get_ref_numbers_value(refn);
+ tmpl.thr_id = erts_get_ref_numbers_thr_id(refn);
+
+ if (tmpl.thr_id > erts_no_schedulers)
+ tblp = &pid_ref_table[0].u.table;
+ else
+ tblp = &pid_ref_table[tmpl.thr_id].u.table;
+
+ erts_rwmtx_rlock(&tblp->rwmtx);
+
+ tep = (ErtsPidRefTableEntry *) hash_get(&tblp->hash, &tmpl);
+
+ erts_rwmtx_runlock(&tblp->rwmtx);
+
+ if (tep) {
+
+ ASSERT(tmpl.value == erts_get_ref_numbers_value(refn));
+ ASSERT(tmpl.thr_id == erts_get_ref_numbers_thr_id(refn));
+
+ erts_rwmtx_rwlock(&tblp->rwmtx);
+
+ tep = hash_remove(&tblp->hash, &tmpl);
+ ASSERT(tep);
+
+ erts_rwmtx_rwunlock(&tblp->rwmtx);
+
+ if (tblp != &pid_ref_table[0].u.table)
+ erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep);
+ else
+ erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep);
+ }
+}
+
+static int nsched_preft_cmp(void *ve1, void *ve2)
+{
+ ErtsNSchedPidRefTableEntry *e1 = ve1;
+ ErtsNSchedPidRefTableEntry *e2 = ve2;
+ return e1->value != e2->value;
+}
+
+static int non_nsched_preft_cmp(void *ve1, void *ve2)
+{
+ ErtsPidRefTableEntry *e1 = ve1;
+ ErtsPidRefTableEntry *e2 = ve2;
+ return e1->value != e2->value || e1->thr_id != e2->thr_id;
+}
+
+static HashValue nsched_preft_hash(void *ve)
+{
+ ErtsNSchedPidRefTableEntry *e = ve;
+ return (HashValue) e->value;
+}
+
+static HashValue non_nsched_preft_hash(void *ve)
+{
+ ErtsPidRefTableEntry *e = ve;
+ HashValue h;
+ h = (HashValue) e->thr_id;
+ h *= 268440163;
+ h += (HashValue) e->value;
+ return h;
+}
+
+static void *preft_alloc(void *ve)
+{
+ /*
+ * We allocate the element before
+ * hash_put() and pass it as
+ * template which we get as
+ * input...
+ */
+ return ve;
+}
+
+static void preft_free(void *ve)
+{
+ /*
+ * We free the element ourselves
+ * after hash_remove()...
+ */
+}
+
+static void *preft_meta_alloc(int i, size_t size)
+{
+ return erts_alloc(ERTS_ALC_T_PREF_TAB_BKTS, size);
+}
+
+static void preft_meta_free(int i, void *ptr)
+{
+ erts_free(ERTS_ALC_T_PREF_TAB_BKTS, ptr);
+}
+
+static void
+init_pid_ref_tables(void)
+{
+ HashFunctions hash_funcs;
+ int i;
+ ErtsPidRefTable *tblp;
+
+ pid_ref_table = erts_alloc_permanent_cache_aligned(ERTS_ALC_T_PREF_TAB,
+ (sizeof(ErtsAlignedPidRefTable)
+ * (erts_no_schedulers + 1)));
+
+ hash_funcs.hash = non_nsched_preft_hash;
+ hash_funcs.cmp = non_nsched_preft_cmp;
+
+ hash_funcs.alloc = preft_alloc;
+ hash_funcs.free = preft_free;
+ hash_funcs.meta_alloc = preft_meta_alloc;
+ hash_funcs.meta_free = preft_meta_free;
+ hash_funcs.meta_print = erts_print;
+
+ tblp = &pid_ref_table[0].u.table;
+ erts_snprintf(&tblp->name[0], sizeof(tblp->name),
+ "pid_ref_table_0");
+ hash_init(0, &tblp->hash, &tblp->name[0], 1, hash_funcs);
+ erts_rwmtx_init(&tblp->rwmtx, "pid_ref_table", NIL,
+ ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
+
+ hash_funcs.hash = nsched_preft_hash;
+ hash_funcs.cmp = nsched_preft_cmp;
+
+ for (i = 1; i <= erts_no_schedulers; i++) {
+ ErtsPidRefTable *tblp = &pid_ref_table[i].u.table;
+ erts_snprintf(&tblp->name[0], sizeof(tblp->name),
+ "pid_ref_table_%d", i);
+ hash_init(0, &tblp->hash, &tblp->name[0], 1, hash_funcs);
+ erts_rwmtx_init(&tblp->rwmtx, "pid_ref_table", NIL,
+ ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
+ }
+}
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Unique Integer *
\* */
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index d0c461f653..42d23d6ac4 100644
--- a/erts/emulator/beam/erl_bif_unique.h
+++ b/erts/emulator/beam/erl_bif_unique.h
@@ -33,12 +33,15 @@ void erts_sched_bif_unique_init(ErtsSchedulerData *esdp);
/* reference */
Eterm erts_make_ref(Process *);
+Eterm erts_make_pid_ref(Process *);
Eterm erts_make_ref_in_buffer(Eterm buffer[ERTS_REF_THING_SIZE]);
void erts_make_ref_in_array(Uint32 ref[ERTS_REF_NUMBERS]);
void erts_make_magic_ref_in_array(Uint32 ref[ERTS_REF_NUMBERS]);
void erts_magic_ref_remove_bin(Uint32 refn[ERTS_REF_NUMBERS]);
void erts_magic_ref_save_bin__(Eterm ref);
ErtsMagicBinary *erts_magic_ref_lookup_bin__(Uint32 refn[ERTS_REF_NUMBERS]);
+void erts_pid_ref_delete(Eterm ref);
+Eterm erts_pid_ref_lookup__(Uint32 refn[ERTS_REF_NUMBERS]);
/* strict monotonic counter */
@@ -76,11 +79,12 @@ Eterm erts_debug_make_unique_integer(Process *c_p,
Eterm etval1);
-ERTS_GLB_INLINE void erts_set_ref_numbers(Uint32 ref[ERTS_REF_NUMBERS],
- Uint32 thr_id, Uint64 value);
-ERTS_GLB_INLINE Uint32 erts_get_ref_numbers_thr_id(Uint32 ref[ERTS_REF_NUMBERS]);
-ERTS_GLB_INLINE int erts_is_ref_numbers_magic(Uint32 ref[ERTS_REF_NUMBERS]);
-ERTS_GLB_INLINE Uint64 erts_get_ref_numbers_value(Uint32 ref[ERTS_REF_NUMBERS]);
+ERTS_GLB_INLINE void erts_set_ref_numbers(Uint32 *ref, Uint32 thr_id, Uint64 value);
+ERTS_GLB_INLINE Uint32 erts_get_ref_numbers_thr_id(Uint32 *ref);
+ERTS_GLB_INLINE int erts_is_ref_numbers_magic(Uint32 *ref);
+ERTS_GLB_INLINE int erts_is_pid_ref_numbers(Uint32 *ref);
+ERTS_GLB_INLINE int erts_is_ordinary_ref_numbers(Uint32 *ref);
+ERTS_GLB_INLINE Uint64 erts_get_ref_numbers_value(Uint32 *ref);
ERTS_GLB_INLINE void erts_sched_make_ref_in_array(ErtsSchedulerData *esdp,
Uint32 ref[ERTS_REF_NUMBERS]);
ERTS_GLB_INLINE void erts_sched_make_magic_ref_in_array(ErtsSchedulerData *esdp,
@@ -91,15 +95,20 @@ ERTS_GLB_INLINE Eterm erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *mb
ERTS_GLB_INLINE Binary *erts_magic_ref2bin(Eterm mref);
ERTS_GLB_INLINE void erts_magic_ref_save_bin(Eterm ref);
ERTS_GLB_INLINE ErtsMagicBinary *erts_magic_ref_lookup_bin(Uint32 ref[ERTS_REF_NUMBERS]);
+ERTS_GLB_INLINE Eterm erts_pid_ref_lookup(Uint32 *refn);
#define ERTS_REF1_MAGIC_MARKER_BIT_NO__ \
(_REF_NUM_SIZE-1)
#define ERTS_REF1_MAGIC_MARKER_BIT__ \
(((Uint32) 1) << ERTS_REF1_MAGIC_MARKER_BIT_NO__)
+#define ERTS_REF1_PID_MARKER_BIT_NO__ \
+ (_REF_NUM_SIZE-2)
+#define ERTS_REF1_PID_MARKER_BIT__ \
+ (((Uint32) 1) << ERTS_REF1_PID_MARKER_BIT_NO__)
#define ERTS_REF1_THR_ID_MASK__ \
- (ERTS_REF1_MAGIC_MARKER_BIT__-1)
+ (ERTS_REF1_PID_MARKER_BIT__-1)
#define ERTS_REF1_NUM_MASK__ \
- (~(ERTS_REF1_THR_ID_MASK__|ERTS_REF1_MAGIC_MARKER_BIT__))
+ (~(ERTS_REF1_THR_ID_MASK__|ERTS_REF1_MAGIC_MARKER_BIT__|ERTS_REF1_PID_MARKER_BIT__))
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
@@ -120,19 +129,32 @@ erts_set_ref_numbers(Uint32 ref[ERTS_REF_NUMBERS], Uint32 thr_id, Uint64 value)
}
ERTS_GLB_INLINE Uint32
-erts_get_ref_numbers_thr_id(Uint32 ref[ERTS_REF_NUMBERS])
+erts_get_ref_numbers_thr_id(Uint32 *ref)
{
return ref[1] & ((Uint32) ERTS_REF1_THR_ID_MASK__);
}
ERTS_GLB_INLINE int
-erts_is_ref_numbers_magic(Uint32 ref[ERTS_REF_NUMBERS])
+erts_is_ref_numbers_magic(Uint32 *ref)
{
return !!(ref[1] & ERTS_REF1_MAGIC_MARKER_BIT__);
}
+ERTS_GLB_INLINE int
+erts_is_pid_ref_numbers(Uint32 *ref)
+{
+ return !!(ref[1] & ERTS_REF1_PID_MARKER_BIT__);
+}
+
+ERTS_GLB_INLINE int
+erts_is_ordinary_ref_numbers(Uint32 *ref)
+{
+ return !(ref[1] & (ERTS_REF1_MAGIC_MARKER_BIT__
+ | ERTS_REF1_PID_MARKER_BIT__));
+}
+
ERTS_GLB_INLINE Uint64
-erts_get_ref_numbers_value(Uint32 ref[ERTS_REF_NUMBERS])
+erts_get_ref_numbers_value(Uint32 *ref)
{
ERTS_CT_ASSERT((ERTS_REF1_NUM_MASK__ | REF_MASK) == 0xffffffff);
ERTS_CT_ASSERT((ERTS_REF1_NUM_MASK__ & REF_MASK) == 0);
@@ -218,6 +240,18 @@ erts_magic_ref_lookup_bin(Uint32 ref[ERTS_REF_NUMBERS])
return erts_magic_ref_lookup_bin__(ref);
}
+/*
+ * Look up pid of a pid ref when the ref comes
+ * from the outside world...
+ */
+ERTS_GLB_INLINE Eterm
+erts_pid_ref_lookup(Uint32 *refn)
+{
+ if (!erts_is_pid_ref_numbers(refn))
+ return THE_NON_VALUE;
+ return erts_pid_ref_lookup__(refn);
+}
+
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
@@ -232,14 +266,13 @@ erts_magic_ref_lookup_bin(Uint32 ref[ERTS_REF_NUMBERS])
# error fix this...
#endif
-ERTS_GLB_INLINE int erts_internal_ref_number_cmp(Uint32 num1[ERTS_REF_NUMBERS],
- Uint32 num2[ERTS_REF_NUMBERS]);
+ERTS_GLB_INLINE int erts_internal_ref_number_cmp(Uint32 *num1, Uint32 *num2);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
ERTS_GLB_INLINE int
-erts_internal_ref_number_cmp(Uint32 num1[ERTS_REF_NUMBERS],
- Uint32 num2[ERTS_REF_NUMBERS])
+erts_internal_ref_number_cmp(Uint32 *num1,
+ Uint32 *num2)
{
if (num1[2] != num2[2])
return num1[2] > num2[2] ? 1 : -1;
@@ -254,10 +287,11 @@ erts_internal_ref_number_cmp(Uint32 num1[ERTS_REF_NUMBERS],
/* Iref storage for all internal references... */
typedef struct {
- Uint32 is_magic;
+ Uint16 is_magic;
+ Uint16 is_pid_ref;
union {
ErtsMagicBinary *mb;
- Uint32 num[ERTS_REF_NUMBERS];
+ Uint32 num[ERTS_MAX_INTERNAL_REF_NUMBERS];
} u;
} ErtsIRefStorage;
@@ -285,13 +319,35 @@ erts_iref_storage_save(ErtsIRefStorage *iref, Eterm ref)
hp = boxed_val(ref);
+ iref->is_magic = 0;
+ iref->is_pid_ref = 0;
if (is_ordinary_ref_thing(hp)) {
ErtsORefThing *rtp = (ErtsORefThing *) hp;
- iref->is_magic = 0;
iref->u.num[0] = rtp->num[0];
iref->u.num[1] = rtp->num[1];
iref->u.num[2] = rtp->num[2];
}
+ else if (is_pid_ref_thing(hp)) {
+ ErtsPRefThing *prtp = (ErtsPRefThing *) hp;
+ iref->is_pid_ref = 1;
+ iref->u.num[0] = prtp->num[0];
+ iref->u.num[1] = prtp->num[1];
+ iref->u.num[2] = prtp->num[2];
+ iref->u.num[3] = prtp->num[3];
+#if defined(ARCH_64)
+ iref->u.num[4] = prtp->num[4];
+
+# if ERTS_PID_REF_NUMBERS != 5
+# error fix this
+# endif
+
+#else /* ARCH_32 */
+
+# if ERTS_PID_REF_NUMBERS != 4
+# error fix this
+# endif
+#endif
+ }
else {
ErtsMRefThing *mrtp = (ErtsMRefThing *) hp;
ASSERT(is_magic_ref_thing(hp));
@@ -314,7 +370,11 @@ erts_iref_storage_clean(ErtsIRefStorage *iref)
ERTS_GLB_INLINE Uint
erts_iref_storage_heap_size(ErtsIRefStorage *iref)
{
- return iref->is_magic ? ERTS_MAGIC_REF_THING_SIZE : ERTS_REF_THING_SIZE;
+ if (iref->is_magic)
+ return ERTS_MAGIC_REF_THING_SIZE;
+ if (iref->is_pid_ref)
+ return ERTS_PID_REF_THING_SIZE;
+ return ERTS_REF_THING_SIZE;
}
ERTS_GLB_INLINE Eterm
@@ -323,11 +383,20 @@ erts_iref_storage_make_ref(ErtsIRefStorage *iref,
int clean_storage)
{
Eterm *hp = *hpp;
- if (!iref->is_magic) {
+ if (!iref->is_magic && !iref->is_pid_ref) {
write_ref_thing(hp, iref->u.num[0], iref->u.num[1],
iref->u.num[2]);
*hpp += ERTS_REF_THING_SIZE;
}
+ else if (iref->is_pid_ref) {
+ Eterm pid = (Eterm) iref->u.num[3];
+#if defined(ARCH_64)
+ pid |= ((Eterm) iref->u.num[4]) << 32;
+#endif
+ write_pid_ref_thing(hp, iref->u.num[0], iref->u.num[1],
+ iref->u.num[2], pid);
+ *hpp += ERTS_PID_REF_THING_SIZE;
+ }
else {
write_magic_ref_thing(hp, ohp, iref->u.mb);
OH_OVERHEAD(ohp, iref->u.mb->orig_size / sizeof(Eterm));
@@ -437,4 +506,10 @@ typedef struct {
Uint64 value;
} ErtsNSchedMagicRefTableEntry;
+typedef struct {
+ HashBucket hash;
+ Eterm pid;
+ Uint64 value;
+} ErtsNSchedPidRefTableEntry;
+
#endif
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 2087e1c337..ae4574a93d 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -5549,6 +5549,11 @@ void db_match_dis(Binary *bp)
num = rt->num;
t += TermWords(ERTS_REF_THING_SIZE);
}
+ else if (is_pid_ref_thing(t)) {
+ ErtsPRefThing *prt = (ErtsPRefThing *) t;
+ num = prt->num;
+ t += TermWords(ERTS_PID_REF_THING_SIZE);
+ }
else {
ErtsMRefThing *mrt = (ErtsMRefThing *) t;
ASSERT(is_magic_ref_thing(t));
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 61b4b81668..c035c0a386 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -2505,7 +2505,7 @@ erts_copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap,
case ARITYVAL_SUBTAG:
break;
case REF_SUBTAG:
- if (is_ordinary_ref_thing(fhp - 1))
+ if (!is_magic_ref_thing(fhp - 1))
goto the_default;
case REFC_BINARY_SUBTAG:
case FUN_SUBTAG:
@@ -3139,7 +3139,7 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
tari = thing_arityval(val);
switch (thing_subtag(val)) {
case REF_SUBTAG:
- if (is_ordinary_ref_thing(hp))
+ if (!is_magic_ref_thing(hp))
break;
case REFC_BINARY_SUBTAG:
case FUN_SUBTAG:
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 9c0ebaa9d1..b30c494428 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -146,6 +146,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "tracer_mtx", NULL },
{ "port_table", NULL },
{ "magic_ref_table", "address" },
+ { "pid_ref_table", "address" },
{ "mtrace_op", NULL },
{ "instr_x", NULL },
{ "instr", NULL },
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c
index 432e895116..70a793fd81 100644
--- a/erts/emulator/beam/erl_monitor_link.c
+++ b/erts/emulator/beam/erl_monitor_link.c
@@ -104,6 +104,7 @@ ml_cmp_keys(Eterm key1, Eterm key2)
|| is_small(key1)
|| is_external_pid(key1)
|| is_internal_ordinary_ref(key1)
+ || is_internal_pid_ref(key1)
|| is_external_ref(key1));
ERTS_ML_ASSERT(is_internal_pid(key2)
@@ -112,6 +113,7 @@ ml_cmp_keys(Eterm key1, Eterm key2)
|| is_small(key2)
|| is_external_pid(key2)
|| is_internal_ordinary_ref(key2)
+ || is_internal_pid_ref(key2)
|| is_external_ref(key2));
if (is_immed(key1)) {
@@ -154,19 +156,21 @@ ml_cmp_keys(Eterm key1, Eterm key2)
w1 = boxed_val(key1);
hdr1 = *w1;
- if ((hdr1 & _TAG_HEADER_MASK) == _TAG_HEADER_REF) {
+ if (is_ref_thing_header(hdr1)) {
Eterm *w2;
+ ERTS_ML_ASSERT(is_ordinary_ref_thing(w1) || is_pid_ref_thing(w1));
+
if (!is_internal_ref(key2))
return is_immed(key2) ? 1 : -1;
w2 = internal_ref_val(key2);
- ERTS_ML_ASSERT(w1[0] == ERTS_REF_THING_HEADER);
- ERTS_ML_ASSERT(w2[0] == ERTS_REF_THING_HEADER);
+ ERTS_ML_ASSERT(is_ordinary_ref_thing(w2) || is_pid_ref_thing(w2));
- return sys_memcmp((void *) &w1[1], (void *) &w2[1],
- (ERTS_REF_THING_SIZE - 1)*sizeof(Eterm));
+ return sys_memcmp((void *) internal_non_magic_ref_thing_numbers(w1),
+ (void *) internal_non_magic_ref_thing_numbers(w2),
+ ERTS_REF_NUMBERS*sizeof(Uint32));
}
ERTS_ML_ASSERT(is_external(key1));
@@ -794,22 +798,24 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name)
case ERTS_MON_TYPE_PORT:
if (is_nil(name)) {
ErtsMonitorDataHeap *mdhp;
- ErtsORefThing *ortp;
+ Eterm *ref_thing;
case ERTS_MON_TYPE_TIME_OFFSET:
ERTS_ML_ASSERT(is_nil(name));
ERTS_ML_ASSERT(is_immed(orgn) && is_immed(trgt));
- ERTS_ML_ASSERT(is_internal_ordinary_ref(ref));
+ ERTS_ML_ASSERT(is_internal_ordinary_ref(ref)
+ || is_internal_pid_ref(ref));
mdhp = erts_alloc(ERTS_ALC_T_MONITOR, sizeof(ErtsMonitorDataHeap));
mdp = &mdhp->md;
ERTS_ML_ASSERT(((void *) mdp) == ((void *) mdhp));
- ortp = (ErtsORefThing *) (char *) internal_ref_val(ref);
- mdhp->oref_thing = *ortp;
- mdp->ref = make_internal_ref(&mdhp->oref_thing.header);
-
+ ref_thing = internal_ref_val(ref);
+ sys_memcpy((void *) &mdhp->ref_heap[0],
+ (void *) ref_thing,
+ sizeof(Eterm)*(1 + thing_arityval(*ref_thing)));
+ mdp->ref = make_internal_ref(&mdhp->ref_heap[0]);
mdp->origin.other.item = trgt;
mdp->origin.offset = (Uint16) offsetof(ErtsMonitorData, origin);
mdp->origin.key_offset = (Uint16) offsetof(ErtsMonitorData, ref);
diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h
index 15c0676988..b5bdfa24ed 100644
--- a/erts/emulator/beam/erl_monitor_link.h
+++ b/erts/emulator/beam/erl_monitor_link.h
@@ -648,7 +648,7 @@ typedef struct {
typedef struct {
ErtsMonitorData md;
- ErtsORefThing oref_thing;
+ Eterm ref_heap[ERTS_MAX_INTERNAL_REF_SIZE];
} ErtsMonitorDataHeap;
typedef struct ErtsMonitorDataExtended__ ErtsMonitorDataExtended;
diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h
index eb23e1eaa5..759128c614 100644
--- a/erts/emulator/beam/erl_node_container_utils.h
+++ b/erts/emulator/beam/erl_node_container_utils.h
@@ -256,10 +256,11 @@ extern ErtsPTab erts_port;
\* */
#define internal_ref_no_numbers(x) ERTS_REF_NUMBERS
-#define internal_ref_numbers(x) (is_internal_ordinary_ref((x)) \
- ? internal_ordinary_ref_numbers((x)) \
- : (ASSERT(is_internal_magic_ref((x))), \
- internal_magic_ref_numbers((x))))
+#define internal_ref_numbers(x) (is_internal_magic_ref((x)) \
+ ? internal_magic_ref_numbers((x)) \
+ : internal_non_magic_ref_numbers((x)))
+
+
#if defined(ARCH_64)
#define external_ref_no_numbers(x) \
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 9983a22f56..b557becbfa 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -172,7 +172,7 @@ struct _erl_drv_port {
struct {
Eterm to;
- Uint32 ref[ERTS_MAX_REF_NUMBERS];
+ Uint32 ref[ERTS_REF_NUMBERS];
} *async_open_port; /* Reference used with async open port */
};
@@ -873,7 +873,7 @@ enum {
struct ErtsProc2PortSigData_ {
int flags;
Eterm caller;
- Uint32 ref[ERTS_MAX_REF_NUMBERS];
+ Uint32 ref[ERTS_REF_NUMBERS];
union {
struct {
Eterm from;
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 3b56e5b574..46d6a2e000 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -115,7 +115,7 @@ struct ErtsPortTask_ {
ErtsPortTask *next;
ErtsPortTaskHandle *handle;
int flags;
- Uint32 ref[ERTS_MAX_REF_NUMBERS];
+ Uint32 ref[ERTS_REF_NUMBERS];
ErtsPortTaskTypeData td;
} alive;
ErtsThrPrgrLaterOp release;
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index d904e35e40..533dde8148 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -132,7 +132,7 @@ ET_DEFINE_CHECKED(struct erl_node_*,internal_pid_node,Eterm,is_internal_pid);
ET_DEFINE_CHECKED(struct erl_node_*,internal_port_node,Eterm,is_internal_port);
ET_DEFINE_CHECKED(Eterm*,internal_ref_val,Wterm,is_internal_ref);
ET_DEFINE_CHECKED(Uint32*,internal_magic_ref_numbers,Wterm,is_internal_magic_ref);
-ET_DEFINE_CHECKED(Uint32*,internal_ordinary_ref_numbers,Wterm,is_internal_ordinary_ref);
+ET_DEFINE_CHECKED(Uint32*,internal_non_magic_ref_numbers,Wterm,is_internal_non_magic_ref);
ET_DEFINE_CHECKED(struct erl_node_*,internal_ref_node,Eterm,is_internal_ref);
ET_DEFINE_CHECKED(Eterm*,external_val,Wterm,is_external);
ET_DEFINE_CHECKED(Uint,external_data_words,Wterm,is_external);
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index f5771705ff..70e2c4a152 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -717,8 +717,14 @@ _ET_DECLARE_CHECKED(struct erl_node_*,internal_port_node,Eterm)
/* Old maximum number of references in the system */
#define MAX_REFERENCE (1 << _REF_NUM_SIZE)
#define REF_MASK (~(~((Uint)0) << _REF_NUM_SIZE))
-#define ERTS_MAX_REF_NUMBERS 5
#define ERTS_REF_NUMBERS 3
+#if defined(ARCH_64)
+#define ERTS_PID_REF_NUMBERS (ERTS_REF_NUMBERS + 2)
+#else
+#define ERTS_PID_REF_NUMBERS (ERTS_REF_NUMBERS + 1)
+#endif
+#define ERTS_MAX_INTERNAL_REF_NUMBERS ERTS_PID_REF_NUMBERS
+#define ERTS_MAX_REF_NUMBERS 5
#ifndef ERTS_ENDIANNESS
# error ERTS_ENDIANNESS not defined...
@@ -747,6 +753,17 @@ typedef struct {
typedef struct {
Eterm header;
+#if ERTS_ENDIANNESS <= 0
+ Uint32 marker;
+#endif
+ Uint32 num[ERTS_PID_REF_NUMBERS];
+#if ERTS_ENDIANNESS > 0
+ Uint32 marker;
+#endif
+} ErtsPRefThing;
+
+typedef struct {
+ Eterm header;
struct magic_binary *mb;
struct erl_off_heap_header* next;
#if !ERTS_ENDIANNESS
@@ -790,11 +807,12 @@ typedef struct {
* +--------------+--------------+
*
* Both pointers in the magic ref are 64-bit aligned. That is,
- * least significant bits are zero. The marker 32-bit word is
- * placed over the least significant bits of one of the pointers.
- * That is, we can distinguish between magic and ordinary ref
- * by looking at the marker field.
- *
+ * least significant bits are zero. The marker 32-bit word of
+ * an ordinary ref is placed over the least significant bits
+ * of one of the pointers. That is, we can distinguish between
+ * magic and ordinary ref by looking at the marker field.
+ * Pid refs are larger than ordinary and magic refs, so we
+ * can distinguish pid refs from the other by the header word.
*/
#define write_ref_thing(Hp, R0, R1, R2) \
@@ -835,6 +853,23 @@ do { \
#endif /* !ERTS_ENDIANNESS */
+#define write_pid_ref_thing(Hp, R0, R1, R2, PID) \
+do { \
+ ((ErtsPRefThing *) (Hp))->header = ERTS_PID_REF_THING_HEADER; \
+ ((ErtsPRefThing *) (Hp))->marker = ERTS_ORDINARY_REF_MARKER; \
+ ((ErtsPRefThing *) (Hp))->num[0] = (R0); \
+ ((ErtsPRefThing *) (Hp))->num[1] = (R1); \
+ ((ErtsPRefThing *) (Hp))->num[2] = (R2); \
+ ((ErtsPRefThing *) (Hp))->num[3] = (Uint32) ((PID) & 0xffffffff); \
+ ((ErtsPRefThing *) (Hp))->num[4] = (Uint32) (((PID) >> 32) \
+ & 0xffffffff); \
+} while (0)
+
+#define pid_ref_thing_get_pid(Hp) \
+ (ASSERT(is_pid_ref_thing((Hp))), \
+ (((Eterm) ((ErtsPRefThing *) (Hp))->num[3]) \
+ | ((((Eterm) ((ErtsPRefThing *) (Hp))->num[4]) << 32))))
+
#else /* ARCH_32 */
typedef struct {
@@ -844,6 +879,11 @@ typedef struct {
typedef struct {
Eterm header;
+ Uint32 num[ERTS_PID_REF_NUMBERS];
+} ErtsPRefThing;
+
+typedef struct {
+ Eterm header;
struct magic_binary *mb;
struct erl_off_heap_header* next;
} ErtsMRefThing;
@@ -866,11 +906,26 @@ do { \
ASSERT(erts_is_ref_numbers_magic((Binp)->refn)); \
} while (0)
+#define write_pid_ref_thing(Hp, R0, R1, R2, PID) \
+do { \
+ ((ErtsPRefThing *) (Hp))->header = ERTS_PID_REF_THING_HEADER; \
+ ((ErtsPRefThing *) (Hp))->num[0] = (R0); \
+ ((ErtsPRefThing *) (Hp))->num[1] = (R1); \
+ ((ErtsPRefThing *) (Hp))->num[2] = (R2); \
+ ((ErtsPRefThing *) (Hp))->num[3] = (Uint32) (PID); \
+} while (0)
+
+#define pid_ref_thing_get_pid(Hp) \
+ (ASSERT(is_pid_ref_thing((Hp))), \
+ ((Eterm) ((ErtsPRefThing *) (Hp))->num[3]))
+
+
#endif /* ARCH_32 */
typedef union {
ErtsMRefThing m;
ErtsORefThing o;
+ ErtsPRefThing p;
} ErtsRefThing;
/* for copy sharing */
@@ -880,6 +935,7 @@ typedef union {
#define BOXED_SHARED_PROCESSED ((Eterm) 3)
#define ERTS_REF_THING_SIZE (sizeof(ErtsORefThing)/sizeof(Uint))
+#define ERTS_PID_REF_THING_SIZE (sizeof(ErtsPRefThing)/sizeof(Uint))
#define ERTS_MAGIC_REF_THING_SIZE (sizeof(ErtsMRefThing)/sizeof(Uint))
#define ERTS_MAX_INTERNAL_REF_SIZE (sizeof(ErtsRefThing)/sizeof(Uint))
@@ -887,56 +943,54 @@ typedef union {
_make_header((Words)-1,_TAG_HEADER_REF)
#define ERTS_REF_THING_HEADER _make_header(ERTS_REF_THING_SIZE-1,_TAG_HEADER_REF)
+#define ERTS_PID_REF_THING_HEADER _make_header(ERTS_PID_REF_THING_SIZE-1,_TAG_HEADER_REF)
-#if defined(ARCH_64) && ERTS_ENDIANNESS /* All internal refs of same size... */
+# define is_ref_thing_header(x) \
+ (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_REF)
+
+#if defined(ARCH_64) && ERTS_ENDIANNESS
+/* Ordinary and magic refs of same size, but pid ref larger */
# undef ERTS_MAGIC_REF_THING_HEADER
-# define is_ref_thing_header(x) ((x) == ERTS_REF_THING_HEADER)
+#define is_pid_ref_thing(x) \
+ (*((Eterm *)(x)) == ERTS_PID_REF_THING_HEADER)
-#ifdef SHCOPY
-#define is_ordinary_ref_thing(x) \
- (((ErtsRefThing *) (x))->o.marker == ERTS_ORDINARY_REF_MARKER)
-#else
-#define is_ordinary_ref_thing(x) \
- (ASSERT(is_ref_thing_header((*((Eterm *)(x))) & ~BOXED_VISITED_MASK)), \
- ((ErtsRefThing *) (x))->o.marker == ERTS_ORDINARY_REF_MARKER)
-#endif
+#define is_ordinary_ref_thing(x) \
+ ((*((Eterm *)(x)) == ERTS_REF_THING_HEADER) \
+ & (((ErtsRefThing *) (x))->o.marker == ERTS_ORDINARY_REF_MARKER))
#define is_magic_ref_thing(x) \
- (!is_ordinary_ref_thing((x)))
-
-#define is_internal_magic_ref(x) \
- ((_unchecked_is_boxed((x)) && *boxed_val((x)) == ERTS_REF_THING_HEADER) \
- && is_magic_ref_thing(boxed_val((x))))
-
-#define is_internal_ordinary_ref(x) \
- ((_unchecked_is_boxed((x)) && *boxed_val((x)) == ERTS_REF_THING_HEADER) \
- && is_ordinary_ref_thing(boxed_val((x))))
+ ((*((Eterm *)(x)) == ERTS_REF_THING_HEADER) \
+ & (((ErtsRefThing *) (x))->o.marker != ERTS_ORDINARY_REF_MARKER))
#else /* Ordinary and magic references of different sizes... */
# define ERTS_MAGIC_REF_THING_HEADER \
_make_header(ERTS_MAGIC_REF_THING_SIZE-1,_TAG_HEADER_REF)
-# define is_ref_thing_header(x) \
- (((x) & _TAG_HEADER_MASK) == _TAG_HEADER_REF)
-
#define is_ordinary_ref_thing(x) \
- (ASSERT(is_ref_thing_header(*((Eterm *)(x)))), \
- *((Eterm *)(x)) == ERTS_REF_THING_HEADER)
+ (*((Eterm *)(x)) == ERTS_REF_THING_HEADER)
+
+#define is_pid_ref_thing(x) \
+ (*((Eterm *)(x)) == ERTS_PID_REF_THING_HEADER)
#define is_magic_ref_thing(x) \
- (ASSERT(is_ref_thing_header(*((Eterm *)(x)))), \
- *((Eterm *)(x)) == ERTS_MAGIC_REF_THING_HEADER)
+ (*((Eterm *)(x)) == ERTS_MAGIC_REF_THING_HEADER)
+
+#endif
#define is_internal_magic_ref(x) \
- (_unchecked_is_boxed((x)) && *boxed_val((x)) == ERTS_MAGIC_REF_THING_HEADER)
+ (_unchecked_is_boxed((x)) && is_magic_ref_thing(boxed_val((x))))
+
+#define is_internal_non_magic_ref(x) \
+ (is_internal_ordinary_ref((x)) || is_internal_pid_ref((x)))
#define is_internal_ordinary_ref(x) \
- (_unchecked_is_boxed((x)) && *boxed_val((x)) == ERTS_REF_THING_HEADER)
+ (_unchecked_is_boxed((x)) && is_ordinary_ref_thing(boxed_val((x))))
-#endif
+#define is_internal_pid_ref(x) \
+ (_unchecked_is_boxed((x)) && is_pid_ref_thing(boxed_val((x))))
#define make_internal_ref(x) make_boxed((Eterm*)(x))
@@ -960,10 +1014,13 @@ typedef union {
_ET_DECLARE_CHECKED(Eterm*,internal_ref_val,Wterm)
#define internal_ref_val(x) _ET_APPLY(internal_ref_val,(x))
-#define internal_ordinary_thing_ref_numbers(ort) (((ErtsORefThing *)(ort))->num)
-#define _unchecked_internal_ordinary_ref_numbers(x) (internal_ordinary_thing_ref_numbers(_unchecked_ordinary_ref_thing_ptr(x)))
-_ET_DECLARE_CHECKED(Uint32*,internal_ordinary_ref_numbers,Wterm)
-#define internal_ordinary_ref_numbers(x) _ET_APPLY(internal_ordinary_ref_numbers,(x))
+#define internal_non_magic_ref_thing_numbers(rt) (((ErtsORefThing *)(rt))->num)
+#define _unchecked_internal_non_magic_ref_numbers(x) (internal_non_magic_ref_thing_numbers(_unchecked_ordinary_ref_thing_ptr(x)))
+_ET_DECLARE_CHECKED(Uint32*,internal_non_magic_ref_numbers,Wterm)
+#define internal_non_magic_ref_numbers(x) _ET_APPLY(internal_non_magic_ref_numbers,(x))
+
+#define internal_ordinary_ref_numbers(x) internal_non_magic_ref_numbers((x))
+#define internal_pid_ref_numbers(x) internal_non_magic_ref_numbers((x))
#if defined(ARCH_64) && !ERTS_ENDIANNESS
#define internal_magic_thing_ref_numbers(mrt) (((ErtsMRefThing *)(mrt))->num)
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 1a29904f5e..7d4c4712f7 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -4383,14 +4383,15 @@ dec_term_atom_common:
r0 = get_int32(ep);
ep += 4;
- ref_ext_common: {
- ErtsORefThing *rtp;
+ ref_ext_common:
if (ref_words > ERTS_MAX_REF_NUMBERS)
goto error;
node = dec_get_node(sysname, cre, make_boxed(hp));
if(node == erts_this_node) {
+ Eterm *rtp = hp;
+ Uint32 ref_num_buf[ERTS_MAX_REF_NUMBERS];
if (r0 >= MAX_REFERENCE) {
/*
* Must reject local refs with more than 18 bits
@@ -4398,9 +4399,13 @@ dec_term_atom_common:
*/
goto error;
}
-
- rtp = (ErtsORefThing *) hp;
- ref_num = &rtp->num[0];
+
+ ref_num = &ref_num_buf[0];
+ ref_num[0] = r0;
+ for(i = 1; i < ref_words; i++) {
+ ref_num[i] = get_int32(ep);
+ ep += 4;
+ }
if (ref_words != ERTS_REF_NUMBERS) {
int i;
if (ref_words > ERTS_REF_NUMBERS)
@@ -4408,17 +4413,36 @@ dec_term_atom_common:
for (i = ref_words; i < ERTS_REF_NUMBERS; i++)
ref_num[i] = 0;
}
-
-#ifdef ERTS_ORDINARY_REF_MARKER
- rtp->marker = ERTS_ORDINARY_REF_MARKER;
-#endif
- hp += ERTS_REF_THING_SIZE;
- rtp->header = ERTS_REF_THING_HEADER;
+ if (erts_is_ordinary_ref_numbers(ref_num)) {
+ make_ordinary_internal_ref:
+ write_ref_thing(hp, ref_num[0], ref_num[1], ref_num[2]);
+ hp += ERTS_REF_THING_SIZE;
+ }
+ else {
+ /* Check if it is a pid reference... */
+ Eterm pid = erts_pid_ref_lookup(ref_num);
+ if (is_internal_pid(pid)) {
+ write_pid_ref_thing(hp, ref_num[0], ref_num[1],
+ ref_num[2], pid);
+ hp += ERTS_PID_REF_THING_SIZE;
+ }
+ else {
+ /* Check if it is a magic reference... */
+ ErtsMagicBinary *mb = erts_magic_ref_lookup_bin(ref_num);
+ if (!mb)
+ goto make_ordinary_internal_ref;
+ /* Refc on binary was increased by lookup above... */
+ ASSERT(rtp);
+ write_magic_ref_thing(hp, factory->off_heap, mb);
+ OH_OVERHEAD(factory->off_heap,
+ mb->orig_size / sizeof(Eterm));
+ hp += ERTS_MAGIC_REF_THING_SIZE;
+ }
+ }
*objp = make_internal_ref(rtp);
}
else {
ExternalThing *etp = (ExternalThing *) hp;
- rtp = NULL;
#if defined(ARCH_64)
hp += EXTERNAL_THING_HEAD_SIZE + ref_words/2 + 1;
#else
@@ -4439,37 +4463,19 @@ dec_term_atom_common:
#if defined(ARCH_64)
*(ref_num++) = ref_words /* 32-bit arity */;
#endif
- }
- ref_num[0] = r0;
+ ref_num[0] = r0;
- for(i = 1; i < ref_words; i++) {
- ref_num[i] = get_int32(ep);
- ep += 4;
- }
+ for(i = 1; i < ref_words; i++) {
+ ref_num[i] = get_int32(ep);
+ ep += 4;
+ }
#if defined(ARCH_64)
- if ((1 + ref_words) % 2)
- ref_num[ref_words] = 0;
+ if ((1 + ref_words) % 2)
+ ref_num[ref_words] = 0;
#endif
- if (node == erts_this_node) {
- /* Check if it was a magic reference... */
- ErtsMagicBinary *mb = erts_magic_ref_lookup_bin(ref_num);
- if (mb) {
- /*
- * Was a magic ref; adjust it...
- *
- * Refc on binary was increased by lookup above...
- */
- ASSERT(rtp);
- hp = (Eterm *) rtp;
- write_magic_ref_thing(hp, factory->off_heap, mb);
- OH_OVERHEAD(factory->off_heap,
- mb->orig_size / sizeof(Eterm));
- hp += ERTS_MAGIC_REF_THING_SIZE;
- }
- }
- break;
}
+ break;
}
case BINARY_EXT:
{
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index d1731ae092..e4f7542fa8 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -3921,7 +3921,7 @@ store_external_or_ref_(Uint **hpp, ErlOffHeap* oh, Eterm ns)
ASSERT(is_external(ns));
erts_ref_node_entry(etp->node, 2, make_boxed(to_hp));
}
- else if (is_ordinary_ref_thing(from_hp))
+ else if (!is_magic_ref_thing(from_hp))
return make_internal_ref(to_hp);
else {
ErtsMRefThing *mreft = (ErtsMRefThing *) from_hp;
diff --git a/erts/emulator/test/ref_SUITE.erl b/erts/emulator/test/ref_SUITE.erl
index 925c30caa5..a3fb96a6aa 100644
--- a/erts/emulator/test/ref_SUITE.erl
+++ b/erts/emulator/test/ref_SUITE.erl
@@ -23,6 +23,9 @@
-export([all/0, suite/0]).
-export([wrap_1/1]).
-export([compare_list/1, compare_ets/1]).
+-export([internal_size/1, external_size/1]).
+
+-export([init_per_testcase/2, end_per_testcase/2]).
-export([loop_ref/1]).
@@ -32,8 +35,14 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {minutes, 2}}].
+init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
+ [{testcase, Func}|Config].
+
+end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
+ ok.
+
all() ->
- [wrap_1, compare_list, compare_ets].
+ [wrap_1, compare_list, compare_ets, internal_size, external_size].
%% Check that refs don't wrap around easily.
wrap_1(Config) when is_list(Config) ->
@@ -79,3 +88,102 @@ compare_ets(Config) when is_list(Config) ->
ets:insert(Ets, [{Ref,Ref} || Ref <- Refs]),
0 = length([R || R <- ets:tab2list(Ets), ets:lookup(Ets, element(1,R)) == []]),
ok.
+
+internal_size(Config) when is_list(Config) ->
+ %% Verifies that the range of heap size used for internal references
+ %% matches what the documentation say in the advanced chapter of the
+ %% efficiency guide. Note that the values in the efficiency guide
+ %% also add the word referencing the heap structure.
+
+ %% Ordinary internal reference
+ ORef = check_internal_size(make_ref()),
+ io:format("ORef = ~p~n", [ORef]),
+
+ %% Internal pid reference (reference containing a pid)
+ PRef = check_internal_size(alias()),
+ io:format("PRef = ~p~n", [PRef]),
+
+ %% Internal magic reference
+ MRef = check_internal_size(ets:new(blipp, [])),
+ io:format("MRef = ~p~n", [MRef]),
+
+ ok.
+
+check_internal_size(Ref) when is_reference(Ref), node(Ref) == node() ->
+ case erlang:system_info(wordsize) of
+ 4 ->
+ case erts_debug:size(Ref) of
+ Sz when 3 =< Sz, Sz =< 6 ->
+ Sz;
+ Sz ->
+ error({internal_ref_size_out_of_range, Sz})
+ end;
+ 8 ->
+ case erts_debug:size(Ref) of
+ Sz when 3 =< Sz, Sz =< 5 ->
+ Sz;
+ Sz ->
+ error({internal_ref_size_out_of_range, Sz})
+ end
+ end.
+
+external_size(Config) when is_list(Config) ->
+ %% Verifies that the range of heap size used for external references
+ %% matches what the documentation say in the advanced chapter of the
+ %% efficiency guide. Note that the values in the efficiency guide
+ %% also add the word referencing the heap structure.
+ {ok, Node} = start_node(Config),
+
+ %% Ordinary external reference
+ ORef = check_external_size(erpc:call(Node, fun () -> make_ref() end)),
+ io:format("ORef = ~p~n", [ORef]),
+
+ %% External pid reference (reference containing a pid) (nothing produce
+ %% this yet, but we need to handle it)
+ PRef = check_external_size(erts_test_utils:mk_ext_ref({Node, 4711},
+ [1, 2, 3, 4, 5])),
+ io:format("PRef = ~p~n", [PRef]),
+
+
+ stop_node(Node),
+ ok.
+
+check_external_size(Ref) when is_reference(Ref) ->
+ case erlang:system_info(wordsize) of
+ 4 ->
+ case erts_debug:size(Ref) of
+ Sz when 6 =< Sz, Sz =< 8 ->
+ Sz;
+ Sz ->
+ error({internal_ref_size_out_of_range, Sz})
+ end;
+ 8 ->
+ case erts_debug:size(Ref) of
+ Sz when 5 =< Sz, Sz =< 6 ->
+ Sz;
+ Sz ->
+ error({internal_ref_size_out_of_range, Sz})
+ end
+ end.
+
+%% Internal stuff...
+
+make_nodename(Config) when is_list(Config) ->
+ list_to_atom(atom_to_list(?MODULE)
+ ++ "-"
+ ++ atom_to_list(proplists:get_value(testcase, Config))
+ ++ "-"
+ ++ integer_to_list(erlang:system_time(second))
+ ++ "-"
+ ++ integer_to_list(erlang:unique_integer([positive]))).
+
+start_node(Config) ->
+ start_node(Config, "").
+
+start_node(Config, Args) when is_list(Config) ->
+ Pa = filename:dirname(code:which(?MODULE)),
+ Name = make_nodename(Config),
+ test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
+
+stop_node(Node) ->
+ test_server:stop_node(Node).