diff options
Diffstat (limited to 'erts/emulator/beam/erl_bif_info.c')
-rw-r--r-- | erts/emulator/beam/erl_bif_info.c | 792 |
1 files changed, 543 insertions, 249 deletions
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 7791231d56..80adca0072 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -48,6 +48,7 @@ #include "erl_map.h" #define ERTS_PTAB_WANT_DEBUG_FUNCS__ #include "erl_ptab.h" +#include "erl_time.h" #ifdef HIPE #include "hipe_arch.h" #endif @@ -94,6 +95,9 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE #if defined(ERTS_DIRTY_SCHEDULERS) && defined(ERTS_SMP) " [ds:%beu:%beu:%beu]" #endif +#if defined(ERTS_DIRTY_SCHEDULERS_TEST) + " [dirty-schedulers-TEST]" +#endif " [async-threads:%d]" #endif #ifdef HIPE @@ -174,7 +178,33 @@ bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh) if (szp) *szp += 4+2; if (hpp) { - Uint refc = (Uint) erts_refc_read(&pb->val->refc, 1); + 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; @@ -199,8 +229,10 @@ bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh) static void do_calc_mon_size(ErtsMonitor *mon, void *vpsz) { Uint *psz = vpsz; - *psz += IS_CONST(mon->ref) ? 0 : NC_HEAP_SIZE(mon->ref); - *psz += IS_CONST(mon->pid) ? 0 : NC_HEAP_SIZE(mon->pid); + *psz += NC_HEAP_SIZE(mon->ref); + *psz += (mon->type == MON_NIF_TARGET ? + erts_resource_ref_size(mon->u.resource) : + (is_immed(mon->u.pid) ? 0 : NC_HEAP_SIZE(mon->u.pid))); *psz += 8; /* CONS + 5-tuple */ } @@ -215,12 +247,11 @@ static void do_make_one_mon_element(ErtsMonitor *mon, void * vpmlc) { MonListContext *pmlc = vpmlc; Eterm tup; - Eterm r = (IS_CONST(mon->ref) - ? mon->ref - : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->ref)); - Eterm p = (IS_CONST(mon->pid) - ? mon->pid - : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->pid)); + Eterm r = STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->ref); + Eterm p = (mon->type == MON_NIF_TARGET ? + erts_bld_resource_ref(&(pmlc->hp), &MSO(pmlc->p), mon->u.resource) + : (is_immed(mon->u.pid) ? mon->u.pid + : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->u.pid))); tup = TUPLE5(pmlc->hp, pmlc->tag, make_small(mon->type), r, p, mon->name); pmlc->hp += 6; pmlc->res = CONS(pmlc->hp, tup, pmlc->res); @@ -259,7 +290,7 @@ make_monitor_list(Process *p, ErtsMonitor *root) static void do_calc_lnk_size(ErtsLink *lnk, void *vpsz) { Uint *psz = vpsz; - *psz += IS_CONST(lnk->pid) ? 0 : NC_HEAP_SIZE(lnk->pid); + *psz += is_immed(lnk->pid) ? 0 : NC_HEAP_SIZE(lnk->pid); if (lnk->type != LINK_NODE && ERTS_LINK_ROOT(lnk) != NULL) { /* Node links use this pointer as ref counter... */ erts_doforall_links(ERTS_LINK_ROOT(lnk),&do_calc_lnk_size,vpsz); @@ -279,7 +310,7 @@ static void do_make_one_lnk_element(ErtsLink *lnk, void * vpllc) LnkListContext *pllc = vpllc; Eterm tup; Eterm old_res, targets = NIL; - Eterm p = (IS_CONST(lnk->pid) + Eterm p = (is_immed(lnk->pid) ? lnk->pid : STORE_NC(&(pllc->hp), &MSO(pllc->p), lnk->pid)); if (lnk->type == LINK_NODE) { @@ -363,8 +394,12 @@ erts_print_system_version(fmtfn_t to, void *arg, Process *c_p) 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 */ - Eterm entity; + * {Entity,Node} = {monitor.Name,erlang:node()} for internal by name + * {Entity,Node} = {monitor.resource,MON_NIF_TARGET}*/ + union { + Eterm term; + ErtsResource* resource; + }entity; Eterm node; /* pid is actual target being monitored, no matter pid/port or name */ Eterm pid; @@ -410,7 +445,7 @@ static void collect_one_link(ErtsLink *lnk, void *vmicp) if (!(lnk->type == LINK_PID)) { return; } - micp->mi[micp->mi_i].entity = lnk->pid; + micp->mi[micp->mi_i].entity.term = lnk->pid; micp->sz += 2 + NC_HEAP_SIZE(lnk->pid); micp->mi_i++; } @@ -423,20 +458,20 @@ static void collect_one_origin_monitor(ErtsMonitor *mon, void *vmicp) return; } EXTEND_MONITOR_INFOS(micp); - if (is_atom(mon->pid)) { /* external by name */ - micp->mi[micp->mi_i].entity = mon->name; - micp->mi[micp->mi_i].node = mon->pid; + if (is_atom(mon->u.pid)) { /* external by name */ + micp->mi[micp->mi_i].entity.term = mon->name; + micp->mi[micp->mi_i].node = mon->u.pid; micp->sz += 3; /* need one 2-tuple */ - } else if (is_external_pid(mon->pid)) { /* external by pid */ - micp->mi[micp->mi_i].entity = mon->pid; + } else if (is_external_pid(mon->u.pid)) { /* external by pid */ + micp->mi[micp->mi_i].entity.term = mon->u.pid; micp->mi[micp->mi_i].node = NIL; - micp->sz += NC_HEAP_SIZE(mon->pid); + micp->sz += NC_HEAP_SIZE(mon->u.pid); } else if (!is_nil(mon->name)) { /* internal by name */ - micp->mi[micp->mi_i].entity = mon->name; + micp->mi[micp->mi_i].entity.term = mon->name; micp->mi[micp->mi_i].node = erts_this_dist_entry->sysname; micp->sz += 3; /* need one 2-tuple */ } else { /* internal by pid */ - micp->mi[micp->mi_i].entity = mon->pid; + micp->mi[micp->mi_i].entity.term = mon->u.pid; micp->mi[micp->mi_i].node = NIL; /* no additional heap space needed */ } @@ -444,7 +479,7 @@ static void collect_one_origin_monitor(ErtsMonitor *mon, void *vmicp) /* 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->pid; + micp->mi[micp->mi_i].pid = mon->u.pid; micp->mi_i++; micp->sz += 2 + 3; /* For a cons cell and a 2-tuple */ @@ -454,15 +489,24 @@ static void collect_one_target_monitor(ErtsMonitor *mon, void *vmicp) { MonitorInfoCollection *micp = vmicp; - if (mon->type != MON_TARGET) { - return; + if (mon->type != MON_TARGET && mon->type != MON_NIF_TARGET) { + return; } EXTEND_MONITOR_INFOS(micp); - micp->mi[micp->mi_i].node = NIL; - micp->mi[micp->mi_i].entity = mon->pid; - micp->sz += (NC_HEAP_SIZE(mon->pid) + 2 /* cons */); + + if (mon->type == MON_NIF_TARGET) { + micp->mi[micp->mi_i].entity.resource = mon->u.resource; + micp->mi[micp->mi_i].node = make_small(MON_NIF_TARGET); + micp->sz += erts_resource_ref_size(mon->u.resource); + } + else { + micp->mi[micp->mi_i].entity.term = mon->u.pid; + micp->mi[micp->mi_i].node = NIL; + micp->sz += NC_HEAP_SIZE(mon->u.pid); + } + micp->sz += 2; /* cons */; micp->mi_i++; } @@ -610,7 +654,8 @@ static Eterm pi_args[] = { am_current_location, am_current_stacktrace, am_message_queue_data, - am_garbage_collection_info + am_garbage_collection_info, + am_magic_ref }; #define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(Eterm))) @@ -661,6 +706,7 @@ pi_arg2ix(Eterm arg) case am_current_stacktrace: return 31; case am_message_queue_data: return 32; case am_garbage_collection_info: return 33; + case am_magic_ref: return 34; default: return -1; } } @@ -1114,9 +1160,9 @@ process_info_aux(Process *BIF_P, case am_initial_call: hp = HAlloc(BIF_P, 3+4); res = TUPLE3(hp, - rp->u.initial[INITIAL_MOD], - rp->u.initial[INITIAL_FUN], - make_small(rp->u.initial[INITIAL_ARI])); + rp->u.initial.module, + rp->u.initial.function, + make_small(rp->u.initial.arity)); hp += 4; break; @@ -1191,7 +1237,7 @@ process_info_aux(Process *BIF_P, hp = HAlloc(BIF_P, 3 + mic.sz); res = NIL; for (i = 0; i < mic.mi_i; i++) { - item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity); + item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity.term); res = CONS(hp, item, res); hp += 2; } @@ -1209,7 +1255,7 @@ process_info_aux(Process *BIF_P, hp = HAlloc(BIF_P, 3 + mic.sz); res = NIL; for (i = 0; i < mic.mi_i; i++) { - if (is_atom(mic.mi[i].entity)) { + if (is_atom(mic.mi[i].entity.term)) { /* Monitor by name. * Build {process|port, {Name, Node}} and cons it. */ @@ -1221,7 +1267,7 @@ process_info_aux(Process *BIF_P, || is_port(mic.mi[i].pid) || is_atom(mic.mi[i].pid)); - t1 = TUPLE2(hp, mic.mi[i].entity, mic.mi[i].node); + t1 = TUPLE2(hp, mic.mi[i].entity.term, mic.mi[i].node); hp += 3; t2 = TUPLE2(hp, m_type, t1); hp += 3; @@ -1231,7 +1277,7 @@ process_info_aux(Process *BIF_P, else { /* Monitor by pid. Build {process|port, Pid} and cons it. */ Eterm t; - Eterm pid = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity); + Eterm pid = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity.term); Eterm m_type = is_port(mic.mi[i].pid) ? am_port : am_process; ASSERT(is_pid(mic.mi[i].pid) @@ -1258,7 +1304,12 @@ process_info_aux(Process *BIF_P, res = NIL; for (i = 0; i < mic.mi_i; ++i) { - item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity); + if (mic.mi[i].node == make_small(MON_NIF_TARGET)) { + item = erts_bld_resource_ref(&hp, &MSO(BIF_P), mic.mi[i].entity.resource); + } + else { + item = STORE_NC(&hp, &MSO(BIF_P), mic.mi[i].entity.term); + } res = CONS(hp, item, res); hp += 2; } @@ -1563,9 +1614,9 @@ process_info_aux(Process *BIF_P, term = am_timeout; else { term = TUPLE3(hp, - scb->ct[j]->code[0], - scb->ct[j]->code[1], - make_small(scb->ct[j]->code[2])); + scb->ct[j]->info.mfa.module, + scb->ct[j]->info.mfa.function, + make_small(scb->ct[j]->info.mfa.arity)); hp += 4; } list = CONS(hp, term, list); @@ -1596,6 +1647,14 @@ process_info_aux(Process *BIF_P, hp = HAlloc(BIF_P, 3); break; + case am_magic_ref: { + Uint sz = 3; + (void) bld_magic_ref_bin_list(NULL, &sz, &MSO(rp)); + hp = HAlloc(BIF_P, sz); + res = bld_magic_ref_bin_list(&hp, NULL, &MSO(rp)); + break; + } + default: return THE_NON_VALUE; /* will produce badarg */ @@ -1614,10 +1673,10 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) if (rp->current == NULL) { erts_lookup_function_info(&fi, rp->i, full_info); - rp->current = fi.current; + rp->current = fi.mfa; } else if (full_info) { erts_lookup_function_info(&fi, rp->i, full_info); - if (fi.current == NULL) { + if (fi.mfa == NULL) { /* Use the current function without location info */ erts_set_current_function(&fi, rp->current); } @@ -1633,9 +1692,9 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) * instead if it can be looked up. */ erts_lookup_function_info(&fi2, rp->cp, full_info); - if (fi2.current) { + if (fi2.mfa) { fi = fi2; - rp->current = fi2.current; + rp->current = fi2.mfa; } } @@ -1650,8 +1709,9 @@ current_function(Process* BIF_P, Process* rp, Eterm** hpp, int full_info) hp = erts_build_mfa_item(&fi, hp, am_true, &res); } else { hp = HAlloc(BIF_P, 3+4); - res = TUPLE3(hp, rp->current[0], - rp->current[1], make_small(rp->current[2])); + res = TUPLE3(hp, rp->current->module, + rp->current->function, + make_small(rp->current->arity)); hp += 4; } *hpp = hp; @@ -1692,7 +1752,7 @@ current_stacktrace(Process* p, Process* rp, Eterm** hpp) heap_size = 3; for (i = 0; i < depth; i++) { erts_lookup_function_info(stkp, s->trace[i], 1); - if (stkp->current) { + if (stkp->mfa) { heap_size += stkp->needed + 2; stkp++; } @@ -2391,7 +2451,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) ERTS_ATOM_ENC_LATIN1, 1), erts_bld_uint(hpp, hszp, - opc[i].count)), + erts_instr_count[i])), res); } @@ -2676,20 +2736,30 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) erts_schedulers_state(NULL, NULL, &active, NULL, NULL, NULL, NULL, NULL); BIF_RET(make_small(active)); #endif -#if defined(ERTS_SMP) && defined(ERTS_DIRTY_SCHEDULERS) } else if (ERTS_IS_ATOM_STR("dirty_cpu_schedulers", BIF_ARG_1)) { Uint dirty_cpu; +#ifdef ERTS_DIRTY_SCHEDULERS erts_schedulers_state(NULL, NULL, NULL, &dirty_cpu, NULL, NULL, NULL, NULL); +#else + dirty_cpu = 0; +#endif BIF_RET(make_small(dirty_cpu)); } else if (ERTS_IS_ATOM_STR("dirty_cpu_schedulers_online", BIF_ARG_1)) { Uint dirty_cpu_onln; +#ifdef ERTS_DIRTY_SCHEDULERS erts_schedulers_state(NULL, NULL, NULL, NULL, &dirty_cpu_onln, NULL, NULL, NULL); +#else + dirty_cpu_onln = 0; +#endif BIF_RET(make_small(dirty_cpu_onln)); } else if (ERTS_IS_ATOM_STR("dirty_io_schedulers", BIF_ARG_1)) { Uint dirty_io; +#ifdef ERTS_DIRTY_SCHEDULERS erts_schedulers_state(NULL, NULL, NULL, NULL, NULL, NULL, &dirty_io, NULL); - BIF_RET(make_small(dirty_io)); +#else + dirty_io = 0; #endif + BIF_RET(make_small(dirty_io)); } else if (ERTS_IS_ATOM_STR("run_queues", BIF_ARG_1)) { res = make_small(erts_no_run_queues); BIF_RET(res); @@ -2859,6 +2929,12 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) else if (ERTS_IS_ATOM_STR("ets_limit",BIF_ARG_1)) { BIF_RET(make_small(erts_db_get_max_tabs())); } + else if (ERTS_IS_ATOM_STR("atom_limit",BIF_ARG_1)) { + BIF_RET(make_small(erts_get_atom_limit())); + } + else if (ERTS_IS_ATOM_STR("atom_count",BIF_ARG_1)) { + BIF_RET(make_small(atom_table_size())); + } else if (ERTS_IS_ATOM_STR("tolerant_timeofday",BIF_ARG_1)) { if (erts_has_time_correction() && erts_time_offset_state() == ERTS_TIME_OFFSET_FINAL) { @@ -2883,27 +2959,6 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) BIF_RET(AM_tag); #endif } - else if (ERTS_IS_ATOM_STR("check_process_code",BIF_ARG_1)) { - Eterm terms[3]; - Sint length = 1; - Uint sz = 0; - Eterm *hp, res; - DECL_AM(direct_references); - - terms[0] = AM_direct_references; -#if !defined(ERTS_NEW_PURGE_STRATEGY) - { - DECL_AM(indirect_references); - terms[1] = AM_indirect_references; - terms[2] = am_copy_literals; - length = 3; - } -#endif - erts_bld_list(NULL, &sz, length, terms); - hp = HAlloc(BIF_P, sz); - res = erts_bld_list(&hp, NULL, length, terms); - BIF_RET(res); - } BIF_ERROR(BIF_P, BADARG); } @@ -2951,7 +3006,7 @@ erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, if (hpp) { res = NIL; for (i = 0; i < mic.mi_i; i++) { - item = STORE_NC(hpp, ohp, mic.mi[i].entity); + item = STORE_NC(hpp, ohp, mic.mi[i].entity.term); res = CONS(*hpp, item, res); *hpp += 2; } @@ -2982,7 +3037,7 @@ erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, Eterm t; Eterm m_type; - item = STORE_NC(hpp, ohp, mic.mi[i].entity); + item = STORE_NC(hpp, ohp, mic.mi[i].entity.term); m_type = is_port(item) ? am_port : am_process; t = TUPLE2(*hpp, m_type, item); *hpp += 3; @@ -3011,7 +3066,8 @@ erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, if (hpp) { res = NIL; for (i = 0; i < mic.mi_i; ++i) { - item = STORE_NC(hpp, ohp, mic.mi[i].entity); + ASSERT(mic.mi[i].node == NIL); + item = STORE_NC(hpp, ohp, mic.mi[i].entity.term); res = CONS(*hpp, item, res); *hpp += 2; } @@ -3248,7 +3304,7 @@ fun_info_2(BIF_ALIST_2) break; case am_module: hp = HAlloc(p, 3); - val = exp->code[0]; + val = exp->info.mfa.module; break; case am_new_index: hp = HAlloc(p, 3); @@ -3276,11 +3332,11 @@ fun_info_2(BIF_ALIST_2) break; case am_arity: hp = HAlloc(p, 3); - val = make_small(exp->code[2]); + val = make_small(exp->info.mfa.arity); break; case am_name: hp = HAlloc(p, 3); - val = exp->code[1]; + val = exp->info.mfa.function; break; default: goto error; @@ -3306,7 +3362,9 @@ fun_info_mfa_1(BIF_ALIST_1) } else if (is_export(fun)) { Export* exp = (Export *) ((UWord) (export_val(fun))[1]); hp = HAlloc(p, 4); - BIF_RET(TUPLE3(hp,exp->code[0],exp->code[1],make_small(exp->code[2]))); + BIF_RET(TUPLE3(hp,exp->info.mfa.module, + exp->info.mfa.function, + make_small(exp->info.mfa.arity))); } BIF_ERROR(p, BADARG); } @@ -3384,13 +3442,24 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) Eterm* hp; if (BIF_ARG_1 == am_scheduler_wall_time) { - res = erts_sched_wall_time_request(BIF_P, 0, 0); + res = erts_sched_wall_time_request(BIF_P, 0, 0, 1, 0); if (is_non_value(res)) BIF_RET(am_undefined); BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res); - } else if (BIF_ARG_1 == am_total_active_tasks - || BIF_ARG_1 == am_total_run_queue_lengths) { - Uint no = erts_run_queues_len(NULL, 0, BIF_ARG_1 == am_total_active_tasks); + } else if (BIF_ARG_1 == am_scheduler_wall_time_all) { + res = erts_sched_wall_time_request(BIF_P, 0, 0, 1, 1); + if (is_non_value(res)) + BIF_RET(am_undefined); + BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res); + } else if ((BIF_ARG_1 == am_total_active_tasks) + | (BIF_ARG_1 == am_total_run_queue_lengths) + | (BIF_ARG_1 == am_total_active_tasks_all) + | (BIF_ARG_1 == am_total_run_queue_lengths_all)) { + Uint no = erts_run_queues_len(NULL, 0, + ((BIF_ARG_1 == am_total_active_tasks) + | (BIF_ARG_1 == am_total_active_tasks_all)), + ((BIF_ARG_1 == am_total_active_tasks_all) + | (BIF_ARG_1 == am_total_run_queue_lengths_all))); if (IS_USMALL(0, no)) res = make_small(no); else { @@ -3398,13 +3467,21 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) res = uint_to_big(no, hp); } BIF_RET(res); - } else if (BIF_ARG_1 == am_active_tasks - || BIF_ARG_1 == am_run_queue_lengths) { + } else if ((BIF_ARG_1 == am_active_tasks) + | (BIF_ARG_1 == am_run_queue_lengths) + | (BIF_ARG_1 == am_active_tasks_all) + | (BIF_ARG_1 == am_run_queue_lengths_all)) { Eterm res, *hp, **hpp; Uint sz, *szp; - int no_qs = erts_no_run_queues; + int incl_dirty_io = ((BIF_ARG_1 == am_active_tasks_all) + | (BIF_ARG_1 == am_run_queue_lengths_all)); + int no_qs = (erts_no_run_queues + ERTS_NUM_DIRTY_CPU_RUNQS + + (incl_dirty_io ? ERTS_NUM_DIRTY_IO_RUNQS : 0)); Uint *qszs = erts_alloc(ERTS_ALC_T_TMP,sizeof(Uint)*no_qs*2); - (void) erts_run_queues_len(qszs, 0, BIF_ARG_1 == am_active_tasks); + (void) erts_run_queues_len(qszs, 0, + ((BIF_ARG_1 == am_active_tasks) + | (BIF_ARG_1 == am_active_tasks_all)), + incl_dirty_io); sz = 0; szp = &sz; hpp = NULL; @@ -3471,7 +3548,7 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) ErtsMonotonicTime u1, u2; Eterm b1, b2; Uint hsz; - elapsed_time_both(&u1, NULL, &u2, NULL); + erts_runtime_elapsed_both(&u1, NULL, &u2, NULL); hsz = 3; /* 2-tuple */ (void) erts_bld_monotonic_time(NULL, &hsz, u1); (void) erts_bld_monotonic_time(NULL, &hsz, u2); @@ -3481,13 +3558,13 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) res = TUPLE2(hp, b1, b2); BIF_RET(res); } else if (BIF_ARG_1 == am_run_queue) { - res = erts_run_queues_len(NULL, 1, 0); + res = erts_run_queues_len(NULL, 1, 0, 0); BIF_RET(make_small(res)); } else if (BIF_ARG_1 == am_wall_clock) { ErtsMonotonicTime w1, w2; Eterm b1, b2; Uint hsz; - wall_clock_elapsed_time_both(&w1, &w2); + erts_wall_clock_elapsed_both(&w1, &w2); hsz = 3; /* 2-tuple */ (void) erts_bld_monotonic_time(NULL, &hsz, w1); (void) erts_bld_monotonic_time(NULL, &hsz, w2); @@ -3503,9 +3580,9 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) else if (ERTS_IS_ATOM_STR("run_queues", BIF_ARG_1)) { Eterm res, *hp, **hpp; Uint sz, *szp; - int no_qs = erts_no_run_queues; + int no_qs = erts_no_run_queues + ERTS_NUM_DIRTY_RUNQS; Uint *qszs = erts_alloc(ERTS_ALC_T_TMP,sizeof(Uint)*no_qs*2); - (void) erts_run_queues_len(qszs, 0, 0); + (void) erts_run_queues_len(qszs, 0, 0, 1); sz = 0; szp = &sz; hpp = NULL; @@ -3533,6 +3610,11 @@ BIF_RETTYPE error_logger_warning_map_0(BIF_ALIST_0) static erts_smp_atomic_t available_internal_state; +static int empty_magic_ref_destructor(Binary *bin) +{ + return 1; +} + BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) { /* @@ -3571,7 +3653,9 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) else if (ERTS_IS_ATOM_STR("DbTable_words", BIF_ARG_1)) { /* Used by ets_SUITE (stdlib) */ size_t words = (sizeof(DbTable) + sizeof(Uint) - 1)/sizeof(Uint); - BIF_RET(make_small((Uint) words)); + Eterm* hp = HAlloc(BIF_P ,3); + BIF_RET(TUPLE2(hp, make_small((Uint) words), + erts_ets_hash_sizeof_ext_segtab())); } else if (ERTS_IS_ATOM_STR("check_io_debug", BIF_ARG_1)) { /* Used by driver_SUITE (emulator) */ @@ -3682,6 +3766,21 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) BIF_RET(erts_sint64_to_big(value, &hp)); } } + else if (ERTS_IS_ATOM_STR("stack_check", BIF_ARG_1)) { + UWord size; + char c; + if (erts_is_above_stack_limit(&c)) + size = erts_check_stack_recursion_downwards(&c); + else + size = erts_check_stack_recursion_upwards(&c); + if (IS_SSMALL(size)) + BIF_RET(make_small(size)); + else { + Uint hsz = BIG_UWORD_HEAP_SIZE(size); + Eterm *hp = HAlloc(BIF_P, hsz); + BIF_RET(uword_to_big(size, hp)); + } + } } else if (is_tuple(BIF_ARG_1)) { Eterm* tp = tuple_val(BIF_ARG_1); @@ -3874,7 +3973,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) BIF_RET(erts_debug_reader_groups_map(BIF_P, (int) groups)); } else if (ERTS_IS_ATOM_STR("internal_hash", tp[1])) { - Uint hash = (Uint) make_internal_hash(tp[2]); + Uint hash = (Uint) make_internal_hash(tp[2], 0); Uint hsz = 0; Eterm* hp; erts_bld_uint(NULL, &hsz, hash); @@ -3892,6 +3991,34 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) } return make_atom(ix); } + else if (ERTS_IS_ATOM_STR("magic_ref", tp[1])) { + Binary *bin; + UWord bin_addr, refc; + Eterm bin_addr_term, refc_term, test_type; + Uint sz; + Eterm *hp; + if (!is_internal_magic_ref(tp[2])) { + if (is_internal_ordinary_ref(tp[2])) { + ErtsORefThing *rtp; + rtp = (ErtsORefThing *) internal_ref_val(tp[2]); + if (erts_is_ref_numbers_magic(rtp->num)) + BIF_RET(am_true); + } + BIF_RET(am_false); + } + bin = erts_magic_ref2bin(tp[2]); + refc = erts_refc_read(&bin->intern.refc, 1); + bin_addr = (UWord) bin; + sz = 4; + erts_bld_uword(NULL, &sz, bin_addr); + erts_bld_uword(NULL, &sz, refc); + hp = HAlloc(BIF_P, sz); + bin_addr_term = erts_bld_uword(&hp, NULL, bin_addr); + refc_term = erts_bld_uword(&hp, NULL, refc); + test_type = (ERTS_MAGIC_BIN_DESTRUCTOR(bin) == empty_magic_ref_destructor + ? am_true : am_false); + BIF_RET(TUPLE3(hp, bin_addr_term, refc_term, test_type)); + } break; } @@ -3980,7 +4107,6 @@ static void broken_halt_test(Eterm bif_arg_2) erts_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); } - BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) { /* @@ -4306,54 +4432,141 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) } BIF_RET(am_ok); } + else if (ERTS_IS_ATOM_STR("make", BIF_ARG_1)) { + if (ERTS_IS_ATOM_STR("magic_ref", BIF_ARG_2)) { + Binary *bin = erts_create_magic_binary(0, empty_magic_ref_destructor); + UWord bin_addr = (UWord) bin; + Eterm bin_addr_term, magic_ref, res; + Eterm *hp; + Uint sz = ERTS_MAGIC_REF_THING_SIZE + 3; + erts_bld_uword(NULL, &sz, bin_addr); + hp = HAlloc(BIF_P, sz); + bin_addr_term = erts_bld_uword(&hp, NULL, bin_addr); + magic_ref = erts_mk_magic_ref(&hp, &BIF_P->off_heap, bin); + res = TUPLE2(hp, magic_ref, bin_addr_term); + BIF_RET(res); + } + } } BIF_ERROR(BIF_P, BADARG); } #ifdef ERTS_ENABLE_LOCK_COUNT + +typedef struct { + /* info->location_count may increase between size calculation and term + * building, so we cap it at the value sampled in lcnt_build_result_vector. + * + * Shrinking is safe though. */ + int max_location_count; + erts_lcnt_lock_info_t *info; +} lcnt_sample_t; + +typedef struct lcnt_sample_vector_ { + lcnt_sample_t *elements; + size_t size; +} lcnt_sample_vector_t; + +static lcnt_sample_vector_t lcnt_build_sample_vector(erts_lcnt_lock_info_list_t *list) { + erts_lcnt_lock_info_t *iterator; + lcnt_sample_vector_t result; + size_t allocated_entries; + + allocated_entries = 64; + result.size = 0; + + result.elements = erts_alloc(ERTS_ALC_T_LCNT_VECTOR, + allocated_entries * sizeof(lcnt_sample_t)); + + iterator = NULL; + while(erts_lcnt_iterate_list(list, &iterator)) { + erts_lcnt_retain_lock_info(iterator); + + result.elements[result.size].max_location_count = iterator->location_count; + result.elements[result.size].info = iterator; + + result.size++; + + if(result.size >= allocated_entries) { + allocated_entries *= 2; + + result.elements = erts_realloc(ERTS_ALC_T_LCNT_VECTOR, result.elements, + allocated_entries * sizeof(lcnt_sample_t)); + } + } + + return result; +} + +static void lcnt_destroy_sample_vector(lcnt_sample_vector_t *vector) { + size_t i; + + for(i = 0; i < vector->size; i++) { + erts_lcnt_release_lock_info(vector->elements[i].info); + } + + erts_free(ERTS_ALC_T_LCNT_VECTOR, vector->elements); +} + +/* The size of an integer is not guaranteed to be constant since we're walking + * over live data, and may cross over into bignum territory between size calc + * and the actual build. This takes care of that through always assuming the + * worst, but needs to be fixed up with HRelease once the final term has been + * built. */ +static ERTS_INLINE Eterm bld_unstable_uint64(Uint **hpp, Uint *szp, Uint64 ui) { + Eterm res = THE_NON_VALUE; + + if(szp) { + *szp += ERTS_UINT64_HEAP_SIZE(~((Uint64) 0)); + } + + if(hpp) { + if (IS_USMALL(0, ui)) { + res = make_small(ui); + } else { + res = erts_uint64_to_big(ui, hpp); + } + } + + return res; +} + static Eterm lcnt_build_lock_stats_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_stats_t *stats, Eterm res) { - Uint tries = 0, colls = 0; - unsigned long timer_s = 0, timer_ns = 0, timer_n = 0; - unsigned int line = 0; unsigned int i; - + const char *file; + Eterm af, uil; Eterm uit, uic; Eterm uits, uitns, uitn; Eterm tt, tstat, tloc, t; Eterm thist, vhist[ERTS_LCNT_HISTOGRAM_SLOT_SIZE]; - + /* term: - * [{{file, line}, {tries, colls, {seconds, nanoseconds, n_blocks}}, - * { .. histogram .. }] - */ + * [{{file, line}, + {tries, colls, {seconds, nanoseconds, n_blocks}}, + * { .. histogram .. }] */ - tries = (Uint) ethr_atomic_read(&stats->tries); - colls = (Uint) ethr_atomic_read(&stats->colls); - - line = stats->line; - timer_s = stats->timer.s; - timer_ns = stats->timer.ns; - timer_n = stats->timer_n; - - af = erts_atom_put((byte *)stats->file, strlen(stats->file), ERTS_ATOM_ENC_LATIN1, 1); - uil = erts_bld_uint( hpp, szp, line); + file = stats->file ? stats->file : "undefined"; + + af = erts_atom_put((byte *)file, strlen(file), ERTS_ATOM_ENC_LATIN1, 1); + uil = erts_bld_uint( hpp, szp, stats->line); tloc = erts_bld_tuple(hpp, szp, 2, af, uil); - - uit = erts_bld_uint( hpp, szp, tries); - uic = erts_bld_uint( hpp, szp, colls); - uits = erts_bld_uint( hpp, szp, timer_s); - uitns = erts_bld_uint( hpp, szp, timer_ns); - uitn = erts_bld_uint( hpp, szp, timer_n); + uit = bld_unstable_uint64(hpp, szp, (Uint)ethr_atomic_read(&stats->attempts)); + uic = bld_unstable_uint64(hpp, szp, (Uint)ethr_atomic_read(&stats->collisions)); + + uits = bld_unstable_uint64(hpp, szp, stats->total_time_waited.s); + uitns = bld_unstable_uint64(hpp, szp, stats->total_time_waited.ns); + uitn = bld_unstable_uint64(hpp, szp, stats->times_waited); tt = erts_bld_tuple(hpp, szp, 3, uits, uitns, uitn); tstat = erts_bld_tuple(hpp, szp, 3, uit, uic, tt); for(i = 0; i < ERTS_LCNT_HISTOGRAM_SLOT_SIZE; i++) { - vhist[i] = erts_bld_uint(hpp, szp, stats->hist.ns[i]); + vhist[i] = bld_unstable_uint64(hpp, szp, stats->wait_time_histogram.ns[i]); } + thist = erts_bld_tuplev(hpp, szp, ERTS_LCNT_HISTOGRAM_SLOT_SIZE, vhist); t = erts_bld_tuple(hpp, szp, 3, tloc, tstat, thist); @@ -4362,185 +4575,266 @@ static Eterm lcnt_build_lock_stats_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_s return res; } -static Eterm lcnt_build_lock_term(Eterm **hpp, Uint *szp, erts_lcnt_lock_t *lock, Eterm res) { +static Eterm lcnt_pretty_print_lock_id(erts_lcnt_lock_info_t *info) { + Eterm id = info->id; + + if((info->flags & ERTS_LOCK_FLAGS_MASK_TYPE) == ERTS_LOCK_FLAGS_TYPE_PROCLOCK) { + /* Use registered names as id's for process locks if available. Thread + * progress is delayed since we may be running on a dirty scheduler. */ + ErtsThrPrgrDelayHandle delay_handle; + Process *process; + + delay_handle = erts_thr_progress_unmanaged_delay(); + + process = erts_proc_lookup(info->id); + if (process && process->common.u.alive.reg) { + id = process->common.u.alive.reg->name; + } + + erts_thr_progress_unmanaged_continue(delay_handle); + } else if(info->flags & ERTS_LOCK_FLAGS_CATEGORY_ALLOCATOR) { + if(is_small(id) && !sys_strcmp(info->name, "alcu_allocator")) { + const char *name = (const char*)ERTS_ALC_A2AD(signed_val(id)); + id = erts_atom_put((byte*)name, strlen(name), ERTS_ATOM_ENC_LATIN1, 1); + } + } + + return id; +} + +static Eterm lcnt_build_lock_term(Eterm **hpp, Uint *szp, lcnt_sample_t *sample, Eterm res) { + erts_lcnt_lock_info_t *info = sample->info; + Eterm name, type, id, stats = NIL, t; - Process *proc = NULL; - char *ltype; + const char *lock_desc; int i; + + /* term: [{name, id, type, stats()}] */ + + ASSERT(info->name); - /* term: - * [{name, id, type, stats()}] - */ - - ASSERT(lock->name); - - ltype = erts_lcnt_lock_type(lock->flag); - - ASSERT(ltype); - - type = erts_atom_put((byte *)ltype, strlen(ltype), ERTS_ATOM_ENC_LATIN1, 1); - name = erts_atom_put((byte *)lock->name, strlen(lock->name), ERTS_ATOM_ENC_LATIN1, 1); - - if (lock->flag & ERTS_LCNT_LT_ALLOC) { - /* use allocator types names as id's for allocator locks */ - ltype = (char *) ERTS_ALC_A2AD(signed_val(lock->id)); - id = erts_atom_put((byte *)ltype, strlen(ltype), ERTS_ATOM_ENC_LATIN1, 1); - } else if (lock->flag & ERTS_LCNT_LT_PROCLOCK) { - /* use registered names as id's for process locks if available */ - proc = erts_proc_lookup(lock->id); - if (proc && proc->common.u.alive.reg) { - id = proc->common.u.alive.reg->name; - } else { - /* otherwise use process id */ - id = lock->id; - } + lock_desc = erts_lock_flags_get_type_name(info->flags); + + type = erts_atom_put((byte*)lock_desc, strlen(lock_desc), ERTS_ATOM_ENC_LATIN1, 1); + name = erts_atom_put((byte*)info->name, strlen(info->name), ERTS_ATOM_ENC_LATIN1, 1); + + /* Only attempt to resolve ids when actually emitting the term. This ought + * to be safe since all immediates are the same size. */ + if(hpp != NULL) { + id = lcnt_pretty_print_lock_id(info); } else { - id = lock->id; + id = NIL; } - for (i = 0; i < lock->n_stats; i++) { - stats = lcnt_build_lock_stats_term(hpp, szp, &(lock->stats[i]), stats); + for(i = 0; i < MIN(info->location_count, sample->max_location_count); i++) { + stats = lcnt_build_lock_stats_term(hpp, szp, &(info->location_stats[i]), stats); } t = erts_bld_tuple(hpp, szp, 4, name, id, type, stats); - res = erts_bld_cons( hpp, szp, t, res); + res = erts_bld_cons(hpp, szp, t, res); return res; } -static Eterm lcnt_build_result_term(Eterm **hpp, Uint *szp, erts_lcnt_data_t *data, Eterm res) { +static Eterm lcnt_build_result_term(Eterm **hpp, Uint *szp, erts_lcnt_time_t *duration, + lcnt_sample_vector_t *current_locks, + lcnt_sample_vector_t *deleted_locks, Eterm res) { + const char *str_duration = "duration"; + const char *str_locks = "locks"; + Eterm dts, dtns, tdt, adur, tdur, aloc, lloc = NIL, tloc; - erts_lcnt_lock_t *lock = NULL; - char *str_duration = "duration"; - char *str_locks = "locks"; - - /* term: - * [{'duration', {seconds, nanoseconds}}, {'locks', locks()}] - */ - + size_t i; + + /* term: [{'duration', {seconds, nanoseconds}}, {'locks', locks()}] */ + /* duration tuple */ - dts = erts_bld_uint( hpp, szp, data->duration.s); - dtns = erts_bld_uint( hpp, szp, data->duration.ns); + dts = bld_unstable_uint64(hpp, szp, duration->s); + dtns = bld_unstable_uint64(hpp, szp, duration->ns); tdt = erts_bld_tuple(hpp, szp, 2, dts, dtns); - + adur = erts_atom_put((byte *)str_duration, strlen(str_duration), ERTS_ATOM_ENC_LATIN1, 1); tdur = erts_bld_tuple(hpp, szp, 2, adur, tdt); /* lock tuple */ - aloc = erts_atom_put((byte *)str_locks, strlen(str_locks), ERTS_ATOM_ENC_LATIN1, 1); - - for (lock = data->current_locks->head; lock != NULL ; lock = lock->next ) { - lloc = lcnt_build_lock_term(hpp, szp, lock, lloc); + + for(i = 0; i < current_locks->size; i++) { + lloc = lcnt_build_lock_term(hpp, szp, ¤t_locks->elements[i], lloc); } - - for (lock = data->deleted_locks->head; lock != NULL ; lock = lock->next ) { - lloc = lcnt_build_lock_term(hpp, szp, lock, lloc); + + for(i = 0; i < deleted_locks->size; i++) { + lloc = lcnt_build_lock_term(hpp, szp, &deleted_locks->elements[i], lloc); } - + tloc = erts_bld_tuple(hpp, szp, 2, aloc, lloc); - - res = erts_bld_cons( hpp, szp, tloc, res); - res = erts_bld_cons( hpp, szp, tdur, res); + + res = erts_bld_cons(hpp, szp, tloc, res); + res = erts_bld_cons(hpp, szp, tdur, res); return res; -} +} + +static struct { + const char *name; + erts_lock_flags_t flag; +} lcnt_category_map[] = { + {"allocator", ERTS_LOCK_FLAGS_CATEGORY_ALLOCATOR}, + {"db", ERTS_LOCK_FLAGS_CATEGORY_DB}, + {"debug", ERTS_LOCK_FLAGS_CATEGORY_DEBUG}, + {"distribution", ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION}, + {"generic", ERTS_LOCK_FLAGS_CATEGORY_GENERIC}, + {"io", ERTS_LOCK_FLAGS_CATEGORY_IO}, + {"process", ERTS_LOCK_FLAGS_CATEGORY_PROCESS}, + {"scheduler", ERTS_LOCK_FLAGS_CATEGORY_SCHEDULER}, + {NULL, 0} + }; + +static erts_lock_flags_t lcnt_atom_to_lock_category(Eterm atom) { + int i = 0; + + for(i = 0; lcnt_category_map[i].name != NULL; i++) { + if(erts_is_atom_str(lcnt_category_map[i].name, atom, 0)) { + return lcnt_category_map[i].flag; + } + } + + return 0; +} + +static Eterm lcnt_build_category_list(Eterm **hpp, Uint *szp, erts_lock_flags_t mask) { + Eterm res; + int i; + + res = NIL; + + for(i = 0; lcnt_category_map[i].name != NULL; i++) { + if(mask & lcnt_category_map[i].flag) { + Eterm category = erts_atom_put((byte*)lcnt_category_map[i].name, + strlen(lcnt_category_map[i].name), + ERTS_ATOM_ENC_UTF8, 0); + + res = erts_bld_cons(hpp, szp, category, res); + } + } + + return res; +} + #endif -BIF_RETTYPE erts_debug_lock_counters_1(BIF_ALIST_1) +BIF_RETTYPE erts_debug_lcnt_clear_0(BIF_ALIST_0) { -#ifdef ERTS_ENABLE_LOCK_COUNT - Eterm res = NIL; -#endif +#ifndef ERTS_ENABLE_LOCK_COUNT + BIF_RET(am_error); +#else + erts_lcnt_clear_counters(); + BIF_RET(am_ok); +#endif +} - if (BIF_ARG_1 == am_enabled) { -#ifdef ERTS_ENABLE_LOCK_COUNT - BIF_RET(am_true); +BIF_RETTYPE erts_debug_lcnt_collect_0(BIF_ALIST_0) +{ +#ifndef ERTS_ENABLE_LOCK_COUNT + BIF_RET(am_error); #else - BIF_RET(am_false); -#endif - } -#ifdef ERTS_ENABLE_LOCK_COUNT + lcnt_sample_vector_t current_locks, deleted_locks; + erts_lcnt_data_t data; - else if (BIF_ARG_1 == am_info) { - erts_lcnt_data_t *data; - Uint hsize = 0; - Uint *szp; - Eterm* hp; + Eterm *term_heap_start, *term_heap_end; + Uint term_heap_size = 0; + Eterm result; - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + data = erts_lcnt_get_data(); - erts_lcnt_set_rt_opt(ERTS_LCNT_OPT_SUSPEND); - data = erts_lcnt_get_data(); + current_locks = lcnt_build_sample_vector(data.current_locks); + deleted_locks = lcnt_build_sample_vector(data.deleted_locks); - /* calculate size */ + lcnt_build_result_term(NULL, &term_heap_size, &data.duration, + ¤t_locks, &deleted_locks, NIL); - szp = &hsize; - lcnt_build_result_term(NULL, szp, data, NIL); + term_heap_start = HAlloc(BIF_P, term_heap_size); + term_heap_end = term_heap_start; - /* alloc and build */ + result = lcnt_build_result_term(&term_heap_end, NULL, + &data.duration, ¤t_locks, &deleted_locks, NIL); - hp = HAlloc(BIF_P, hsize); + HRelease(BIF_P, term_heap_start + term_heap_size, term_heap_end); - res = lcnt_build_result_term(&hp, NULL, data, res); - - erts_lcnt_clear_rt_opt(ERTS_LCNT_OPT_SUSPEND); + lcnt_destroy_sample_vector(¤t_locks); + lcnt_destroy_sample_vector(&deleted_locks); - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - - BIF_RET(res); - } else if (BIF_ARG_1 == am_clear) { - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + BIF_RET(result); +#endif +} - erts_lcnt_clear_counters(); +BIF_RETTYPE erts_debug_lcnt_control_1(BIF_ALIST_1) +{ +#ifdef ERTS_ENABLE_LOCK_COUNT + if(ERTS_IS_ATOM_STR("mask", BIF_ARG_1)) { + erts_lock_flags_t mask; + Eterm *term_heap_block; + Uint term_heap_size; - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); + mask = erts_lcnt_get_category_mask(); + term_heap_size = 0; - BIF_RET(am_ok); - } else if (is_tuple(BIF_ARG_1)) { - Eterm* ptr = tuple_val(BIF_ARG_1); - - if ((arityval(ptr[0]) == 2) && (ptr[2] == am_false || ptr[2] == am_true)) { - int lock_opt = 0, enable = (ptr[2] == am_true) ? 1 : 0; - if (ERTS_IS_ATOM_STR("copy_save", ptr[1])) { - lock_opt = ERTS_LCNT_OPT_COPYSAVE; - } else if (ERTS_IS_ATOM_STR("process_locks", ptr[1])) { - lock_opt = ERTS_LCNT_OPT_PROCLOCK; - } else if (ERTS_IS_ATOM_STR("port_locks", ptr[1])) { - lock_opt = ERTS_LCNT_OPT_PORTLOCK; - } else if (ERTS_IS_ATOM_STR("suspend", ptr[1])) { - lock_opt = ERTS_LCNT_OPT_SUSPEND; - } else if (ERTS_IS_ATOM_STR("location", ptr[1])) { - lock_opt = ERTS_LCNT_OPT_LOCATION; - } else { - BIF_ERROR(BIF_P, BADARG); - } + lcnt_build_category_list(NULL, &term_heap_size, mask); - erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erts_smp_thr_progress_block(); + term_heap_block = HAlloc(BIF_P, term_heap_size); - if (enable) res = erts_lcnt_set_rt_opt(lock_opt) ? am_true : am_false; - else res = erts_lcnt_clear_rt_opt(lock_opt) ? am_true : am_false; - -#ifdef ERTS_SMP - if (res != ptr[2] && lock_opt == ERTS_LCNT_OPT_PORTLOCK) { - erts_lcnt_enable_io_lock_count(enable); - } else if (res != ptr[2] && lock_opt == ERTS_LCNT_OPT_PROCLOCK) { - erts_lcnt_enable_proc_lock_count(enable); - } + BIF_RET(lcnt_build_category_list(&term_heap_block, NULL, mask)); + } else if(ERTS_IS_ATOM_STR("copy_save", BIF_ARG_1)) { + if(erts_lcnt_get_preserve_info()) { + BIF_RET(am_true); + } + + BIF_RET(am_false); + } #endif - erts_smp_thr_progress_unblock(); - erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); - BIF_RET(res); + BIF_ERROR(BIF_P, BADARG); +} + +BIF_RETTYPE erts_debug_lcnt_control_2(BIF_ALIST_2) +{ +#ifdef ERTS_ENABLE_LOCK_COUNT + if(ERTS_IS_ATOM_STR("mask", BIF_ARG_1)) { + erts_lock_flags_t category_mask = 0; + Eterm categories = BIF_ARG_2; + + if(!(is_list(categories) || is_nil(categories))) { + BIF_ERROR(BIF_P, BADARG); } - } -#endif + while(is_list(categories)) { + Eterm *cell = list_val(categories); + erts_lock_flags_t category; + + category = lcnt_atom_to_lock_category(CAR(cell)); + + if(!category) { + Eterm *hp = HAlloc(BIF_P, 4); + + BIF_RET(TUPLE3(hp, am_error, am_badarg, CAR(cell))); + } + + category_mask |= category; + categories = CDR(cell); + } + + erts_lcnt_set_category_mask(category_mask); + + BIF_RET(am_ok); + } else if(BIF_ARG_2 == am_true || BIF_ARG_2 == am_false) { + int enabled = (BIF_ARG_2 == am_true); + + if(ERTS_IS_ATOM_STR("copy_save", BIF_ARG_1)) { + erts_lcnt_set_preserve_info(enabled); + + BIF_RET(am_ok); + } + } +#endif BIF_ERROR(BIF_P, BADARG); } |