GDB不立即中断程序

在debugging一个大的C应用程序时,我发现gdb有一个奇怪的行为:我总是可以按Ctrl+C中断程序:

 ^C Program received signal SIGINT, Interrupt. 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81 81 in ../sysdeps/unix/syscall-template.S (gdb) 

但是,在程序运行足够的时间之后(例如> 1天),我不能再轻易地中断程序了。 当试图用Ctrl+C中断程序时, gdb只显示

 ^C Program received signal SIGINT, Interrupt. 

并挂在那里几分钟到几个小时。 如果花费时间超过几分钟,我通常会打开另一个terminal并手动杀死gdb以便能够继续。

问:这是gdb预期行为吗? 我可以设置一个选项来避免这种情况吗?

更多细节:

  • 应用程序是FTL ( https://github.com/pi-hole/FTL )
  • 它是使用pthreadsmultithreading
  • Ctrl+C后的等待时间内, gdb处于100%CPU。

编辑:进一步的细节

我运行了perf record -p $(pidof gdb)约10秒,而gdb被冻结。 perf report返回:

 90,82% gdb gdb [.] find_thread_ptid 9,13% gdb gdb [.] ptid_equal 0,02% gdb gdb [.] iterate_over_threads 0,01% gdb [kernel.kallsyms] [k] run_timer_softirq 0,01% gdb gdb [.] 0x0016a9a4 0,00% gdb gdb [.] 0x0015a480 0,00% gdb gdb [.] 0x0016a998 0,00% gdb gdb [.] is_exited 

几分钟后, gdb完成,我跑了info threads仍然只显示三个线程(如以前):

 (gdb) info threads Id Target Id Frame 3 Thread 0x764b8460 (LWP 10114) "socket listener" 0x76f60260 in accept () at ../sysdeps/unix/syscall-template.S:81 2 Thread 0x76cb8460 (LWP 10113) "loganalyzer" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81 * 1 Thread 0x76e65000 (LWP 10098) "pihole-FTL" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81 

gdb只是显示…并挂在那里几分钟长达数小时。

一个猜测:你的程序创建,但没有正确地加入和终止线程。

您可以通过运行该程序几个小时,用Control-C中断它,并发出info threads命令来确认或反驳。

在Linux上,线程只是碰巧共享虚拟内存和文件描述符(以及控制终端)的进程。 当您点击Control-C ,只有一个线程收到了SIGINT

在默认的all-stop模式下,GDB得到(由内核)一个线程有一个挂起的SIGINT通知。 然后,GDB需要停止你的进程的所有其他线程,这可能会花费不少的时间。

不仅如此,GDB可能需要重复几次:在线程运行时,它们可能创建了新的线程,现在也必须停止。