📄 break.c
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* This File contains functions which are called if a user hits ^C */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "version.h"#include "error.h"#include "version.h"#include "erl_db.h"#include "bif.h"#include "erl_version.h"#include "hash.h"#include "atom.h"#include "beam_load.h"#include "erl_instrument.h"#include "erl_bif_timer.h"#ifdef _OSE_#include "time.h"#endif/* Forward declarations -- should really appear somewhere else */static void process_killer(void);void do_break(void);void erl_crash_dump_v(char *file, int line, char* fmt, va_list args);void erl_crash_dump(char* file, int line, char* fmt, ...);#ifdef DEBUGstatic void bin_check(void);#endifstatic void print_garb_info(int to, void *to_arg, Process* p);#ifdef OPPROFstatic void dump_frequencies(void);#endifstatic void dump_attributes(int to, void *to_arg, byte* ptr, int size);extern char* erts_system_version[];static voidport_info(int to, void *to_arg){ int i; for (i = 0; i < erts_max_ports; i++) print_port_info(to, to_arg, i);}voidprocess_info(int to, void *to_arg){ int i; for (i = 0; i < erts_max_processes; i++) { if ((process_tab[i] != NULL) && (process_tab[i]->i != ENULL)) { if (process_tab[i]->status != P_EXITING) print_process_info(to, to_arg, process_tab[i]); } } port_info(to, to_arg);}static voidprocess_killer(void){ int i, j; Process* rp; erts_printf("\n\nProcess Information\n\n"); erts_printf("--------------------------------------------------\n"); for (i = erts_max_processes-1; i >= 0; i--) { if (((rp = process_tab[i]) != NULL) && rp->i != ENULL) { int br; print_process_info(ERTS_PRINT_STDOUT, NULL, rp); erts_printf("(k)ill (n)ext (r)eturn:\n"); while(1) { if ((j = sys_get_key(0)) <= 0) halt_0(0); switch(j) { case 'k': if (rp->status == P_WAITING) { Uint32 rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; erts_smp_proc_lock(rp, rp_locks); (void) erts_send_exit_signal(NULL, NIL, rp, &rp_locks, am_kill, NIL, NULL, 0); erts_smp_proc_unlock(rp, rp_locks); } else erts_printf("Can only kill WAITING processes this way\n"); case 'n': br = 1; break; case 'r': return; default: return; } if (br == 1) break; } } }}typedef struct { int is_first; int to; void *to_arg;} PrintMonitorContext;static void doit_print_link(ErtsLink *lnk, void *vpcontext){ PrintMonitorContext *pcontext = vpcontext; int to = pcontext->to; void *to_arg = pcontext->to_arg; if (pcontext->is_first) { pcontext->is_first = 0; erts_print(to, to_arg, "%T", lnk->pid); } else { erts_print(to, to_arg, ", %T", lnk->pid); }} static void doit_print_monitor(ErtsMonitor *mon, void *vpcontext){ PrintMonitorContext *pcontext = vpcontext; int to = pcontext->to; void *to_arg = pcontext->to_arg; char *prefix = ", "; if (pcontext->is_first) { pcontext->is_first = 0; prefix = ""; } if (mon->type == MON_ORIGIN) { if (is_atom(mon->pid)) { /* dist by name */ ASSERT(is_node_name_atom(mon->pid)); erts_print(to, to_arg, "%s{to,{%T,%T},%T}", prefix, mon->name, mon->pid, mon->ref); erts_print(to, to_arg,"}"); } 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->pid, mon->ref); } } else { /* MON_TARGET */ erts_print(to, to_arg, "%s{from,%T,%T}", prefix, mon->pid, mon->ref); }} /* Display info about an individual Erlang process */voidprint_process_info(int to, void *to_arg, Process *p){ int garbing = 0; int running = 0; /* display the PID */ erts_print(to, to_arg, "=proc:%T\n", p->id); /* Display the state */ erts_print(to, to_arg, "State: "); switch (p->status) { case P_FREE: erts_print(to, to_arg, "Non Existing\n"); /* Should never happen */ break; case P_RUNABLE: erts_print(to, to_arg, "Scheduled\n"); break; case P_WAITING: erts_print(to, to_arg, "Waiting\n"); break; case P_SUSPENDED: erts_print(to, to_arg, "Suspended\n"); break; case P_RUNNING: erts_print(to, to_arg, "Running\n"); running = 1; break; case P_EXITING: erts_print(to, to_arg, "Exiting\n"); break; case P_GARBING: erts_print(to, to_arg, "Garbing\n"); garbing = 1; running = 1; break; } /* * If the process is registered as a global process, display the * registered name */ if (p->reg != NULL) erts_print(to, to_arg, "Name: %T\n", p->reg->name); /* * Display the initial function name */ erts_print(to, to_arg, "Spawned as: %T:%T/%bpu\n", p->initial[INITIAL_MOD], p->initial[INITIAL_FUN], p->initial[INITIAL_ARI]); if (p->current != NULL) { if (running) { erts_print(to, to_arg, "Last scheduled in for: "); } else { erts_print(to, to_arg, "Current call: "); } erts_print(to, to_arg, "%T:%T/%bpu\n", p->current[0], p->current[1], p->current[2]); } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); erts_print(to, to_arg, "Started: %s", ctime((time_t*)&p->started)); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); /* display the message queue only if there is anything in it */ if (!ERTS_IS_CRASH_DUMPING && p->msg.first != NULL && !garbing) { ErlMessage* mp; 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_print(to, to_arg, "]\n"); } { long s = 0; int frags = 0; ErlHeapFragment *m = p->mbuf; while (m != NULL) { frags++; s += m->size; m = m->next; } erts_print(to, to_arg, "Number of heap fragments: %d\n", frags); } erts_print(to, to_arg, "Heap fragment data: %bpu\n", MBUF_SIZE(p)); if (p->ct != NULL) { int i, j; erts_print(to, to_arg, "Last calls:"); for (i = 0; i < p->ct->n; i++) { erts_print(to, to_arg, " "); j = p->ct->cur - i - 1; if (j < 0) j += p->ct->len; if (p->ct->ct[j] == &exp_send) erts_print(to, to_arg, "send"); else if (p->ct->ct[j] == &exp_receive) erts_print(to, to_arg, "'receive'"); else if (p->ct->ct[j] == &exp_timeout) erts_print(to, to_arg, "timeout"); else erts_print(to, to_arg, "%T:%T/%bpu\n", p->ct->ct[j]->code[0], p->ct->ct[j]->code[1], p->ct->ct[j]->code[2]); } erts_print(to, to_arg, "\n"); } /* display the links only if there are any*/ if (p->nlinks != NULL || p->monitors != NULL) { PrintMonitorContext context = {1,to}; erts_print(to, to_arg,"Link list: ["); erts_doforall_links(p->nlinks, &doit_print_link, &context); erts_doforall_monitors(p->monitors, &doit_print_monitor, &context); erts_print(to, to_arg,"]\n"); } if (!ERTS_IS_CRASH_DUMPING) { /* and the dictionary */ if (p->dictionary != NULL && !garbing) { erts_print(to, to_arg, "Dictionary: "); erts_dictionary_dump(to, to_arg, p->dictionary); erts_print(to, to_arg, "\n"); } /* as well as the debug dictionary */ if (p->debug_dictionary != NULL && !garbing) { erts_print(to, to_arg, "$Dictionary: "); erts_dictionary_dump(to, to_arg, p->debug_dictionary); erts_print(to, to_arg, "\n"); } } /* print the number of reductions etc */ erts_print(to, to_arg, "Reductions: %bpu\n", p->reds); erts_print(to, to_arg, "Stack+heap: %bpu\n", p->heap_sz); erts_print(to, to_arg, "OldHeap: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (unsigned)(OLD_HEND(p) - OLD_HEAP(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_HEAP(p)) ); if (garbing) { print_garb_info(to, to_arg, p); } if (ERTS_IS_CRASH_DUMPING) { erts_program_counter_info(to, to_arg, p); } else { erts_print(to, to_arg, "Stack dump:\n");#ifdef ERTS_SMP if (!garbing)#endif erts_stack_dump(to, to_arg, p); }}static voidprint_garb_info(int to, void *to_arg, Process* p){ /* ERTS_SMP: A scheduler is probably concurrently doing gc... */#ifndef ERTS_SMP erts_print(to, to_arg, "New heap start: %bpX\n", p->heap); erts_print(to, to_arg, "New heap top: %bpX\n", p->htop); erts_print(to, to_arg, "Stack top: %bpX\n", p->stop); erts_print(to, to_arg, "Stack end: %bpX\n", p->hend); erts_print(to, to_arg, "Old heap start: %bpX\n", OLD_HEAP(p)); erts_print(to, to_arg, "Old heap top: %bpX\n", OLD_HTOP(p)); erts_print(to, to_arg, "Old heap end: %bpX\n", OLD_HEND(p));#endif}voidinfo(int to, void *to_arg){ erts_memory(&to, to_arg, NULL, THE_NON_VALUE); atom_info(to, to_arg); module_info(to, to_arg); export_info(to, to_arg); register_info(to, to_arg); erts_fun_info(to, to_arg); erts_node_table_info(to, to_arg); erts_dist_table_info(to, to_arg); erts_allocated_areas(&to, to_arg, NULL); erts_allocator_info(to, to_arg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -