/erts/emulator/beam/erl_bif_info.c
C | 5205 lines | 4420 code | 555 blank | 230 comment | 1150 complexity | dc4aed70d905f906d55343d1d7cc2755 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2018. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * %CopyrightEnd%
- */
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #define ERTS_WANT_MEM_MAPPERS
- #include "sys.h"
- #include "erl_vm.h"
- #include "global.h"
- #include "erl_process.h"
- #include "error.h"
- #include "erl_driver.h"
- #include "erl_nif.h"
- #include "bif.h"
- #include "big.h"
- #include "erl_version.h"
- #include "erl_compile_flags.h"
- #include "erl_db_util.h"
- #include "erl_message.h"
- #include "erl_binary.h"
- #include "erl_db.h"
- #include "erl_mtrace.h"
- #include "dist.h"
- #include "erl_gc.h"
- #include "erl_cpu_topology.h"
- #include "erl_async.h"
- #include "erl_thr_progress.h"
- #include "erl_bif_unique.h"
- #include "erl_map.h"
- #include "erl_check_io.h"
- #define ERTS_PTAB_WANT_DEBUG_FUNCS__
- #include "erl_ptab.h"
- #include "erl_time.h"
- #include "erl_proc_sig_queue.h"
- #include "erl_alloc_util.h"
- #ifdef HIPE
- #include "hipe_arch.h"
- #endif
- #ifdef ERTS_ENABLE_LOCK_COUNT
- #include "erl_lock_count.h"
- #endif
- #ifdef VALGRIND
- #include <valgrind/valgrind.h>
- #include <valgrind/memcheck.h>
- #endif
- static Export* alloc_info_trap = NULL;
- static Export* alloc_sizes_trap = NULL;
- static Export* gather_io_bytes_trap = NULL;
- static Export *gather_sched_wall_time_res_trap;
- static Export *gather_msacc_res_trap;
- static Export *gather_gc_info_res_trap;
- static Export *gather_system_check_res_trap;
- static Export *is_process_alive_trap;
- #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
- static char otp_version[] = ERLANG_OTP_VERSION;
- /* Keep erts_system_version as a global variable for easy access from a core */
- static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
- "%s"
- " [erts-" ERLANG_VERSION "]"
- #ifndef OTP_RELEASE
- #ifdef ERLANG_GIT_VERSION
- " [source-" ERLANG_GIT_VERSION "]"
- #else
- " [source]"
- #endif
- #endif
- #ifdef ARCH_64
- " [64-bit]"
- #endif
- " [smp:%beu:%beu]"
- " [ds:%beu:%beu:%beu]"
- #if defined(ERTS_DIRTY_SCHEDULERS_TEST)
- " [dirty-schedulers-TEST]"
- #endif
- " [async-threads:%d]"
- #ifdef HIPE
- " [hipe]"
- #endif
- #ifdef ET_DEBUG
- #if ET_DEBUG
- " [type-assertions]"
- #endif
- #endif
- #ifdef DEBUG
- " [debug-compiled]"
- #endif
- #ifdef ERTS_ENABLE_LOCK_CHECK
- " [lock-checking]"
- #endif
- #ifdef ERTS_ENABLE_LOCK_COUNT
- " [lock-counting]"
- #endif
- #ifdef ERTS_OPCODE_COUNTER_SUPPORT
- " [instruction-counting]"
- #endif
- #ifdef PURIFY
- " [purify-compiled]"
- #endif
- #ifdef VALGRIND
- " [valgrind-compiled]"
- #endif
- #ifdef ERTS_FRMPTR
- " [frame-pointer]"
- #endif
- #ifdef USE_LTTNG
- " [lttng]"
- #endif
- #ifdef USE_DTRACE
- " [dtrace]"
- #endif
- #ifdef USE_SYSTEMTAP
- " [systemtap]"
- #endif
- #ifdef SHCOPY
- " [sharing-preserving]"
- #endif
- "\n");
- #define ASIZE(a) (sizeof(a)/sizeof(a[0]))
- #if defined(HAVE_SOLARIS_SPARC_PERFMON)
- # include <sys/ioccom.h>
- # define PERFMON_SETPCR _IOW('P', 1, unsigned long long)
- # define PERFMON_GETPCR _IOR('P', 2, unsigned long long)
- #endif
- /* Cached, pre-built {OsType,OsFlavor} and {Major,Minor,Build} tuples */
- static Eterm os_type_tuple;
- static Eterm os_version_tuple;
- static Eterm
- current_function(Process* p, ErtsHeapFactory *hfact, Process* rp,
- int full_info, Uint reserve_size, int flags);
- static Eterm current_stacktrace(ErtsHeapFactory *hfact, Process* rp,
- Uint reserve_size);
- static Eterm
- bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
- {
- struct erl_off_heap_header* ohh;
- Eterm res = NIL;
- Eterm tuple;
- for (ohh = oh->first; ohh; ohh = ohh->next) {
- if (ohh->thing_word == HEADER_PROC_BIN) {
- ProcBin* pb = (ProcBin*) ohh;
- Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val);
- Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size);
-
- if (szp)
- *szp += 4+2;
- if (hpp) {
- Uint refc = (Uint) erts_refc_read(&pb->val->intern.refc, 1);
- tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
- res = CONS(*hpp + 4, tuple, res);
- *hpp += 4+2;
- }
- }
- }
- return res;
- }
- static Eterm
- bld_magic_ref_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
- {
- struct erl_off_heap_header* ohh;
- Eterm res = NIL;
- Eterm tuple;
- for (ohh = oh->first; ohh; ohh = ohh->next) {
- if (is_ref_thing_header((*((Eterm *) ohh)))) {
- ErtsMRefThing *mrtp = (ErtsMRefThing *) ohh;
- Eterm val = erts_bld_uword(hpp, szp, (UWord) mrtp->mb);
- Eterm orig_size = erts_bld_uint(hpp, szp, mrtp->mb->orig_size);
-
- if (szp)
- *szp += 4+2;
- if (hpp) {
- Uint refc = (Uint) erts_refc_read(&mrtp->mb->intern.refc, 1);
- tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
- res = CONS(*hpp + 4, tuple, res);
- *hpp += 4+2;
- }
- }
- }
- return res;
- }
- /*
- make_monitor_list:
- returns a list of records..
- -record(erl_monitor, {
- type, % process | port | time_offset | dist_process | resource
- % | node | nodes | suspend
- dir, % origin | target
- ref, % reference or []
- pid, % Process or nodename
- extra % registered name, integer or []
- }).
- */
- static int do_calc_mon_size(ErtsMonitor *mon, void *vpsz, Sint reds)
- {
- ErtsMonitorData *mdp = erts_monitor_to_data(mon);
- Uint *psz = vpsz;
- *psz += is_immed(mdp->ref) ? 0 : NC_HEAP_SIZE(mdp->ref);
- if (mon->type == ERTS_MON_TYPE_RESOURCE && erts_monitor_is_target(mon))
- *psz += erts_resource_ref_size(mon->other.ptr);
- else
- *psz += is_immed(mon->other.item) ? 0 : NC_HEAP_SIZE(mon->other.item);
- *psz += 9; /* CONS + 6-tuple */
- return 1;
- }
- typedef struct {
- Process *p;
- Eterm *hp;
- Eterm res;
- Eterm tag;
- } MonListContext;
- static int do_make_one_mon_element(ErtsMonitor *mon, void * vpmlc, Sint reds)
- {
- ErtsMonitorData *mdp = erts_monitor_to_data(mon);
- MonListContext *pmlc = vpmlc;
- Eterm tup, t, d, r, p, x;
- r = is_immed(mdp->ref) ? mdp->ref : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mdp->ref);
- if (mon->type == ERTS_MON_TYPE_RESOURCE && erts_monitor_is_target(mon))
- p = erts_bld_resource_ref(&(pmlc->hp), &MSO(pmlc->p), mon->other.ptr);
- else
- p = (is_immed(mon->other.item)
- ? mon->other.item
- : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->other.item));
- if (mon->flags & ERTS_ML_FLG_NAME)
- x = ((ErtsMonitorDataExtended *) mdp)->u.name;
- else if (erts_monitor_is_target(mon))
- x = NIL;
- else if (mon->type == ERTS_MON_TYPE_NODE || mon->type == ERTS_MON_TYPE_NODES)
- x = make_small(((ErtsMonitorDataExtended *) mdp)->u.refc);
- else
- x = NIL;
- switch (mon->type) {
- case ERTS_MON_TYPE_PROC:
- t = am_process;
- break;
- case ERTS_MON_TYPE_PORT:
- t = am_port;
- break;
- case ERTS_MON_TYPE_TIME_OFFSET:
- t = am_time_offset;
- break;
- case ERTS_MON_TYPE_DIST_PROC: {
- ERTS_DECL_AM(dist_process);
- t = AM_dist_process;
- break;
- }
- case ERTS_MON_TYPE_RESOURCE: {
- ERTS_DECL_AM(resource);
- t = AM_resource;
- break;
- }
- case ERTS_MON_TYPE_NODE:
- t = am_node;
- break;
- case ERTS_MON_TYPE_NODES: {
- ERTS_DECL_AM(nodes);
- t = AM_nodes;
- break;
- }
- case ERTS_MON_TYPE_SUSPEND:
- t = am_suspend;
- break;
- default:
- ERTS_INTERNAL_ERROR("Unknown monitor type");
- t = am_error;
- break;
- }
- if (erts_monitor_is_target(mon)) {
- ERTS_DECL_AM(target);
- d = AM_target;
- }
- else {
- ERTS_DECL_AM(origin);
- d = AM_origin;
- }
- tup = TUPLE6(pmlc->hp, pmlc->tag, t, d, r, p, x);
- pmlc->hp += 7;
- pmlc->res = CONS(pmlc->hp, tup, pmlc->res);
- pmlc->hp += 2;
- return 1;
- }
- static Eterm
- make_monitor_list(Process *p, int tree, ErtsMonitor *root, Eterm tail)
- {
- DECL_AM(erl_monitor);
- Uint sz = 0;
- MonListContext mlc;
- void (*foreach)(ErtsMonitor *,
- ErtsMonitorFunc,
- void *);
- foreach = tree ? erts_monitor_tree_foreach : erts_monitor_list_foreach;
- (*foreach)(root, do_calc_mon_size, &sz);
- if (sz == 0)
- return tail;
- mlc.p = p;
- mlc.hp = HAlloc(p,sz);
- mlc.res = tail;
- mlc.tag = AM_erl_monitor;
- (*foreach)(root, do_make_one_mon_element, &mlc);
- return mlc.res;
- }
- /*
- make_link_list:
- returns a list of records..
- -record(erl_link, {
- type, % process | port | dist_process
- pid, % Process or port
- id % (address)
- }).
- */
- static int calc_lnk_size(ErtsLink *lnk, void *vpsz, Sint reds)
- {
- Uint *psz = vpsz;
- Uint sz = 0;
- ErtsLinkData *ldp = erts_link_to_data(lnk);
- (void) erts_bld_uword(NULL, &sz, (UWord) ldp);
- *psz += sz;
- *psz += is_immed(lnk->other.item) ? 0 : size_object(lnk->other.item);
- *psz += 7; /* CONS + 4-tuple */
- return 1;
- }
- typedef struct {
- Process *p;
- Eterm *hp;
- Eterm res;
- Eterm tag;
- } LnkListContext;
- static int make_one_lnk_element(ErtsLink *lnk, void * vpllc, Sint reds)
- {
- LnkListContext *pllc = vpllc;
- Eterm tup, t, pid, id;
- ErtsLinkData *ldp = erts_link_to_data(lnk);
- id = erts_bld_uword(&pllc->hp, NULL, (UWord) ldp);
- if (is_immed(lnk->other.item))
- pid = lnk->other.item;
- else {
- Uint sz = size_object(lnk->other.item);
- pid = copy_struct(lnk->other.item, sz, &(pllc->hp), &MSO(pllc->p));
- }
- switch (lnk->type) {
- case ERTS_LNK_TYPE_PROC:
- t = am_process;
- break;
- case ERTS_LNK_TYPE_PORT:
- t = am_port;
- break;
- case ERTS_LNK_TYPE_DIST_PROC: {
- ERTS_DECL_AM(dist_process);
- t = AM_dist_process;
- break;
- }
- default:
- ERTS_INTERNAL_ERROR("Unkown link type");
- t = am_undefined;
- break;
- }
- tup = TUPLE4(pllc->hp, pllc->tag, t, pid, id);
- pllc->hp += 5;
- pllc->res = CONS(pllc->hp, tup, pllc->res);
- pllc->hp += 2;
- return 1;
- }
- static Eterm
- make_link_list(Process *p, int tree, ErtsLink *root, Eterm tail)
- {
- DECL_AM(erl_link);
- Uint sz = 0;
- LnkListContext llc;
- void (*foreach)(ErtsLink *,
- ErtsLinkFunc,
- void *);
- foreach = tree ? erts_link_tree_foreach : erts_link_list_foreach;
- (*foreach)(root, calc_lnk_size, (void *) &sz);
- if (sz == 0) {
- return tail;
- }
- llc.p = p;
- llc.hp = HAlloc(p,sz);
- llc.res = tail;
- llc.tag = AM_erl_link;
- (*foreach)(root, make_one_lnk_element, (void *) &llc);
- return llc.res;
- }
- int
- erts_print_system_version(fmtfn_t to, void *arg, Process *c_p)
- {
- int i, rc = -1;
- char *rc_str = "";
- char rc_buf[100];
- char *ov = otp_version;
- Uint total, online, active;
- Uint dirty_cpu, dirty_cpu_onln, dirty_io;
- erts_schedulers_state(&total, &online, &active,
- &dirty_cpu, &dirty_cpu_onln, NULL,
- &dirty_io, NULL);
- for (i = 0; i < sizeof(otp_version)-4; i++) {
- if (ov[i] == '-' && ov[i+1] == 'r' && ov[i+2] == 'c')
- rc = atoi(&ov[i+3]);
- }
- if (rc >= 0) {
- if (rc == 0)
- rc_str = " [DEVELOPMENT]";
- else {
- erts_snprintf(rc_buf, sizeof(rc_buf), " [RELEASE CANDIDATE %d]", rc);
- rc_str = rc_buf;
- }
- }
- return erts_print(to, arg, erts_system_version,
- rc_str
- , total, online
- , dirty_cpu, dirty_cpu_onln, dirty_io
- , erts_async_max_threads
- );
- }
- typedef struct {
- /* {Entity,Node} = {monitor.Name,monitor.Pid} for external by name
- * {Entity,Node} = {monitor.Pid,NIL} for external/external by pid
- * {Entity,Node} = {monitor.Name,erlang:node()} for internal by name
- * {Entity,Node} = {monitor.resource,MON_NIF_TARGET}*/
- union {
- Eterm term;
- ErtsResource* resource;
- }entity;
- int named;
- Uint16 type;
- Eterm node;
- /* pid is actual target being monitored, no matter pid/port or name */
- Eterm pid;
- } MonitorInfo;
- typedef struct {
- MonitorInfo *mi;
- Uint mi_i;
- Uint mi_max;
- int sz;
- } MonitorInfoCollection;
- #define INIT_MONITOR_INFOS(MIC) do { \
- (MIC).mi = NULL; \
- (MIC).mi_i = (MIC).mi_max = 0; \
- (MIC).sz = 0; \
- } while(0)
- #define MI_INC 50
- #define EXTEND_MONITOR_INFOS(MICP) \
- do { \
- if ((MICP)->mi_i >= (MICP)->mi_max) { \
- (MICP)->mi = ((MICP)->mi ? erts_realloc(ERTS_ALC_T_TMP, \
- (MICP)->mi, \
- ((MICP)->mi_max+MI_INC) \
- * sizeof(MonitorInfo)) \
- : erts_alloc(ERTS_ALC_T_TMP, \
- MI_INC*sizeof(MonitorInfo))); \
- (MICP)->mi_max += MI_INC; \
- } \
- } while (0)
- #define DESTROY_MONITOR_INFOS(MIC) \
- do { \
- if ((MIC).mi != NULL) { \
- erts_free(ERTS_ALC_T_TMP, (void *) (MIC).mi); \
- } \
- } while (0)
- static int collect_one_link(ErtsLink *lnk, void *vmicp, Sint reds)
- {
- MonitorInfoCollection *micp = vmicp;
- EXTEND_MONITOR_INFOS(micp);
- micp->mi[micp->mi_i].entity.term = lnk->other.item;
- micp->sz += 2 + NC_HEAP_SIZE(lnk->other.item);
- micp->mi_i++;
- return 1;
- }
- static int collect_one_origin_monitor(ErtsMonitor *mon, void *vmicp, Sint reds)
- {
- if (erts_monitor_is_origin(mon)) {
- MonitorInfoCollection *micp = vmicp;
-
- EXTEND_MONITOR_INFOS(micp);
- micp->mi[micp->mi_i].type = mon->type;
- switch (mon->type) {
- case ERTS_MON_TYPE_PROC:
- case ERTS_MON_TYPE_PORT:
- case ERTS_MON_TYPE_DIST_PROC:
- case ERTS_MON_TYPE_TIME_OFFSET:
- if (!(mon->flags & ERTS_ML_FLG_NAME)) {
- micp->mi[micp->mi_i].named = 0;
- micp->mi[micp->mi_i].entity.term = mon->other.item;
- micp->mi[micp->mi_i].node = NIL;
- if (is_not_atom(mon->other.item))
- micp->sz += NC_HEAP_SIZE(mon->other.item);
- }
- else {
- ErtsMonitorDataExtended *mdep;
- micp->mi[micp->mi_i].named = !0;
- mdep = (ErtsMonitorDataExtended *) erts_monitor_to_data(mon);
- micp->mi[micp->mi_i].entity.term = mdep->u.name;
- if (mdep->dist)
- micp->mi[micp->mi_i].node = mdep->dist->nodename;
- else
- micp->mi[micp->mi_i].node = erts_this_dist_entry->sysname;
- micp->sz += 3; /* need one 2-tuple */
- }
- /* have always pid at hand, to assist with figuring out if its a port or
- * a process, when we monitored by name and process_info is requested.
- * See: erl_bif_info.c:process_info_aux section for am_monitors */
- micp->mi[micp->mi_i].pid = mon->other.item;
- micp->mi_i++;
- micp->sz += 2 + 3; /* For a cons cell and a 2-tuple */
- break;
- default:
- break;
- }
- }
- return 1;
- }
- static int collect_one_target_monitor(ErtsMonitor *mon, void *vmicp, Sint reds)
- {
- MonitorInfoCollection *micp = vmicp;
-
- if (erts_monitor_is_target(mon)) {
- EXTEND_MONITOR_INFOS(micp);
-
- micp->mi[micp->mi_i].type = mon->type;
- micp->mi[micp->mi_i].named = !!(mon->flags & ERTS_ML_FLG_NAME);
- switch (mon->type) {
- case ERTS_MON_TYPE_PROC:
- case ERTS_MON_TYPE_PORT:
- case ERTS_MON_TYPE_DIST_PROC:
- micp->mi[micp->mi_i].entity.term = mon->other.item;
- micp->mi[micp->mi_i].node = NIL;
- micp->sz += NC_HEAP_SIZE(mon->other.item);
- micp->sz += 2; /* cons */;
- micp->mi_i++;
- break;
- case ERTS_MON_TYPE_RESOURCE:
- micp->mi[micp->mi_i].entity.resource = mon->other.ptr;
- micp->mi[micp->mi_i].node = NIL;
- micp->sz += erts_resource_ref_size(mon->other.ptr);
- micp->sz += 2; /* cons */;
- micp->mi_i++;
- break;
- default:
- break;
- }
- }
- return 1;
- }
- typedef struct {
- ErtsMonitorSuspend **smi;
- Uint smi_i;
- Uint smi_max;
- Uint sz;
- } ErtsSuspendMonitorInfoCollection;
- #define ERTS_INIT_SUSPEND_MONITOR_INFOS(SMIC) do { \
- (SMIC).smi = NULL; \
- (SMIC).smi_i = (SMIC).smi_max = 0; \
- (SMIC).sz = 0; \
- } while(0)
- #define ERTS_SMI_INC 50
- #define ERTS_EXTEND_SUSPEND_MONITOR_INFOS(SMICP) \
- do { \
- if ((SMICP)->smi_i >= (SMICP)->smi_max) { \
- (SMICP)->smi = ((SMICP)->smi \
- ? erts_realloc(ERTS_ALC_T_TMP, \
- (SMICP)->smi, \
- ((SMICP)->smi_max \
- + ERTS_SMI_INC) \
- * sizeof(ErtsMonitorSuspend *)) \
- : erts_alloc(ERTS_ALC_T_TMP, \
- ERTS_SMI_INC \
- * sizeof(ErtsMonitorSuspend *))); \
- (SMICP)->smi_max += ERTS_SMI_INC; \
- } \
- } while (0)
- #define ERTS_DESTROY_SUSPEND_MONITOR_INFOS(SMIC) \
- do { \
- if ((SMIC).smi != NULL) { \
- erts_free(ERTS_ALC_T_TMP, (void *) (SMIC).smi); \
- } \
- } while (0)
- static int
- collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp, Sint reds)
- {
- if (mon->type == ERTS_MON_TYPE_SUSPEND) {
- Sint count;
- erts_aint_t mstate;
- ErtsMonitorSuspend *msp;
- ErtsSuspendMonitorInfoCollection *smicp;
- msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
- smicp = vsmicp;
- ERTS_EXTEND_SUSPEND_MONITOR_INFOS(smicp);
- smicp->smi[smicp->smi_i] = msp;
- smicp->sz += 2 /* cons */ + 4 /* 3-tuple */;
- mstate = erts_atomic_read_nob(&msp->state);
- count = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
- if (!IS_SSMALL(count))
- smicp->sz += BIG_UINT_HEAP_SIZE;
- smicp->smi_i++;
- }
- return 1;
- }
- /*
- * process_info/[1,2]
- */
- /*
- * All valid process_info arguments.
- */
- #define ERTS_PI_IX_REGISTERED_NAME 0
- #define ERTS_PI_IX_CURRENT_FUNCTION 1
- #define ERTS_PI_IX_INITIAL_CALL 2
- #define ERTS_PI_IX_STATUS 3
- #define ERTS_PI_IX_MESSAGES 4
- #define ERTS_PI_IX_MESSAGE_QUEUE_LEN 5
- #define ERTS_PI_IX_LINKS 6
- #define ERTS_PI_IX_MONITORS 7
- #define ERTS_PI_IX_MONITORED_BY 8
- #define ERTS_PI_IX_DICTIONARY 9
- #define ERTS_PI_IX_TRAP_EXIT 10
- #define ERTS_PI_IX_ERROR_HANDLER 11
- #define ERTS_PI_IX_HEAP_SIZE 12
- #define ERTS_PI_IX_STACK_SIZE 13
- #define ERTS_PI_IX_MEMORY 14
- #define ERTS_PI_IX_GARBAGE_COLLECTION 15
- #define ERTS_PI_IX_GROUP_LEADER 16
- #define ERTS_PI_IX_REDUCTIONS 17
- #define ERTS_PI_IX_PRIORITY 18
- #define ERTS_PI_IX_TRACE 19
- #define ERTS_PI_IX_BINARY 20
- #define ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN 21
- #define ERTS_PI_IX_CATCHLEVEL 22
- #define ERTS_PI_IX_BACKTRACE 23
- #define ERTS_PI_IX_LAST_CALLS 24
- #define ERTS_PI_IX_TOTAL_HEAP_SIZE 25
- #define ERTS_PI_IX_SUSPENDING 26
- #define ERTS_PI_IX_MIN_HEAP_SIZE 27
- #define ERTS_PI_IX_MIN_BIN_VHEAP_SIZE 28
- #define ERTS_PI_IX_MAX_HEAP_SIZE 29
- #define ERTS_PI_IX_CURRENT_LOCATION 30
- #define ERTS_PI_IX_CURRENT_STACKTRACE 31
- #define ERTS_PI_IX_MESSAGE_QUEUE_DATA 32
- #define ERTS_PI_IX_GARBAGE_COLLECTION_INFO 33
- #define ERTS_PI_IX_MAGIC_REF 34
- #define ERTS_PI_IX_FULLSWEEP_AFTER 35
- #define ERTS_PI_FLAG_SINGELTON (1 << 0)
- #define ERTS_PI_FLAG_ALWAYS_WRAP (1 << 1)
- #define ERTS_PI_FLAG_WANT_MSGS (1 << 2)
- #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_UNRESERVE(RS, SZ) \
- (ASSERT((RS) >= (SZ)), (RS) -= (SZ))
- typedef struct {
- Eterm name;
- Uint reserve_size;
- int flags;
- ErtsProcLocks locks;
- } ErtsProcessInfoArgs;
- static ErtsProcessInfoArgs pi_args[] = {
- {am_registered_name, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_current_function, 4, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_initial_call, 4, 0, ERTS_PROC_LOCK_MAIN},
- {am_status, 0, 0, 0},
- {am_messages, 0, ERTS_PI_FLAG_WANT_MSGS|ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_message_queue_len, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN, ERTS_PROC_LOCK_MAIN},
- {am_links, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_monitors, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_monitored_by, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_dictionary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_trap_exit, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_error_handler, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_stack_size, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_memory, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_garbage_collection, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + ERTS_MAX_HEAP_SIZE_MAP_SZ, 0, ERTS_PROC_LOCK_MAIN},
- {am_group_leader, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_reductions, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_priority, 0, 0, 0},
- {am_trace, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_binary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_sequential_trace_token, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_catchlevel, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_backtrace, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_last_calls, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_total_heap_size, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_suspending, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, 0},
- {am_min_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_min_bin_vheap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_max_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_current_location, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_current_stacktrace, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_message_queue_data, 0, 0, ERTS_PROC_LOCK_MAIN},
- {am_garbage_collection_info, ERTS_PROCESS_GC_INFO_MAX_SIZE, 0, ERTS_PROC_LOCK_MAIN},
- {am_magic_ref, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
- {am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN}
- };
- #define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(pi_args[0])))
- #ifdef DEBUG
- # define ERTS_PI_DEF_ARR_SZ 2
- #else
- # define ERTS_PI_DEF_ARR_SZ ERTS_PI_ARGS
- #endif
- static ERTS_INLINE Eterm
- pi_ix2arg(int ix)
- {
- if (ix < 0 || ERTS_PI_ARGS <= ix)
- return am_undefined;
- return pi_args[ix].name;
- }
- static ERTS_INLINE int
- pi_ix2flags(int ix)
- {
- if (ix < 0 || ERTS_PI_ARGS <= ix)
- return 0;
- return pi_args[ix].flags;
- }
- static ERTS_INLINE Uint
- pi_ix2rsz(int ix)
- {
- if (ix < 0 || ERTS_PI_ARGS <= ix)
- return 0;
- return pi_args[ix].reserve_size;
- }
- static ERTS_INLINE ErtsProcLocks
- pi_ix2locks(int ix)
- {
- if (ix < 0 || ERTS_PI_ARGS <= ix)
- return 0;
- return pi_args[ix].locks;
- }
- static ERTS_INLINE int
- pi_arg2ix(Eterm arg)
- {
- switch (arg) {
- case am_registered_name:
- return ERTS_PI_IX_REGISTERED_NAME;
- case am_current_function:
- return ERTS_PI_IX_CURRENT_FUNCTION;
- case am_initial_call:
- return ERTS_PI_IX_INITIAL_CALL;
- case am_status:
- return ERTS_PI_IX_STATUS;
- case am_messages:
- return ERTS_PI_IX_MESSAGES;
- case am_message_queue_len:
- return ERTS_PI_IX_MESSAGE_QUEUE_LEN;
- case am_links:
- return ERTS_PI_IX_LINKS;
- case am_monitors:
- return ERTS_PI_IX_MONITORS;
- case am_monitored_by:
- return ERTS_PI_IX_MONITORED_BY;
- case am_dictionary:
- return ERTS_PI_IX_DICTIONARY;
- case am_trap_exit:
- return ERTS_PI_IX_TRAP_EXIT;
- case am_error_handler:
- return ERTS_PI_IX_ERROR_HANDLER;
- case am_heap_size:
- return ERTS_PI_IX_HEAP_SIZE;
- case am_stack_size:
- return ERTS_PI_IX_STACK_SIZE;
- case am_memory:
- return ERTS_PI_IX_MEMORY;
- case am_garbage_collection:
- return ERTS_PI_IX_GARBAGE_COLLECTION;
- case am_group_leader:
- return ERTS_PI_IX_GROUP_LEADER;
- case am_reductions:
- return ERTS_PI_IX_REDUCTIONS;
- case am_priority:
- return ERTS_PI_IX_PRIORITY;
- case am_trace:
- return ERTS_PI_IX_TRACE;
- case am_binary:
- return ERTS_PI_IX_BINARY;
- case am_sequential_trace_token:
- return ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN;
- case am_catchlevel:
- return ERTS_PI_IX_CATCHLEVEL;
- case am_backtrace:
- return ERTS_PI_IX_BACKTRACE;
- case am_last_calls:
- return ERTS_PI_IX_LAST_CALLS;
- case am_total_heap_size:
- return ERTS_PI_IX_TOTAL_HEAP_SIZE;
- case am_suspending:
- return ERTS_PI_IX_SUSPENDING;
- case am_min_heap_size:
- return ERTS_PI_IX_MIN_HEAP_SIZE;
- case am_min_bin_vheap_size:
- return ERTS_PI_IX_MIN_BIN_VHEAP_SIZE;
- case am_max_heap_size:
- return ERTS_PI_IX_MAX_HEAP_SIZE;
- case am_current_location:
- return ERTS_PI_IX_CURRENT_LOCATION;
- case am_current_stacktrace:
- return ERTS_PI_IX_CURRENT_STACKTRACE;
- case am_message_queue_data:
- return ERTS_PI_IX_MESSAGE_QUEUE_DATA;
- case am_garbage_collection_info:
- return ERTS_PI_IX_GARBAGE_COLLECTION_INFO;
- case am_magic_ref:
- return ERTS_PI_IX_MAGIC_REF;
- case am_fullsweep_after:
- return ERTS_PI_IX_FULLSWEEP_AFTER;
- default:
- return -1;
- }
- }
- static Eterm pi_1_keys[] = {
- am_registered_name,
- am_current_function,
- am_initial_call,
- am_status,
- am_message_queue_len,
- am_links,
- am_dictionary,
- am_trap_exit,
- am_error_handler,
- am_priority,
- am_group_leader,
- am_total_heap_size,
- am_heap_size,
- am_stack_size,
- am_reductions,
- am_garbage_collection,
- am_suspending
- };
- #define ERTS_PI_1_NO_OF_KEYS (sizeof(pi_1_keys)/sizeof(Eterm))
- static Eterm pi_1_keys_list;
- static Eterm pi_1_keys_list_heap[2*ERTS_PI_1_NO_OF_KEYS];
- static void
- process_info_init(void)
- {
- Eterm *hp = &pi_1_keys_list_heap[0];
- int i;
- pi_1_keys_list = NIL;
- for (i = ERTS_PI_1_NO_OF_KEYS-1; i >= 0; i--) {
- pi_1_keys_list = CONS(hp, pi_1_keys[i], pi_1_keys_list);
- hp += 2;
- }
- #ifdef DEBUG
- { /* 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);
- }
- }
- #endif
- }
- static BIF_RETTYPE
- process_info_aux(Process *c_p,
- ErtsHeapFactory *hfact,
- Process *rp,
- ErtsProcLocks rp_locks,
- int item_ix,
- int flags,
- Uint *reserve_sizep,
- Uint *reds);
- Eterm
- erts_process_info(Process *c_p,
- ErtsHeapFactory *hfact,
- Process *rp,
- ErtsProcLocks rp_locks,
- int *item_ix,
- int item_ix_len,
- int flags,
- Uint reserve_size,
- Uint *reds)
- {
- Eterm res;
- Eterm part_res[ERTS_PI_ARGS];
- int item_ix_ix, ix;
- if (ERTS_PI_FLAG_SINGELTON & flags) {
- ASSERT(item_ix_len == 1);
- res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0],
- flags, &reserve_size, reds);
- return res;
- }
- for (ix = 0; ix < ERTS_PI_ARGS; ix++)
- part_res[ix] = THE_NON_VALUE;
- /*
- * We always handle 'messages' first if it should be part
- * of the result. This since if both 'messages' and
- * 'message_queue_len' are wanted, 'messages' may
- * change the result of 'message_queue_len' (in case
- * the queue contain bad distribution messages).
- */
- if (flags & ERTS_PI_FLAG_WANT_MSGS) {
- ix = pi_arg2ix(am_messages);
- ASSERT(part_res[ix] == THE_NON_VALUE);
- res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
- 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--) {
- ix = item_ix[item_ix_ix];
- if (part_res[ix] == THE_NON_VALUE) {
- res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
- flags, &reserve_size, reds);
- ASSERT(res != am_undefined);
- ASSERT(res != THE_NON_VALUE);
- part_res[ix] = res;
- }
- }
- res = NIL;
- for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) {
- 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);
- }
- }
- return res;
- }
- static void
- pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix);
- static BIF_RETTYPE
- 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];
- int *item_ix = &def_arr[0];
- Process *rp = NULL;
- erts_aint32_t state;
- BIF_RETTYPE ret;
- Uint reds = 0;
- ErtsProcLocks locks = 0;
- int flags;
- Uint reserve_size;
- int len;
- Eterm res;
- ERTS_CT_ASSERT(ERTS_PI_DEF_ARR_SZ > 0);
- if (c_p->common.id == pid) {
- int local_only = c_p->flags & F_LOCAL_SIGS_ONLY;
- int sres, sreds, reds_left;
- reds_left = ERTS_BIF_REDS_LEFT(c_p);
- sreds = reds_left;
- if (!local_only) {
- erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ);
- erts_proc_sig_fetch(c_p);
- erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ);
- }
- sres = erts_proc_sig_handle_incoming(c_p, &state, &sreds, sreds, !0);
- BUMP_REDS(c_p, (int) sreds);
- reds_left -= sreds;
- if (state & ERTS_PSFLG_EXITING) {
- c_p->flags &= ~F_LOCAL_SIGS_ONLY;
- goto exited;
- }
- if (!sres | (reds_left <= 0)) {
- /*
- * More signals to handle or out of reds; need
- * to yield and continue. Prevent fetching of
- * more signals by setting local-sigs-only flag.
- */
- c_p->flags |= F_LOCAL_SIGS_ONLY;
- goto yield;
- }
- c_p->flags &= ~F_LOCAL_SIGS_ONLY;
- }
- if (is_atom(opt)) {
- int ix = pi_arg2ix(opt);
- item_ix[0] = ix;
- len = 1;
- locks = pi_ix2locks(ix);
- reserve_size = 3 + pi_ix2rsz(ix);
- flags = ERTS_PI_FLAG_SINGELTON;
- flags |= pi_ix2flags(ix);
- if (ix < 0)
- goto badarg;
- }
- else {
- Eterm list = opt;
- Uint size = ERTS_PI_DEF_ARR_SZ;
- len = 0;
- reserve_size = 0;
- locks = 0;
- flags = 0;
- while (is_list(list)) {
- Eterm *consp = list_val(list);
- Eterm arg = CAR(consp);
- int ix = pi_arg2ix(arg);
- if (ix < 0)
- goto badarg;
- if (len >= size)
- pi_setup_grow(&item_ix, def_arr, &size, len);
- item_ix[len++] = ix;
- locks |= pi_ix2locks(ix);
- flags |= pi_ix2flags(ix);
- reserve_size += pi_ix2rsz(ix);
- reserve_size += 3; /* 2-tuple */
- reserve_size += 2; /* cons */
- list = CDR(consp);
- }
- if (is_not_nil(list))
- goto badarg;
- }
- if (is_not_internal_pid(pid)) {
- if (is_external_pid(pid)
- && external_pid_dist_entry(pid) == erts_this_dist_entry)
- goto undefined;
- goto badarg;
- }
- if (always_wrap)
- flags |= ERTS_PI_FLAG_ALWAYS_WRAP;
- if (c_p->common.id == pid) {
- rp = c_p;
- if (locks & ~ERTS_PROC_LOCK_MAIN)
- erts_proc_lock(c_p, locks & ~ERTS_PROC_LOCK_MAIN);
- locks |= ERTS_PROC_LOCK_MAIN;
- }
- else {
- if (flags & ERTS_PI_FLAG_FORCE_SIG_SEND)
- goto send_signal;
- state = ERTS_PSFLG_RUNNING; /* fail state... */
- rp = erts_try_lock_sig_free_proc(pid, locks, &state);
- if (!rp)
- goto undefined;
- if (rp == ERTS_PROC_LOCK_BUSY) {
- rp = NULL;
- goto send_signal;
- }
- if (state & ERTS_PSFLG_EXITING) {
- if (locks)
- erts_proc_unlock(rp, locks);
- locks = 0;
- /* wait for it to terminate properly... */
- goto send_signal;
- }
- if (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN) {
- ASSERT(locks & ERTS_PROC_LOCK_MAIN);
- erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ);
- erts_proc_sig_fetch(rp);
- if (c_p->sig_qs.cont) {
- erts_proc_unlock(rp, locks|ERTS_PROC_LOCK_MSGQ);
- locks = 0;
- goto send_signal;
- }
- erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ);
- }
- }
- erts_factory_proc_init(&hfact, c_p);
- res = erts_process_info(c_p, &hfact, rp, locks, item_ix, len,
- flags, reserve_size, &reds);
- erts_factory_close(&hfact);
- if (reds > INT_MAX/2)
- reds = INT_MAX/2;
- BUMP_REDS(c_p, (int) reds);
- state = erts_atomic32_read_acqb(&rp->state);
- if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE)) {
- if (state & ERTS_PSFLG_FREE) {
- ASSERT(!locks);
- goto undefined;
- }
- if (locks)
- erts_proc_unlock(rp, locks);
- locks = 0;
- /* wait for it to terminate properly... */
- goto send_signal;
- }
- ERTS_BIF_PREP_RET(ret, res);
- done:
- if (c_p == rp)
- locks &= ~ERTS_PROC_LOCK_MAIN;
- if (locks && rp)
- erts_proc_unlock(rp, locks);
- if (item_ix != def_arr)
- erts_free(ERTS_ALC_T_TMP, item_ix);
- return ret;
- badarg:
- ERTS_BIF_PREP_ERROR(ret, c_p, BADARG);
- goto done;
- undefined:
- ERTS_BIF_PREP_RET(ret, am_undefined);
- goto done;
- exited:
- ERTS_BIF_PREP_EXITED(ret, c_p);
- goto done;
- yield:
- if (pi2)
- ERTS_BIF_PREP_YIELD2(ret, bif_export[BIF_process_info_2], c_p, pid, opt);
- else
- ERTS_BIF_PREP_YIELD1(ret, bif_export[BIF_process_info_1], c_p, pid);
- goto done;
- send_signal: {
- Eterm ref = erts_make_ref(c_p);
- int enqueued, need_msgq_len;
- flags |= ERTS_PI_FLAG_REQUEST_FOR_OTHER;
- need_msgq_len = (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
- /*
- * Set receive mark so we wont have to scan the whole
- * message queue for the result. Note caller unconditionally
- * has to enter a receive only matching messages containing
- * 'ref', or restore save pointer.
- */
- ERTS_RECV_MARK_SAVE(c_p);
- ERTS_RECV_MARK_SET(c_p);
- enqueued = erts_proc_sig_send_process_info_request(c_p, pid, item_ix,
- len, need_msgq_len,
- flags, reserve_size,
- ref);
- if (!enqueued) {
- /* Restore save pointer... */
- JOIN_MESSAGE(c_p);
- goto undefined;
- }
- ERTS_BIF_PREP_TRAP1(ret, erts_await_result, c_p, ref);
- goto done;
- }
- }
- static void
- pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix)
- {
- *sz = (ix+1) + ERTS_PI_DEF_ARR_SZ;
- if (*arr != def_arr)
- *arr = erts_realloc(ERTS_ALC_T_TMP, *arr, (*sz)*sizeof(int));
- 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;
- }
- }
- BIF_RETTYPE process_info_2(BIF_ALIST_2)
- {
- return process_info_bif(BIF_P, BIF_ARG_1, BIF_ARG_2, !is_atom(BIF_ARG_2), !0);
- }
- BIF_RETTYPE process_info_1(BIF_ALIST_1)
- {
- return process_info_bif(BIF_P, BIF_ARG_1, pi_1_keys_list, 0, 0);
- }
- Eterm
- process_info_aux(Process *c_p,
- ErtsHeapFactory *hfact,
- Process *rp,
- ErtsProcLocks rp_locks,
- int item_ix,
- int flags,
- Uint *reserve_sizep,
- Uint *reds)
- {
- Eterm *hp;
- Eterm res = NIL;
- Uint reserved;
- Uint reserve_size = *reserve_sizep;
- #ifdef ERTS_ENABLE_LOCK_CHECK
- ErtsProcLocks locks = erts_proc_lc_my_proc_locks(rp);
- switch (item_ix) {
- case ERTS_PI_IX_STATUS:
- case ERTS_PI_IX_PRIORITY:
- case ERTS_PI_IX_SUSPENDING:
- ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCK_MAIN) == 0);
- break;
- default:
- ERTS_LC_ASSERT(locks == ERTS_PROC_LOCK_MAIN);
- break;
- }
- #endif
- reserved = pi_ix2rsz(item_ix);
- ERTS_PI_UNRESERVE(reserve_size, reserved);
- (*reds)++;
- ASSERT(rp);
- /*
- * Q: Why this ERTS_PI_FLAG_ALWAYS_WRAP flag?
- *
- * A: registered_name is strange. If process has no registered name,
- * process_info(Pid, registered_name) returns [], and
- * the result of process_info(Pid) has no {registered_name, Name}
- * tuple in the resulting list. This is inconsistent with all other
- * options, but we do not dare to change it.
- *
- * When process_info/2 is called with a list as second argument,
- * registered_name behaves as it should, i.e. a
- * {registered_name, []} will appear in the resulting list.
- *
- * If ERTS_PI_FLAG_ALWAYS_WRAP is set, process_info_aux() always
- * wrap the result in a key two tuple.
- */
- switch (item_ix) {
- case ERTS_PI_IX_REGISTERED_NAME:
- if (rp->common.u.alive.reg)
- res = rp->common.u.alive.reg->name;
- else {
- if (flags & ERTS_PI_FLAG_ALWAYS_WRAP)
- res = NIL;
- else
- return NIL;
- }
- break;
- case ERTS_PI_IX_CURRENT_FUNCTION:
- res = current_function(c_p, hfact, rp, 0,
- reserve_size, flags);
- break;
- case ERTS_PI_IX_CURRENT_LOCATION:
- res = current_function(c_p, hfact, rp, 1,
- reserve_size, flags);
- break;
- case ERTS_PI_IX_CURRENT_STACKTRACE:
- res = current_stacktrace(hfact, rp, reserve_size);
- break;
- case ERTS_PI_IX_INITIAL_CALL:
- hp = erts_produce_heap(hfact, 4, reserve_size);
- res = TUPLE3(hp,
- rp->u.initial.module,
- rp->u.initial.function,
- make_small(rp->u.initial.arity));
- hp += 4;
- break;
- case ERTS_PI_IX_STATUS: {
- erts_aint32_t state = erts_atomic32_read_nob(&rp->state);
- res = erts_process_state2status(state);
- if (res == am_running && (state & ERTS_PSFLG_RUNNING_SYS)) {
- ASSERT(c_p == rp);
- ASSERT(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER);
- if (!(state & (ERTS_PSFLG_SYS_TASKS
- | ERTS_PSFLG_ACTIVE
- | ERTS_PSFLG_SIG_Q
- | ERTS_PSFLG_SIG_IN_Q))) {
- /*
- * We are servicing a process-info request from
- * another process. If that other process could
- * have inspected our state itself, we would have
- * been in the 'waiting' state.
- */
- res = am_waiting;
- }
- }
- break;
- }
- case ERTS_PI_IX_MESSAGES: {
- ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
- if (rp->sig_qs.len == 0 || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE))
- res = NIL;
- else {
- int info_on_self = !(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER);
- ErtsMessageInfo *mip;
- Sint i, len;
- Uint heap_need;
- mip = erts_alloc(ERTS_ALC_T_TMP,
- rp->sig_qs.len*sizeof(ErtsMessageInfo));
- /*
- * Note that message queue may shrink when calling
- * erts_proc_sig_prep_msgq_for_inspection() since it removes
- * corrupt distribution messages.
- */
- heap_need = erts_proc_sig_prep_msgq_for_inspection(c_p, rp,
- rp_locks,
- info_on_self,
- mip);
- len = rp->sig_qs.len;
- heap_need += len*2; /* Cons cells */
- reserve_size += heap_need;
- /* Build list of messages... */
- for (i = len - 1, res = NIL; i >= 0; i--) {
- Eterm msg = ERL_MESSAGE_TERM(mip[i].msgp);
- Uint sz = mip[i].size;
- ERTS_PI_UNRESERVE(reserve_size, sz+2);
- hp = erts_produce_heap(hfact, sz+2, reserve_size);
- if (sz != 0)
- msg = copy_struct(msg, sz, &hp, hfact->off_heap);
- res = CONS(hp, msg, res);
- hp += 2;
- }
- *reds += (Uint) len / 4;
- erts_free(ERTS_ALC_T_TMP, mip);
- }
- break;
- }
- case ERTS_PI_IX_MESSAGE_QUEUE_LEN: {
- Sint len = rp->sig_qs.len;
- ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
- ASSERT(len >= 0);
- if (len <= MAX_SMALL)
- res = make_small(len);
- else {
- hp = erts_produce_heap(hfact, BIG_UINT_HEAP_SIZE, reserve_size);
- res = uint_to_big((Uint) len, hp);
- }
- break;
- }
- case ERTS_PI_IX_LINKS: {
- MonitorInfoCollection mic;
- int i;
- Eterm item;
- INIT_MONITOR_INFOS(mic);
- erts_link_tree_foreach(ERTS_P_LINKS(rp), collect_one_link, (void *) &mic);
- reserve_size += mic.sz;
- res = NIL;
- for (i = 0; i < mic.mi_i; i++) {
- Eterm item_src = mic.mi[i].entity.term;
- Uint sz = NC_HEAP_SIZE(item_src) + 2;
- ERTS_PI_UNRESERVE(reserve_size, sz);
- hp = erts_produce_heap(hfact, sz, reserve_size);
- item = STORE_NC(&hp, hfact->off_heap, item_src);
- res = CONS(hp, item, res);
- }
- *reds += (Uint) mic.mi_i / 4;
- DESTROY_MONITOR_INFOS(mic);
- break;
- }
- case ERTS_PI_IX_MONITORS: {
- MonitorInfoCollection mic;
- int i;
- INIT_MONITOR_INFOS(mic);
- erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
- collect_one_origin_monitor,
- (void *) &mic);
- reserve_size += mic.sz;
- res = NIL;
- for (i = 0; i < mic.mi_i; i++) {
- if (mic.mi[i].named) {
- /* Monitor by name.
- * Build {process|port, {Name, Node}} and cons it.
- */
- Eterm t1, t2;
- /* If pid is an atom, then it is a remote named monitor, which
- has to be a process */
- Eterm m_type = is_port(mic.mi[i].pid) ? am_port : am_process;
- ASSERT(is_pid(mic.mi[i].pid)
- || is_port(mic.mi[i].pid)
- || is_atom(mic.mi[i].pid));
- ERTS_PI_UNRESERVE(reserve_size, 3+3+2);
- hp = erts_produce_heap(hfact, 3+3+2, reserve_size);
- t1 = TUPLE2(hp, mic.mi[i].entity.term, mic.mi[i].node);
- hp += 3;
- t2 = TUPLE2(hp, m_type, t1);
- hp += 3;
- res = CONS(hp, t2, res);
- }
- else {
- /* Build {process|port|time_offset, Pid|clock_service} and cons it. */
- Eterm t;
- Eterm pid;
- Eterm m_type;
- Eterm pid_src = mic.mi[i].entity.term;
- Uint sz = is_atom(pid_src) ? 0 : NC_HEAP_SIZE(pid_src);
- sz += 3 + 2;
- ERTS_PI_UNRESERVE(reserve_size, sz);
- hp = erts_produce_heap(hfact, sz, reserve_size);
- pid = (is_atom(pid_src)
- ? pid_src
- : STORE_NC(&hp, hfact->off_heap, pid_src));
- switch (mic.mi[i].type) {
- case ERTS_MON_TYPE_PORT:
- m_type = am_port;
- break;
- case ERTS_MON_TYPE_TIME_OFFSET:
- m_type = am_time_offset;
- break;
- default:
- m_type = am_process;
- break;
- }
- ASSERT(is_pid(mic.mi[i].pid)
- || is_port(mic.mi[i].pid));
- t = TUPLE2(hp, m_type, pid);
- hp += 3;
- res = CONS(hp, t, res);
- }
- }
- *reds += (Uint) mic.mi_i / 4;
- DESTROY_MONITOR_INFOS(mic);
- break;
- }
- case ERTS_PI_IX_MONITORED_BY: {
- MonitorInfoCollection mic;
- int i;
- Eterm item;
- INIT_MONITOR_INFOS(mic);
- erts_monitor_list_foreach(ERTS_P_LT_MONITORS(rp),
- collect_one_target_monitor,
- (void *) &mic);
- erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
- collect_one_target_monitor,
- (void *) &mic);
- reserve_size += mic.sz;
- res = NIL;
- for (i = 0; i < mic.mi_i; ++i) {
- Uint sz = 2;
- if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE)
- sz += erts_resource_ref_size(mic.mi[i].entity.resource);
- else
- sz += NC_HEAP_SIZE(mic.mi[i].entity.term);
- ERTS_PI_UNRESERVE(reserve_size, sz);
- hp = erts_produce_heap(hfact, sz, reserve_size);
- if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE)
- item = erts_bld_resource_ref(&hp,
- hfact->off_heap,
- mic.mi[i].entity.resource);
- else
- item = STORE_NC(&hp,
- hfact->off_heap,
- mic.mi[i].entity.term);
- res = CONS(hp, item, res);
- }
- *reds += (Uint) mic.mi_i / 4;
- DESTROY_MONITOR_INFOS(mic);
- break;
- }
- case ERTS_PI_IX_SUSPENDING: {
- ErtsSuspendMonitorInfoCollection smic;
- int i;
- ERTS_INIT_SUSPEND_MONITOR_INFOS(smic);
- erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
- collect_one_suspend_monitor,
- (void *) &smic);
- reserve_size += smic.sz;
- res = NIL;
- for (i = 0; i < smic.smi_i; i++) {
- ErtsMonitorSuspend *msp;
- erts_aint_t mstate;
- Sint ci;
- Eterm ct, active, pending, item;
- Uint sz = 4 + 2;
- msp = smic.smi[i];
- mstate = erts_atomic_read_nob(&msp->state);
- ci = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
- if (!IS_SSMALL(ci))
- sz += BIG_UINT_HEAP_SIZE;
- ERTS_PI_UNRESERVE(reserve_size, sz);
- hp = erts_produce_heap(hfact, sz, reserve_size);
- if (IS_SSMALL(ci))
- ct = make_small(ci);
- else {
- ct = small_to_big(ci, hp);
- hp += BIG_UINT_HEAP_SIZE;
- }
- if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE) {
- active = ct;
- pending = make_small(0);
- }
- else {
- active = make_small(0);
- pending = ct;
- }
- ASSERT(is_internal_pid(msp->md.origin.other.item));
- item = TUPLE3(hp, msp->md.origin.other.item, active, pending);
- hp += 4;
- res = CONS(hp, item, res);
- }
- *reds += (Uint) smic.smi_i / 4;
- ERTS_DESTROY_SUSPEND_MONITOR_INFOS(smic);
- break;
- }
- case ERTS_PI_IX_DICTIONARY:
- if (!rp->dictionary || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) {
- res = NIL;
- } else {
- Uint num = rp->dictionary->numElements;
- res = erts_dictionary_copy(hfact, rp->dictionary, reserve_size);
- *reds += (Uint) num / 4;
- }
- break;
- case ERTS_PI_IX_TRAP_EXIT:
- res = (rp->flags & F_TRAP_EXIT) ? am_true : am_false;
- break;
- case ERTS_PI_IX_ERROR_HANDLER:
- res = erts_proc_get_error_handler(rp);
- break;
- case ERTS_PI_IX_HEAP_SIZE: {
- Uint hsz = 0;
- (void) erts_bld_uint(NULL, &hsz, HEAP_SIZE(rp));
- hp = erts_produce_heap(hfact, hsz, reserve_size);
- res = erts_bld_uint(&hp, NULL, HEAP_SIZE(rp));
- break;
- }
- case ERTS_PI_IX_FULLSWEEP_AFTER: {
- Uint hsz = 0;
- (void) erts_bld_uint(NULL, &hsz, MAX_GEN_GCS(rp));
- hp = erts_produce_heap(hfact, hsz, reserve_size);
- res = erts_bld_uint(&hp, NULL, MAX_GEN_GCS(rp));
- break;
- }
- case ERTS_PI_IX_MIN_HEAP_SIZE: {
- Uint hsz = 0;
- (void) erts_bld_uint(NULL, &hsz, MIN_HEAP_SIZE(rp));
- hp = erts_produce_heap(hfact, hsz, reserve_size);
- res = erts_bld_uint(&hp, NULL, MIN_HEAP_SIZE(rp));
- break;
- }
- case ERTS_PI_IX_MIN_BIN_VHEAP_SIZE: {
- Uint hsz = 0;
- (void) erts_bld_uint(NULL, &hsz, MIN_VHEAP_SIZE(rp));
- hp = erts_produce_heap(hfact, hsz, reserve_size);
- res = erts_bld_uint(&hp, NULL, MIN_VHEAP_SIZE(rp));
- break;
- }
- case ERTS_PI_IX_MAX_HEAP_SIZE: {
- Uint hsz = 0;
- (void) erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp),
- MAX_HEAP_SIZE_FLAGS_GET(rp),
- NULL, &hsz);
- hp = er…
Large files files are truncated, but you can click here to view the full file