diff options
author | Rickard Green <rickard@erlang.org> | 2020-07-23 17:46:25 +0200 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2020-11-03 12:47:49 +0100 |
commit | 9f4c1a9ccd33063e64661c287faea780d9db419f (patch) | |
tree | 4046a19bf50e9956e81cd732c2d7e228878f61d0 /erts | |
parent | c7b50c83af7ce4e3b111ad2b21897ec5bd57d31c (diff) | |
download | erlang-9f4c1a9ccd33063e64661c287faea780d9db419f.tar.gz |
Introduce internal references containing pid of creator
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/bif.c | 27 | ||||
-rw-r--r-- | erts/emulator/beam/copy.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_alloc.types | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_unique.c | 289 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_unique.h | 113 | ||||
-rw-r--r-- | erts/emulator/beam/erl_db_util.c | 5 | ||||
-rw-r--r-- | erts/emulator/beam/erl_gc.c | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_lock_check.c | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_monitor_link.c | 28 | ||||
-rw-r--r-- | erts/emulator/beam/erl_monitor_link.h | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_node_container_utils.h | 9 | ||||
-rw-r--r-- | erts/emulator/beam/erl_port.h | 4 | ||||
-rw-r--r-- | erts/emulator/beam/erl_port_task.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_term.c | 2 | ||||
-rw-r--r-- | erts/emulator/beam/erl_term.h | 135 | ||||
-rw-r--r-- | erts/emulator/beam/external.c | 82 | ||||
-rw-r--r-- | erts/emulator/beam/utils.c | 2 | ||||
-rw-r--r-- | erts/emulator/test/ref_SUITE.erl | 110 |
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). |