-
Module is the error handler module used by
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index 00ab6284d78b..dc931e825450 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -355,6 +355,16 @@ erts_alloc_get_verify_unused_temp_alloc(Allctr_t **allctr);
#define ERTS_ALC_DATA_ALIGN_SIZE(SZ) \
(((((SZ) - 1) / 8) + 1) * 8)
+#if defined(ARCH_64)
+#define ERTS_ALC_WORD_ALIGN_SIZE(SZ) \
+ ERTS_ALC_DATA_ALIGN_SIZE((SZ))
+#elif defined(ARCH_32)
+#define ERTS_ALC_WORD_ALIGN_SIZE(SZ) \
+ (((((SZ) - 1) / 4) + 1) * 4)
+#else
+#error "Not supported word size"
+#endif
+
#define ERTS_ALC_CACHE_LINE_ALIGN_SIZE(SZ) \
(((((SZ) - 1) / ERTS_CACHE_LINE_SIZE) + 1) * ERTS_CACHE_LINE_SIZE)
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 867db56f390c..b3dd42bf6795 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -778,6 +778,7 @@ collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp, Sint reds)
#define ERTS_PI_IX_FULLSWEEP_AFTER 35
#define ERTS_PI_IX_PARENT 36
#define ERTS_PI_IX_ASYNC_DIST 37
+#define ERTS_PI_IX_DICTIONARY_LOOKUP 38
#define ERTS_PI_FLAG_SINGELTON (1 << 0)
#define ERTS_PI_FLAG_ALWAYS_WRAP (1 << 1)
@@ -785,6 +786,7 @@ collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp, Sint reds)
#define ERTS_PI_FLAG_NEED_MSGQ_LEN (1 << 3)
#define ERTS_PI_FLAG_FORCE_SIG_SEND (1 << 4)
#define ERTS_PI_FLAG_REQUEST_FOR_OTHER (1 << 5)
+#define ERTS_PI_FLAG_KEY_TUPLE2 (1 << 6)
#define ERTS_PI_UNRESERVE(RS, SZ) \
(ASSERT((RS) >= (SZ)), (RS) -= (SZ))
@@ -835,7 +837,8 @@ static ErtsProcessInfoArgs pi_args[] = {
{am_magic_ref, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
{am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN},
{am_parent, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_async_dist, 0, 0, ERTS_PROC_LOCK_MAIN}
+ {am_async_dist, 0, 0, ERTS_PROC_LOCK_MAIN},
+ {am_dictionary, 3, ERTS_PI_FLAG_FORCE_SIG_SEND|ERTS_PI_FLAG_KEY_TUPLE2, ERTS_PROC_LOCK_MAIN},
};
#define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(pi_args[0])))
@@ -847,11 +850,21 @@ static ErtsProcessInfoArgs pi_args[] = {
#endif
static ERTS_INLINE Eterm
-pi_ix2arg(int ix)
+pi_ix2arg(Eterm **hpp, int ix, Eterm extra)
{
+ Eterm res;
if (ix < 0 || ERTS_PI_ARGS <= ix)
return am_undefined;
- return pi_args[ix].name;
+
+ if (!(pi_args[ix].flags & ERTS_PI_FLAG_KEY_TUPLE2))
+ return pi_args[ix].name;
+
+ ASSERT(hpp != NULL);
+ ASSERT(*hpp != NULL);
+ ASSERT(is_value(extra));
+ res = TUPLE2(*hpp, pi_args[ix].name, extra);
+ *hpp += 3;
+ return res;
}
static ERTS_INLINE int
@@ -879,7 +892,7 @@ pi_ix2locks(int ix)
}
static ERTS_INLINE int
-pi_arg2ix(Eterm arg)
+pi_arg2ix(Eterm arg, Eterm *extrap)
{
switch (arg) {
case am_registered_name:
@@ -959,6 +972,17 @@ pi_arg2ix(Eterm arg)
case am_async_dist:
return ERTS_PI_IX_ASYNC_DIST;
default:
+ if (is_tuple_arity(arg, 2)) {
+ Eterm *tpl = tuple_val(arg);
+ if (extrap)
+ *extrap = tpl[2];
+ switch (tpl[1]) {
+ case am_dictionary:
+ return ERTS_PI_IX_DICTIONARY_LOOKUP;
+ default:
+ break;
+ }
+ }
return -1;
}
}
@@ -1005,7 +1029,10 @@ process_info_init(void)
{ /* Make sure the process_info argument mappings are consistent */
int ix;
for (ix = 0; ix < ERTS_PI_ARGS; ix++) {
- ASSERT(pi_arg2ix(pi_ix2arg(ix)) == ix);
+ Eterm heap[3];
+ Eterm *hp = &heap[0];
+ ASSERT(pi_arg2ix(pi_ix2arg(&hp, ix, am_ok), NULL) == ix);
+ ASSERT(hp <= &heap[3]);
}
}
#endif
@@ -1018,6 +1045,7 @@ process_info_aux(Process *c_p,
Process *rp,
ErtsProcLocks rp_locks,
int item_ix,
+ Eterm extra,
Sint *msgq_len_p,
int flags,
Uint *reserve_sizep,
@@ -1029,7 +1057,8 @@ erts_process_info(Process *c_p,
Process *rp,
ErtsProcLocks rp_locks,
int *item_ix,
- int item_ix_len,
+ Eterm *item_extra,
+ int item_len,
int flags,
Uint reserve_size,
Uint *reds)
@@ -1040,8 +1069,27 @@ erts_process_info(Process *c_p,
Sint msgq_len = -1;
if (ERTS_PI_FLAG_SINGELTON & flags) {
- ASSERT(item_ix_len == 1);
- res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0],
+ Eterm extra;
+ ASSERT(item_len == 1);
+ if (!item_extra) {
+ extra = THE_NON_VALUE;
+ ASSERT(!(pi_ix2flags(item_ix[0]) & ERTS_PI_FLAG_KEY_TUPLE2));
+ }
+ else {
+ extra = item_extra[0];
+ ASSERT(pi_ix2flags(item_ix[0]) & ERTS_PI_FLAG_KEY_TUPLE2);
+ ASSERT(is_value(extra));
+ if ((flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER)
+ && is_not_immed(extra)) {
+ Eterm *hp;
+ Uint sz = size_object(extra);
+ ASSERT(sz);
+ ERTS_PI_UNRESERVE(reserve_size, sz);
+ hp = erts_produce_heap(hfact, sz, reserve_size);
+ extra = copy_struct(extra, sz, &hp, hfact->off_heap);
+ }
+ }
+ res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0], extra,
&msgq_len, flags, &reserve_size, reds);
return res;
}
@@ -1057,19 +1105,21 @@ erts_process_info(Process *c_p,
* the queue contain bad distribution messages).
*/
if (flags & ERTS_PI_FLAG_WANT_MSGS) {
- ix = pi_arg2ix(am_messages);
+ ix = pi_arg2ix(am_messages, NULL);
ASSERT(part_res[ix] == THE_NON_VALUE);
- res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
+ res = process_info_aux(c_p, hfact, rp, rp_locks, ix, THE_NON_VALUE,
&msgq_len, flags, &reserve_size, reds);
ASSERT(res != am_undefined);
ASSERT(res != THE_NON_VALUE);
part_res[ix] = res;
}
- for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) {
+ for (item_ix_ix = item_len - 1; item_ix_ix >= 0; item_ix_ix--) {
ix = item_ix[item_ix_ix];
+ if (pi_ix2flags(ix) & ERTS_PI_FLAG_KEY_TUPLE2)
+ continue;
if (part_res[ix] == THE_NON_VALUE) {
- res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
+ res = process_info_aux(c_p, hfact, rp, rp_locks, ix, THE_NON_VALUE,
&msgq_len, flags, &reserve_size, reds);
ASSERT(res != am_undefined);
ASSERT(res != THE_NON_VALUE);
@@ -1079,31 +1129,53 @@ erts_process_info(Process *c_p,
res = NIL;
- for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) {
+ for (item_ix_ix = item_len - 1; item_ix_ix >= 0; item_ix_ix--) {
+ Eterm *hp, val;
ix = item_ix[item_ix_ix];
- ASSERT(part_res[ix] != THE_NON_VALUE);
- /*
- * If we should ignore the value of registered_name,
- * its value is nil. For more info, see comment in the
- * beginning of process_info_aux().
- */
- if (is_nil(part_res[ix])) {
- ASSERT(!(flags & ERTS_PI_FLAG_ALWAYS_WRAP));
- ASSERT(pi_ix2arg(ix) == am_registered_name);
- }
- else {
- Eterm *hp;
- ERTS_PI_UNRESERVE(reserve_size, 2);
- hp = erts_produce_heap(hfact, 2, reserve_size);
- res = CONS(hp, part_res[ix], res);
+ if (pi_ix2flags(ix) & ERTS_PI_FLAG_KEY_TUPLE2) {
+ Eterm extra = item_extra[item_ix_ix];
+ ASSERT(is_value(extra));
+ ASSERT(part_res[ix] == THE_NON_VALUE);
+ if ((flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER)
+ && is_not_immed(extra)) {
+ Uint sz = size_object(extra);
+ ASSERT(sz);
+ ERTS_PI_UNRESERVE(reserve_size, sz);
+ hp = erts_produce_heap(hfact, sz, reserve_size);
+ extra = copy_struct(extra, sz, &hp, hfact->off_heap);
+ }
+ val = process_info_aux(c_p, hfact, rp, rp_locks, ix, extra,
+ &msgq_len, flags, &reserve_size, reds);
+ }
+ else {
+ ASSERT(part_res[ix] != THE_NON_VALUE);
+ /*
+ * If we should ignore the value of registered_name,
+ * its value is nil. For more info, see comment in the
+ * beginning of process_info_aux().
+ */
+ if (is_nil(part_res[ix])) {
+ ASSERT(!(flags & ERTS_PI_FLAG_ALWAYS_WRAP));
+ ASSERT(pi_ix2arg(NULL, ix, THE_NON_VALUE) == am_registered_name);
+ continue;
+ }
+ val = part_res[ix];
}
+
+ ERTS_PI_UNRESERVE(reserve_size, 2);
+ hp = erts_produce_heap(hfact, 2, reserve_size);
+ res = CONS(hp, val, res);
}
return res;
}
static void
-pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix);
+pi_setup_grow(int **arr, int *def_arr, Eterm **extra_arr,
+ Eterm *def_extra_arr, Uint *sz, int ix);
+static void
+pi_setup_init_extra(Eterm **extra_arr, Eterm *def_extra_arr, Uint sz);
+
#ifdef DEBUG
static int
@@ -1225,7 +1297,9 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
{
ErtsHeapFactory hfact;
int def_arr[ERTS_PI_DEF_ARR_SZ];
+ Eterm def_extra_arr[ERTS_PI_DEF_ARR_SZ];
int *item_ix = &def_arr[0];
+ Eterm *item_extra = NULL;
Process *rp = NULL;
erts_aint32_t state;
BIF_RETTYPE ret;
@@ -1238,8 +1312,9 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
ERTS_CT_ASSERT(ERTS_PI_DEF_ARR_SZ > 0);
- if (is_atom(opt)) {
- int ix = pi_arg2ix(opt);
+ if (is_atom(opt) || is_tuple_arity(opt, 2)) {
+ Eterm extra = THE_NON_VALUE;
+ int ix = pi_arg2ix(opt, &extra);
item_ix[0] = ix;
len = 1;
locks = pi_ix2locks(ix);
@@ -1248,6 +1323,11 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
flags |= pi_ix2flags(ix);
if (ix < 0)
goto badarg;
+ if (flags & ERTS_PI_FLAG_KEY_TUPLE2) {
+ ASSERT(is_value(extra));
+ item_extra = &def_extra_arr[0];
+ item_extra[0] = extra;
+ }
}
else {
Eterm list = opt;
@@ -1259,23 +1339,34 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
flags = 0;
while (is_list(list)) {
+ int item_flags;
+ Eterm extra = THE_NON_VALUE;
Eterm *consp = list_val(list);
Eterm arg = CAR(consp);
- int ix = pi_arg2ix(arg);
+ int ix = pi_arg2ix(arg, &extra);
if (ix < 0)
goto badarg;
if (len >= size)
- pi_setup_grow(&item_ix, def_arr, &size, len);
+ pi_setup_grow(&item_ix, def_arr, &item_extra,
+ def_extra_arr, &size, len);
- item_ix[len++] = ix;
+ item_ix[len] = ix;
locks |= pi_ix2locks(ix);
- flags |= pi_ix2flags(ix);
+ item_flags = pi_ix2flags(ix);
+ flags |= item_flags;
reserve_size += pi_ix2rsz(ix);
reserve_size += 3; /* 2-tuple */
reserve_size += 2; /* cons */
-
+ if (item_flags & ERTS_PI_FLAG_KEY_TUPLE2) {
+ ASSERT(is_value(extra));
+ if (!item_extra)
+ pi_setup_init_extra(&item_extra, def_extra_arr, size);
+ ASSERT(item_extra);
+ item_extra[len] = extra;
+ }
+ len++;
list = CDR(consp);
}
@@ -1345,8 +1436,8 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
erts_factory_proc_init(&hfact, c_p);
- res = erts_process_info(c_p, &hfact, rp, locks, item_ix, len,
- flags, reserve_size, &reds);
+ res = erts_process_info(c_p, &hfact, rp, locks, item_ix, item_extra,
+ len, flags, reserve_size, &reds);
erts_factory_close(&hfact);
@@ -1384,6 +1475,9 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
if (item_ix != def_arr)
erts_free(ERTS_ALC_T_TMP, item_ix);
+ if (item_extra && item_extra != def_extra_arr)
+ erts_free(ERTS_ALC_T_TMP, item_extra);
+
return ret;
badarg:
@@ -1418,6 +1512,7 @@ send_signal: {
*/
erts_msgq_set_save_end(c_p);
enqueued = erts_proc_sig_send_process_info_request(c_p, pid, item_ix,
+ item_extra,
len, need_msgq_len,
flags, reserve_size,
ref);
@@ -1432,19 +1527,54 @@ send_signal: {
}
static void
-pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix)
+pi_setup_grow(int **arr, int *def_arr, Eterm **extra_arr,
+ Eterm *def_extra_arr, Uint *sz, int ix)
{
*sz = (ix+1) + ERTS_PI_DEF_ARR_SZ;
- if (*arr != def_arr)
+ if (*arr != def_arr) {
*arr = erts_realloc(ERTS_ALC_T_TMP, *arr, (*sz)*sizeof(int));
+ if (*extra_arr) {
+ Eterm *new_extra_arr;
+ int i;
+ ASSERT(*extra_arr != def_extra_arr);
+ new_extra_arr = erts_realloc(ERTS_ALC_T_TMP, *extra_arr,
+ (*sz)*sizeof(Eterm));
+ for (i = ix; i < *sz; i++)
+ new_extra_arr[i] = THE_NON_VALUE;
+ *extra_arr = new_extra_arr;
+ }
+ }
else {
int *new_arr = erts_alloc(ERTS_ALC_T_TMP, (*sz)*sizeof(int));
sys_memcpy((void *) new_arr, (void *) def_arr,
sizeof(int)*ERTS_PI_DEF_ARR_SZ);
*arr = new_arr;
+ if (*extra_arr) {
+ int i;
+ Eterm *new_extra_arr = erts_alloc(ERTS_ALC_T_TMP,
+ (*sz)*sizeof(Eterm));
+ ASSERT(*extra_arr == def_extra_arr);
+ sys_memcpy((void *) new_extra_arr, (void *) def_extra_arr,
+ sizeof(Eterm)*ERTS_PI_DEF_ARR_SZ);
+ for (i = ERTS_PI_DEF_ARR_SZ; i < *sz; i++)
+ new_extra_arr[i] = THE_NON_VALUE;
+ *extra_arr = new_extra_arr;
+ }
}
}
+static void
+pi_setup_init_extra(Eterm **extra_arr, Eterm *def_extra_arr, Uint sz)
+{
+ Eterm *new_extra_arr;
+ int i;
+ new_extra_arr = (sz > ERTS_PI_DEF_ARR_SZ
+ ? (Eterm *) erts_alloc(ERTS_ALC_T_TMP, sz*sizeof(Eterm))
+ : def_extra_arr);
+ for (i = 0; i < sz; i++)
+ new_extra_arr[i] = THE_NON_VALUE;
+ *extra_arr = new_extra_arr;
+}
BIF_RETTYPE process_info_2(BIF_ALIST_2)
{
@@ -1462,12 +1592,14 @@ process_info_aux(Process *c_p,
Process *rp,
ErtsProcLocks rp_locks,
int item_ix,
+ Eterm extra,
Sint *msgq_len_p,
int flags,
Uint *reserve_sizep,
Uint *reds)
{
- Eterm *hp;
+ Eterm *hp = NULL /* silence code checker... */;
+ Eterm key;
Eterm res = NIL;
Uint reserved;
Uint reserve_size = *reserve_sizep;
@@ -2174,16 +2306,39 @@ process_info_aux(Process *c_p,
break;
}
+ case ERTS_PI_IX_DICTIONARY_LOOKUP: {
+ Uint sz;
+
+ ASSERT(is_value(extra));
+ res = ((ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)
+ ? am_undefined
+ : erts_pd_hash_get(rp, extra));
+ sz = (!(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER) || is_immed(res)
+ ? 0
+ : size_object(res));
+
+ /* Allocate 3 words extra for key 2-tuple... */
+ hp = erts_produce_heap(hfact, sz + 3, reserve_size);
+
+ if (sz)
+ res = copy_struct(res, sz, &hp, hfact->off_heap);
+
+ break;
+ }
+
default:
return THE_NON_VALUE; /* will produce badarg */
}
+ key = pi_ix2arg(&hp, item_ix, extra);
+
ERTS_PI_UNRESERVE(reserve_size, 3);
*reserve_sizep = reserve_size;
hp = erts_produce_heap(hfact, 3, reserve_size);
+ res = TUPLE2(hp, key, res);
- return TUPLE2(hp, pi_ix2arg(item_ix), res);
+ return res;
}
#undef MI_INC
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index c35729edfd01..f490abd41657 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -200,7 +200,9 @@ typedef struct {
Uint reserve_size;
Uint len;
int flags;
- int item_ix[1]; /* of len size in reality... */
+ int *item_ix;
+ Eterm *item_extra;
+ ErlHeapFragment *extra_hfrag;
} ErtsProcessInfoSig;
#define ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE ((Sint) -1)
@@ -509,6 +511,14 @@ destroy_sig_group_leader(ErtsSigGroupLeader *sgl)
erts_free(ERTS_ALC_T_SIG_DATA, sgl);
}
+static void
+destroy_process_info_sig(ErtsProcessInfoSig *pis)
+{
+ if (pis->extra_hfrag)
+ erts_cleanup_offheap(&pis->extra_hfrag->off_heap);
+ erts_free(ERTS_ALC_T_SIG_DATA, pis);
+}
+
static ERTS_INLINE void
sig_enqueue_trace(ErtsPTabElementCommon *sender, Eterm from,
ErtsMessage **sigp, int op, Process *rp,
@@ -2684,16 +2694,89 @@ int
erts_proc_sig_send_process_info_request(Process *c_p,
Eterm to,
int *item_ix,
+ Eterm *item_extra,
int len,
int need_msgq_len,
int flags,
Uint reserve_size,
Eterm ref)
{
- Uint size = sizeof(ErtsProcessInfoSig) + (len - 1) * sizeof(int);
- ErtsProcessInfoSig *pis = erts_alloc(ERTS_ALC_T_SIG_DATA, size);
+ Uint size, item_ix_offs, extra_offs, extra_hfrag_offs,
+ extra_hsz = 0, *extra_hszs = NULL;
+ ErtsProcessInfoSig *pis;
int res;
+ if (item_extra) {
+ int i;
+ extra_hszs = erts_alloc(ERTS_ALC_T_TMP, sizeof(Uint)*len);
+ for (i = 0; i < len; i++) {
+ Eterm extra = item_extra[i];
+ extra_hszs[i] = (is_non_value(extra) || is_immed(extra)
+ ? 0
+ : size_object(extra));
+ extra_hsz += extra_hszs[i];
+ }
+ }
+
+ size = ERTS_ALC_WORD_ALIGN_SIZE(sizeof(ErtsProcessInfoSig));
+ item_ix_offs = size;
+ size += ERTS_ALC_WORD_ALIGN_SIZE(len * sizeof(int));
+ if (!item_extra) {
+ extra_offs = 0;
+ extra_hfrag_offs = 0;
+ }
+ else {
+ extra_offs = size;
+ size += ERTS_ALC_WORD_ALIGN_SIZE(len * sizeof(Eterm));
+ extra_hfrag_offs = size;
+ if (extra_hsz)
+ size += ERTS_HEAP_FRAG_SIZE(extra_hsz);
+ }
+ pis = erts_alloc(ERTS_ALC_T_SIG_DATA, size);
+ pis->item_ix = (int *) (((char *) pis) + item_ix_offs);
+ if (!item_extra) {
+ ASSERT(!extra_offs);
+ pis->item_extra = NULL;
+ pis->extra_hfrag = NULL;
+ }
+ else {
+ int i;
+ Eterm *extra_hp;
+ ErlOffHeap *extra_off_heap;
+#ifdef DEBUG
+ Eterm *end_hp = NULL;
+#endif
+ ASSERT(extra_offs);
+ pis->item_extra = (Eterm *) (((char *) pis) + extra_offs);
+ if (!extra_hsz) {
+ extra_hp = NULL;
+ extra_off_heap = NULL;
+ pis->extra_hfrag = NULL;
+ }
+ else {
+ pis->extra_hfrag = (ErlHeapFragment *) (((char *) pis)
+ + extra_hfrag_offs);
+ ERTS_INIT_HEAP_FRAG(pis->extra_hfrag, extra_hsz, extra_hsz);
+ extra_hp = &pis->extra_hfrag->mem[0];
+#ifdef DEBUG
+ end_hp = extra_hp + extra_hsz;
+#endif
+ extra_off_heap = &pis->extra_hfrag->off_heap;
+ }
+ for (i = 0; i < len; i++) {
+ if (!extra_hsz || !extra_hszs[i]) {
+ pis->item_extra[i] = item_extra[i];
+ }
+ else {
+ pis->item_extra[i] = copy_struct(item_extra[i], extra_hszs[i],
+ &extra_hp, extra_off_heap);
+ }
+ }
+ ASSERT(extra_hp == end_hp);
+ erts_free(ERTS_ALC_T_TMP, extra_hszs);
+ reserve_size += sizeof(Eterm)*extra_hsz;
+ }
+
ASSERT(c_p);
ASSERT(item_ix);
ASSERT(len > 0);
@@ -2730,7 +2813,7 @@ erts_proc_sig_send_process_info_request(Process *c_p,
if (res) {
(void) maybe_elevate_sig_handling_prio(c_p, -1, to);
} else {
- erts_free(ERTS_ALC_T_SIG_DATA, pis);
+ destroy_process_info_sig(pis);
}
return res;
@@ -4713,12 +4796,17 @@ destroy_process_info_request(Process *c_p, ErtsProcessInfoSig *pisig)
= (ErtsProcessInfoSig *) (((char *) marker)
- offsetof(ErtsProcessInfoSig,
marker));
- erts_free(ERTS_ALC_T_SIG_DATA, pisig2);
+ destroy_process_info_sig(pisig2);
}
}
- if (dealloc_pisig)
- erts_free(ERTS_ALC_T_SIG_DATA, pisig);
+ if (dealloc_pisig) {
+ destroy_process_info_sig(pisig);
+ }
+ else if (pisig->extra_hfrag) {
+ erts_cleanup_offheap(&pisig->extra_hfrag->off_heap);
+ pisig->extra_hfrag = NULL;
+ }
}
static int
@@ -4826,7 +4914,7 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing,
erts_factory_selfcontained_message_init(&hfact, mp, &hfrag->mem[0]);
res = erts_process_info(c_p, &hfact, c_p, ERTS_PROC_LOCK_MAIN,
- pisig->item_ix, pisig->len,
+ pisig->item_ix, pisig->item_extra, pisig->len,
pisig->flags, reserve_size, &reds);
hp = erts_produce_heap(&hfact,
diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h
index 663d42d59fad..187b8d7a164a 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.h
+++ b/erts/emulator/beam/erl_proc_sig_queue.h
@@ -866,7 +866,11 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to,
* @param[in] item_ix Info index array to pass to
* erts_process_info()
*
- * @param[in] len Length of info index array
+ * @param[in] item_extra Extra terms array to pass to
+ * erts_process_info()
+ *
+ * @param[in] len Length of info index array and
+ * extra array if such is provided
*
* @param[in] need_msgq_len Non-zero if message queue
* length is needed; otherwise,
@@ -892,6 +896,7 @@ int
erts_proc_sig_send_process_info_request(Process *c_p,
Eterm to,
int *item_ix,
+ Eterm *item_extra,
int len,
int need_msgq_len,
int flags,
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index b266dc556182..6f166e372c51 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -2031,7 +2031,7 @@ void erts_dump_extended_process_state(fmtfn_t to, void *to_arg, erts_aint32_t ps
void erts_dump_process_state(fmtfn_t to, void *to_arg, erts_aint32_t psflg);
Eterm erts_process_info(Process *c_p, ErtsHeapFactory *hfact,
Process *rp, ErtsProcLocks rp_locks,
- int *item_ix, int item_ix_len,
+ int *item_ix, Eterm *item_extra, int item_len,
int flags, Uint reserve_size, Uint *reds);
typedef struct {
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 1d546ff36e8b..10cddfdfa137 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -54,6 +54,7 @@
process_info_self_msgq_len_messages/1,
process_info_self_msgq_len_more/1,
process_info_msgq_len_no_very_long_delay/1,
+ process_info_dict_lookup/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, dist_unlink_ack_exit_leak/1, bad_register/1,
garbage_collect/1, otp_6237/1,
@@ -178,7 +179,8 @@ groups() ->
process_info_self_msgq_len,
process_info_self_msgq_len_messages,
process_info_self_msgq_len_more,
- process_info_msgq_len_no_very_long_delay]},
+ process_info_msgq_len_no_very_long_delay,
+ process_info_dict_lookup]},
{otp_7738, [],
[otp_7738_waiting, otp_7738_suspended,
otp_7738_resume]},
@@ -1260,7 +1262,8 @@ process_info_smoke_all(Config) when is_list(Config) ->
message_queue_data,
garbage_collection_info,
magic_ref,
- fullsweep_after],
+ fullsweep_after,
+ {dictionary, ets_ref}],
{ok, Peer, Node} = ?CT_PEER(),
RP = spawn_link(Node, fun process_info_smoke_all_tester/0),
@@ -1554,6 +1557,200 @@ process_info_msgq_len_no_very_long_delay(Config) when is_list(Config) ->
false = is_process_alive(P2),
ok.
+process_info_dict_lookup(Config) when is_list(Config) ->
+ Pid = spawn_link(fun proc_dict_helper/0),
+ {async_dist, AsyncDist} = process_info(Pid, async_dist),
+ Ref = make_ref(),
+ Bin = <<17:4096>>,
+ Int0 = 9999999999999999999999999999999999,
+ Int1 = 1111111111111111111111111111111111,
+ Tuple = {make_ref(), erlang:monotonic_time()},
+
+ %% Check that we can lookup dictionary values on another process...
+ pdh(Pid, put_async, [hej, hopp]),
+ pdh(Pid, put_async, [hopp, hej]),
+ pdh(Pid, put_async, [Ref, Int0]),
+ pdh(Pid, put_async, [Int0, Int1]),
+ pdh(Pid, put_async, [Pid, Ref]),
+ pdh(Pid, put_async, [Tuple, Bin]),
+ undefined = pdh(Pid, put, [Bin, Ref]),
+
+ erlang:garbage_collect(Pid),
+
+ {{dictionary, Ref}, Int0} = process_info(Pid, {dictionary, Ref}),
+ [{{dictionary, Ref}, Int0}] = process_info(Pid, [{dictionary, Ref}]),
+
+ PIRes = process_info(Pid, [async_dist,
+ trap_exit,
+ {dictionary, hej},
+ {dictionary, hopp},
+ {dictionary, Ref},
+ {dictionary, Int0},
+ async_dist,
+ trap_exit,
+ {dictionary, Pid},
+ {dictionary, Tuple},
+ {dictionary, Bin}]),
+ ct:log("PIRes = ~p", [PIRes]),
+ PIRes = [{async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, hej}, hopp},
+ {{dictionary, hopp}, hej},
+ {{dictionary, Ref}, Int0},
+ {{dictionary, Int0}, Int1},
+ {async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, Pid}, Ref},
+ {{dictionary, Tuple}, Bin},
+ {{dictionary, Bin}, Ref}],
+
+ pdh(Pid, erase_async, [hej]),
+ pdh(Pid, erase_async, [hopp]),
+ pdh(Pid, erase_async, [Ref]),
+ pdh(Pid, erase_async, [Int0]),
+ pdh(Pid, erase_async, [Pid]),
+ pdh(Pid, erase_async, [Tuple]),
+ Ref = pdh(Pid, erase, [Bin]),
+
+ erlang:garbage_collect(Pid),
+
+ {{dictionary, Ref}, undefined} = process_info(Pid, {dictionary, Ref}),
+ [{{dictionary, Ref}, undefined}] = process_info(Pid, [{dictionary, Ref}]),
+
+ PIRes2 = process_info(Pid, [async_dist,
+ trap_exit,
+ {dictionary, hej},
+ {dictionary, hopp},
+ {dictionary, Ref},
+ {dictionary, Int0},
+ async_dist,
+ trap_exit,
+ {dictionary, Pid},
+ {dictionary, Tuple},
+ {dictionary, Bin}]),
+ ct:log("PIRes2 = ~p", [PIRes2]),
+
+ PIRes2 = [{async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, hej}, undefined},
+ {{dictionary, hopp}, undefined},
+ {{dictionary, Ref}, undefined},
+ {{dictionary, Int0}, undefined},
+ {async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, Pid}, undefined},
+ {{dictionary, Tuple}, undefined},
+ {{dictionary, Bin}, undefined}],
+
+ unlink(Pid),
+ exit(Pid,kill),
+
+ %% Also check that it works on ourself...
+
+ put(hej, hopp),
+ put(hopp, hej),
+ put(Ref, Int0),
+ put(Int0, Int1),
+ put(Pid, Ref),
+ put(Tuple, Bin),
+ undefined = put(Bin, Ref),
+
+ erlang:garbage_collect(),
+
+ {{dictionary, Ref}, Int0} = process_info(self(), {dictionary, Ref}),
+ [{{dictionary, Ref}, Int0}] = process_info(self(), [{dictionary, Ref}]),
+
+ PIRes3 = process_info(self(), [async_dist,
+ trap_exit,
+ {dictionary, hej},
+ {dictionary, hopp},
+ {dictionary, Ref},
+ {dictionary, Int0},
+ async_dist,
+ trap_exit,
+ {dictionary, Pid},
+ {dictionary, Tuple},
+ {dictionary, Bin}]),
+ ct:log("PIRes3 = ~p", [PIRes3]),
+ PIRes3 = [{async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, hej}, hopp},
+ {{dictionary, hopp}, hej},
+ {{dictionary, Ref}, Int0},
+ {{dictionary, Int0}, Int1},
+ {async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, Pid}, Ref},
+ {{dictionary, Tuple}, Bin},
+ {{dictionary, Bin}, Ref}],
+
+ erase(hej),
+ erase(hopp),
+ erase(Ref),
+ erase(Int0),
+ erase(Pid),
+ erase(Tuple),
+ Ref = erase(Bin),
+
+ erlang:garbage_collect(),
+
+ {{dictionary, Ref}, undefined} = process_info(self(), {dictionary, Ref}),
+ [{{dictionary, Ref}, undefined}] = process_info(self(), [{dictionary, Ref}]),
+
+ PIRes4 = process_info(self(), [async_dist,
+ trap_exit,
+ {dictionary, hej},
+ {dictionary, hopp},
+ {dictionary, Ref},
+ {dictionary, Int0},
+ async_dist,
+ trap_exit,
+ {dictionary, Pid},
+ {dictionary, Tuple},
+ {dictionary, Bin}]),
+ ct:log("PIRes4 = ~p", [PIRes4]),
+
+ PIRes4 = [{async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, hej}, undefined},
+ {{dictionary, hopp}, undefined},
+ {{dictionary, Ref}, undefined},
+ {{dictionary, Int0}, undefined},
+ {async_dist, AsyncDist},
+ {trap_exit, false},
+ {{dictionary, Pid}, undefined},
+ {{dictionary, Tuple}, undefined},
+ {{dictionary, Bin}, undefined}],
+
+ false = is_process_alive(Pid),
+ ok.
+
+pdh(Pid, AsyncOp, Args) when AsyncOp == put_async;
+ AsyncOp == erase_async ->
+ Pid ! {AsyncOp, Args},
+ ok;
+pdh(Pid, SyncOp, Args) ->
+ Ref = make_ref(),
+ Pid ! {SyncOp, self(), Ref, Args},
+ receive {Ref, Res} -> Res end.
+
+proc_dict_helper() ->
+ receive
+ {put, From, Ref, [Key, Value]} ->
+ From ! {Ref, put(Key, Value)};
+ {get, From, Ref, [Key]} ->
+ From ! {Ref, get(Key)};
+ {get, From, Ref, []} ->
+ From ! {Ref, get()};
+ {erase, From, Ref, [Key]} ->
+ From ! {Ref, erase(Key)};
+ {put_async, [Key, Value]} ->
+ _ = put(Key, Value);
+ {erase_async, [Key]} ->
+ _ = erase(Key)
+ end,
+ proc_dict_helper().
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 00ea9e5775fb..01476d307184 100644
Binary files a/erts/preloaded/ebin/erlang.beam and b/erts/preloaded/ebin/erlang.beam differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 110e6e62894b..1ba97db9e034 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -2690,6 +2690,7 @@ process_flag(_Flag, _Value) ->
current_location |
current_stacktrace |
dictionary |
+ {dictionary, Key :: term()} |
error_handler |
garbage_collection |
garbage_collection_info |
@@ -2733,6 +2734,7 @@ process_flag(_Flag, _Value) ->
{line, Line :: pos_integer()}]}} |
{current_stacktrace, Stack :: [stack_item()]} |
{dictionary, Dictionary :: [{Key :: term(), Value :: term()}]} |
+ {{dictionary, Key :: term()}, Value :: term()} |
{error_handler, Module :: module()} |
{garbage_collection, GCInfo :: [{atom(),non_neg_integer()}]} |
{garbage_collection_info, GCInfo :: [{atom(),non_neg_integer()}]} |