dump所有cpu的callstack

来源:互联网 发布:linux 发送tcp报文 编辑:程序博客网 时间:2024/06/05 15:46
可以通过static inline bool trigger_all_cpu_backtrace(void){arch_trigger_cpumask_backtrace(cpu_online_mask, false);return true;}来让所有的cpu 打印当前的callstack这个函数是平台相关的,目前4.14的kernel arm 有实现这个函数,但是arm64 没有实现这个函数我们看看这个函数是如果打印所有cpu的callstack的呢?static void raise_nmi(cpumask_t *mask){smp_cross_call(mask, IPI_CPU_BACKTRACE);}void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self){nmi_trigger_cpumask_backtrace(mask, exclude_self, raise_nmi);}可见arch_trigger_cpumask_backtrace 最终还是调用nmi_trigger_cpumask_backtrace 来打印callstack其源码如下:void nmi_trigger_cpumask_backtrace(const cpumask_t *mask,   bool exclude_self,   void (*raise)(cpumask_t *mask)){int i, this_cpu = get_cpu();// 如果当前cpu 已经处于trigger_all_cpu_backtrace,则退出if (test_and_set_bit(0, &backtrace_flag)) {/* * If there is already a trigger_all_cpu_backtrace() in progress * (backtrace_flag == 1), don't output double cpu dump infos. */put_cpu();return;}// 如果exclude_self 置位的话,则表示不打印当前cpu的callstack,因此这里调用cpumask_clear_cpu来在要打印callstack的cpm_mask中去掉当前cpucpumask_copy(to_cpumask(backtrace_mask), mask);if (exclude_self)cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));/* * Don't try to send an NMI to this cpu; it may work on some * architectures, but on others it may not, and we'll get * information at least as useful just by doing a dump_stack() here. * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit. *///如果exclude_self 没有置位的话,则需要打印当前cpu的callstack,则调用nmi_cpu_backtrace 打印当前cpu的callstackif (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask)))nmi_cpu_backtrace(NULL);// 通过raise 还是来让backtrace_mask 中的所有cpu打印callstack,raise函数其实就是smp_cross_call(mask, IPI_CPU_BACKTRACE);也就是说会触发ipi中断,让其他的cpu 打印callstackif (!cpumask_empty(to_cpumask(backtrace_mask))) {pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n",this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask));raise(to_cpumask(backtrace_mask));}//等10是中让所有的cpu 打印完callstack/* Wait for up to 10 seconds for all CPUs to do the backtrace */for (i = 0; i < 10 * 1000; i++) {if (cpumask_empty(to_cpumask(backtrace_mask)))break;mdelay(1);touch_softlockup_watchdog();}/* * Force flush any remote buffers that might be stuck in IRQ context * and therefore could not run their irq_work. */printk_safe_flush();clear_bit_unlock(0, &backtrace_flag);put_cpu();}我们看看如何打印当前cpu的callstack 呢?bool nmi_cpu_backtrace(struct pt_regs *regs){static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;int cpu = smp_processor_id();if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {arch_spin_lock(&lock);if (regs && cpu_in_idle(instruction_pointer(regs))) {pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n",cpu, instruction_pointer(regs));} else {pr_warn("NMI backtrace for cpu %d\n", cpu);if (regs)show_regs(regs);elsedump_stack();}arch_spin_unlock(&lock);cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));return true;}return false;}注意这里的regs 为null,原来当前cpu就简单调用dump_stack() 来打印callstack那其他cpu 收到ipi 打印callstack的中断如何处理呢?void handle_IPI(int ipinr, struct pt_regs *regs){unsigned int cpu = smp_processor_id();struct pt_regs *old_regs = set_irq_regs(regs);case IPI_CPU_BACKTRACE:printk_nmi_enter();irq_enter();nmi_cpu_backtrace(regs);irq_exit();printk_nmi_exit();break;}原来每个cpu 在收到ipi中断后也就是执行nmi_cpu_backtrace 来打印callstack