diff options
Diffstat (limited to 'erts/emulator/beam/break.c')
-rw-r--r-- | erts/emulator/beam/break.c | 261 |
1 files changed, 171 insertions, 90 deletions
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 35b2365655..4dabac3512 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2017. All Rights Reserved. + * Copyright Ericsson AB 1996-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. @@ -39,6 +39,7 @@ #include "erl_instrument.h" #include "erl_hl_timer.h" #include "erl_thr_progress.h" +#include "erl_proc_sig_queue.h" /* Forward declarations -- should really appear somewhere else */ static void process_killer(void); @@ -58,6 +59,8 @@ static void dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size); extern char* erts_system_version[]; +#define WRITE_BUFFER_SIZE (64*1024) + static void port_info(fmtfn_t to, void *to_arg) { @@ -105,36 +108,11 @@ process_killer(void) if ((j = sys_get_key(0)) <= 0) erts_exit(0, ""); switch(j) { - case 'k': { - ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; - erts_aint32_t state; - erts_proc_inc_refc(rp); - erts_proc_lock(rp, rp_locks); - state = erts_atomic32_read_acqb(&rp->state); - if (state & (ERTS_PSFLG_FREE - | ERTS_PSFLG_EXITING - | ERTS_PSFLG_ACTIVE - | ERTS_PSFLG_ACTIVE_SYS - | ERTS_PSFLG_IN_RUNQ - | ERTS_PSFLG_RUNNING - | ERTS_PSFLG_RUNNING_SYS - | ERTS_PSFLG_DIRTY_RUNNING - | ERTS_PSFLG_DIRTY_RUNNING_SYS)) { - erts_printf("Can only kill WAITING processes this way\n"); - } - else { - (void) erts_send_exit_signal(NULL, - NIL, - rp, - &rp_locks, - am_kill, - NIL, - NULL, - 0); - } - erts_proc_unlock(rp, rp_locks); - erts_proc_dec_refc(rp); - } + case 'k': + /* Send a 'kill' exit signal from init process */ + erts_proc_sig_send_exit(NULL, erts_init_process_id, + rp->common.id, am_kill, NIL, + 0); case 'n': br = 1; break; case 'r': return; default: return; @@ -159,47 +137,64 @@ static void doit_print_link(ErtsLink *lnk, void *vpcontext) if (pcontext->is_first) { pcontext->is_first = 0; - erts_print(to, to_arg, "%T", lnk->pid); + erts_print(to, to_arg, "%T", lnk->other.item); } else { - erts_print(to, to_arg, ", %T", lnk->pid); + erts_print(to, to_arg, ", %T", lnk->other.item); } } static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext) { + ErtsMonitorData *mdp; PrintMonitorContext *pcontext = vpcontext; fmtfn_t to = pcontext->to; void *to_arg = pcontext->to_arg; char *prefix = ", "; - if (pcontext->is_first) { - pcontext->is_first = 0; - prefix = ""; - } - + mdp = erts_monitor_to_data(mon); switch (mon->type) { - case MON_ORIGIN: - if (is_atom(mon->u.pid)) { /* dist by name */ - ASSERT(is_node_name_atom(mon->u.pid)); - erts_print(to, to_arg, "%s{to,{%T,%T},%T}", prefix, mon->name, - mon->u.pid, mon->ref); - } else if (is_atom(mon->name)){ /* local by name */ - erts_print(to, to_arg, "%s{to,{%T,%T},%T}", prefix, mon->name, - erts_this_dist_entry->sysname, mon->ref); - } else { /* local and distributed by pid */ - erts_print(to, to_arg, "%s{to,%T,%T}", prefix, mon->u.pid, mon->ref); - } - break; - case MON_TARGET: - erts_print(to, to_arg, "%s{from,%T,%T}", prefix, mon->u.pid, mon->ref); - break; - case MON_NIF_TARGET: { - ErtsResource* rsrc = mon->u.resource; - erts_print(to, to_arg, "%s{from,{%T,%T},%T}", prefix, rsrc->type->module, - rsrc->type->name, mon->ref); - break; - } + case ERTS_MON_TYPE_PROC: + case ERTS_MON_TYPE_PORT: + case ERTS_MON_TYPE_TIME_OFFSET: + case ERTS_MON_TYPE_DIST_PROC: + case ERTS_MON_TYPE_RESOURCE: + case ERTS_MON_TYPE_NODE: + + if (pcontext->is_first) { + pcontext->is_first = 0; + prefix = ""; + } + + if (erts_monitor_is_target(mon)) { + if (mon->type != ERTS_MON_TYPE_RESOURCE) + erts_print(to, to_arg, "%s{from,%T,%T}", prefix, mon->other.item, mdp->ref); + else { + ErtsResource* rsrc = mon->other.ptr; + erts_print(to, to_arg, "%s{from,{%T,%T},%T}", prefix, rsrc->type->module, + rsrc->type->name, mdp->ref); + } + } + else { + if (!(mon->flags & ERTS_ML_FLG_NAME)) + erts_print(to, to_arg, "%s{to,%T,%T}", prefix, mon->other.item, mdp->ref); + else { + ErtsMonitorDataExtended *mdep = (ErtsMonitorDataExtended *) mdp; + Eterm node; + if (mdep->dist) + node = mdep->dist->nodename; + else + node = erts_this_dist_entry->sysname; + erts_print(to, to_arg, "%s{to,{%T,%T},%T}", prefix, mdep->u.name, + node, mdp->ref); + } + } + + break; + + default: + /* ignore other monitors... */ + break; } } @@ -207,7 +202,6 @@ static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext) void print_process_info(fmtfn_t to, void *to_arg, Process *p) { - time_t approx_started; int garbing = 0; int running = 0; struct saved_calls *scb; @@ -256,17 +250,22 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); - approx_started = (time_t) p->approx_started; - erts_print(to, to_arg, "Started: %s", ctime(&approx_started)); - ERTS_MSGQ_MV_INQ2PRIVQ(p); - erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); + + erts_proc_lock(p, ERTS_PROC_LOCK_MSGQ); + erts_proc_sig_fetch(p); + erts_proc_unlock(p, ERTS_PROC_LOCK_MSGQ); + erts_print(to, to_arg, "Message queue length: %d\n", p->sig_qs.len); /* display the message queue only if there is anything in it */ - if (!ERTS_IS_CRASH_DUMPING && p->msg.first != NULL && !garbing) { - ErtsMessage* mp; + if (!ERTS_IS_CRASH_DUMPING && p->sig_qs.first != NULL && !garbing) { erts_print(to, to_arg, "Message queue: ["); - for (mp = p->msg.first; mp; mp = mp->next) - erts_print(to, to_arg, mp->next ? "%T," : "%T", ERL_MESSAGE_TERM(mp)); + ERTS_FOREACH_SIG_PRIVQS( + p, mp, + { + if (ERTS_SIG_IS_NON_MSG((ErtsSignal *) mp)) + erts_print(to, to_arg, mp->next ? "%T," : "%T", + ERL_MESSAGE_TERM(mp)); + }); erts_print(to, to_arg, "]\n"); } @@ -307,11 +306,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) } /* display the links only if there are any*/ - if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p)) { + if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p)) { PrintMonitorContext context = {1, to, to_arg}; erts_print(to, to_arg,"Link list: ["); - erts_doforall_links(ERTS_P_LINKS(p), &doit_print_link, &context); - erts_doforall_monitors(ERTS_P_MONITORS(p), &doit_print_monitor, &context); + erts_link_tree_foreach(ERTS_P_LINKS(p), doit_print_link, &context); + erts_monitor_tree_foreach(ERTS_P_MONITORS(p), doit_print_monitor, &context); + erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p), doit_print_monitor, &context); erts_print(to, to_arg,"]\n"); } @@ -334,6 +334,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop)); erts_print(to, to_arg, "OldHeap unused: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) ); + erts_print(to, to_arg, "BinVHeap: %b64u\n", p->off_heap.overhead); + erts_print(to, to_arg, "OldBinVHeap: %b64u\n", BIN_OLD_VHEAP(p)); + erts_print(to, to_arg, "BinVHeap unused: %b64u\n", + BIN_VHEAP_SZ(p) - p->off_heap.overhead); + erts_print(to, to_arg, "OldBinVHeap unused: %b64u\n", + BIN_OLD_VHEAP_SZ(p) - BIN_OLD_VHEAP(p)); erts_print(to, to_arg, "Memory: %beu\n", erts_process_memory(p, !0)); if (garbing) { @@ -356,7 +362,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p) static void print_garb_info(fmtfn_t to, void *to_arg, Process* p) { - /* ERTS_SMP: A scheduler is probably concurrently doing gc... */ + /* A scheduler is probably concurrently doing gc... */ if (!ERTS_IS_CRASH_DUMPING) return; erts_print(to, to_arg, "New heap start: %bpX\n", p->heap); @@ -486,9 +492,7 @@ loaded(fmtfn_t to, void *to_arg) static void dump_attributes(fmtfn_t to, void *to_arg, byte* ptr, int size) { - while (size-- > 0) { - erts_print(to, to_arg, "%02X", *ptr++); - } + erts_print_base64(to, to_arg, ptr, size); erts_print(to, to_arg, "\n"); } @@ -503,7 +507,7 @@ do_break(void) /* check if we're in console mode and, if so, halt immediately if break is called */ mode = erts_read_env("ERL_CONSOLE_MODE"); - if (mode && strcmp(mode, "window") != 0) + if (mode && sys_strcmp(mode, "window") != 0) erts_exit(0, ""); erts_free_read_env(mode); #endif /* __WIN32__ */ @@ -673,18 +677,28 @@ bin_check(void) static Sint64 crash_dump_limit = ERTS_SINT64_MAX; static Sint64 crash_dump_written = 0; -static int crash_dump_limited_writer(void* vfdp, char* buf, size_t len) +typedef struct LimitedWriterInfo_ { + fmtfn_t to; + void* to_arg; +} LimitedWriterInfo; + +static int +crash_dump_limited_writer(void* vfdp, char* buf, size_t len) { const char stop_msg[] = "\n=abort:CRASH DUMP SIZE LIMIT REACHED\n"; + LimitedWriterInfo* lwi = (LimitedWriterInfo *) vfdp; crash_dump_written += len; if (crash_dump_written <= crash_dump_limit) { - return erts_write_fd(vfdp, buf, len); + return lwi->to(lwi->to_arg, buf, len); } len -= (crash_dump_written - crash_dump_limit); - erts_write_fd(vfdp, buf, len); - erts_write_fd(vfdp, (char*)stop_msg, sizeof(stop_msg)-1); + lwi->to(lwi->to_arg, buf, len); + lwi->to(lwi->to_arg, (char*)stop_msg, sizeof(stop_msg)-1); + if (lwi->to == &erts_write_fp) { + fclose((FILE *) lwi->to_arg); + } /* We assume that crash dump was called from erts_exit_vv() */ erts_exit_epilogue(); @@ -707,6 +721,9 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) int i; fmtfn_t to = &erts_write_fd; void* to_arg; + FILE* fp = 0; + LimitedWriterInfo lwi; + static char* write_buffer; /* 'static' to avoid a leak warning in valgrind */ if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; @@ -762,16 +779,16 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) * - write dump until alarm or file is written completely */ - if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { - env_erl_crash_dump_seconds_set = 0; - secs = -1; + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_SECONDS", env, &envsz) == 1) { + env_erl_crash_dump_seconds_set = 1; + secs = atoi(env); } else { - env_erl_crash_dump_seconds_set = 1; - secs = atoi(env); + env_erl_crash_dump_seconds_set = 0; + secs = -1; } if (secs == 0) { - return; + return; } /* erts_sys_prepare_crash_dump returns 1 if heart port is found, otherwise 0 @@ -787,7 +804,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) crash_dump_limit = ERTS_SINT64_MAX; envsz = sizeof(env); - if (erts_sys_getenv__("ERL_CRASH_DUMP_BYTES", env, &envsz) == 0) { + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_BYTES", env, &envsz) == 1) { Sint64 limit; char* endptr; errno = 0; @@ -800,7 +817,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } } - if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) + if (erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 1) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; @@ -810,9 +827,30 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) fd = open(dumpname,O_WRONLY | O_CREAT | O_TRUNC,0640); if (fd < 0) return; /* Can't create the crash dump, skip it */ - to_arg = (void*)&fd; + + /* + * Wrap into a FILE* so that we can use buffered output. Set an + * explicit buffer to make sure the first write does not fail because + * of a failure to allocate a buffer. + */ + write_buffer = (char *) erts_alloc_fnf(ERTS_ALC_T_TMP, WRITE_BUFFER_SIZE); + if (write_buffer && (fp = fdopen(fd, "w")) != NULL) { + setvbuf(fp, write_buffer, _IOFBF, WRITE_BUFFER_SIZE); + lwi.to = &erts_write_fp; + lwi.to_arg = (void*)fp; + } else { + lwi.to = &erts_write_fd; + lwi.to_arg = (void*)&fd; + } + if (to == &crash_dump_limited_writer) { + to_arg = (void *) &lwi; + } else { + to = lwi.to; + to_arg = lwi.to_arg; + } + time(&now); - erts_cbprintf(to, to_arg, "=erl_crash_dump:0.3\n%s", ctime(&now)); + erts_cbprintf(to, to_arg, "=erl_crash_dump:0.5\n%s", ctime(&now)); if (file != NULL) erts_cbprintf(to, to_arg, "The error occurred in file %s, line %d\n", file, line); @@ -857,6 +895,21 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) erts_print_scheduler_info(to, to_arg, ERTS_SCHEDULER_IX(i)), erts_cbprintf(to, to_arg, "** crashed **\n")); } + for (i = 0; i < erts_no_dirty_cpu_schedulers; i++) { + ERTS_SYS_TRY_CATCH( + erts_print_scheduler_info(to, to_arg, ERTS_DIRTY_CPU_SCHEDULER_IX(i)), + erts_cbprintf(to, to_arg, "** crashed **\n")); + } + erts_cbprintf(to, to_arg, "=dirty_cpu_run_queue\n"); + erts_print_run_queue_info(to, to_arg, ERTS_DIRTY_CPU_RUNQ); + + for (i = 0; i < erts_no_dirty_io_schedulers; i++) { + ERTS_SYS_TRY_CATCH( + erts_print_scheduler_info(to, to_arg, ERTS_DIRTY_IO_SCHEDULER_IX(i)), + erts_cbprintf(to, to_arg, "** crashed **\n")); + } + erts_cbprintf(to, to_arg, "=dirty_io_run_queue\n"); + erts_print_run_queue_info(to, to_arg, ERTS_DIRTY_IO_RUNQ); #endif @@ -916,7 +969,35 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) } erts_cbprintf(to, to_arg, "=end\n"); + if (fp) { + fclose(fp); + } close(fd); erts_fprintf(stderr,"done\n"); } +void +erts_print_base64(fmtfn_t to, void *to_arg, byte* src, Uint size) +{ + static const byte base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + while (size >= 3) { + erts_putc(to, to_arg, base64_chars[src[0] >> 2]); + erts_putc(to, to_arg, base64_chars[((src[0] & 0x03) << 4) | (src[1] >> 4)]); + erts_putc(to, to_arg, base64_chars[((src[1] & 0x0f) << 2) | (src[2] >> 6)]); + erts_putc(to, to_arg, base64_chars[src[2] & 0x3f]); + size -= 3; + src += 3; + } + if (size == 1) { + erts_putc(to, to_arg, base64_chars[src[0] >> 2]); + erts_putc(to, to_arg, base64_chars[(src[0] & 0x03) << 4]); + erts_print(to, to_arg, "=="); + } else if (size == 2) { + erts_putc(to, to_arg, base64_chars[src[0] >> 2]); + erts_putc(to, to_arg, base64_chars[((src[0] & 0x03) << 4) | (src[1] >> 4)]); + erts_putc(to, to_arg, base64_chars[(src[1] & 0x0f) << 2]); + erts_putc(to, to_arg, '='); + } +} |