linux信号以及core

您所在的位置:网站首页 内核coredump linux信号以及core

linux信号以及core

2023-10-15 21:49| 来源: 网络整理| 查看: 265

何为信号

信号(signal)用于通知进程发生了某种情况。进程有以下3种处理信号的方式:

忽略信号。有些信号表示硬件异常,例如,除以0或访问进程地址空间以外的存储单元等,因为这些异常产生的后果不确定,所以不推荐使用这种处理>方式。按系统默认方式处理提供一个函数,信号发生时调用该函数,这被称为捕抓该信号。通过提供的信号处理函数,我们就能知道什么时候产生了信号,并按期望的方式处理它。

以上摘自《APUE》中文版14页

信号类型[root@test ~]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX

每个信号有其默认的处理方式,参考manpage,分为以下几种类型

Term Default action is to terminate the process. Ign Default action is to ignore the signal. Core Default action is to terminate the process and dump core (see core(5)). Stop Default action is to stop the process. Cont Default action is to continue the process if it is currently stopped.

例如我们常用的kill的默认信号SIGTERM(15),以及强制结束信号SIGKILL(9),其对应的处理方式都是Term,我们经常使用SIGABRT(6)对应处理方式是Core,可以用来产生core-dump文件

core文件详解

core文件是ELF-formatted文件,可以使用readelf查看core的elf信息。它包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等

配置coredump开启coredump# 开启coredump ulimit -c unlimited # 持久化方式 echo "ulimit -c unlimited" >> /etc/profile设置coredump的命名规则# 在/etc/sysctl.conf文件中加入 # 例如下面这个命令,可以通过在%e前面增加/home/之类的路径使其保存到特定路径 kernel.core_pattern=%e.core.%s_%t 并保存退出,执行下面指令使其生效 sysctl -p # 参数含义 %% output one '%' %p pid %u uid %g gid %s signal number %t UNIX time of dump %h hostname %e executable filename # 默认是这样的 |/usr/share/apport/apport %p %s %c %P If the first character of the pattern is a '|', the kernel will treat the rest of the pattern as a command to run. The core dump will be written to the standard input of that program instead of to a file.通过cat /proc/sys/kernel/core_pattern 验证设置的pattern每个进程也可以通过setrlimit的RLIMIT_CORE配置进程级别的core大小控制coredump的mapping

/proc/[pid]/coredump_filter可以指定怎样的进程空间内存可以保存到core文件里,它是由下面的bitmask组成

(bit 0) anonymous private memory(匿名私有内存段,例如:动态变了)(bit 1) anonymous shared memory(匿名共享内存段)(bit 2) file-backed private memory(file-backed 私有内存段)(bit 3) file-backed shared memory(file-bakced 共享内存段,例如:动态链接库)(bit 4) ELF header pages in file-backed private memory areas (it is effective only if the bit 2 is cleared)(ELF 文件映射,只有在bit 2 复位的时候才起作用)(bit 5) hugetlb private memory(大页私有内存)(bit 6) hugetlb shared memory(大页共享内存)bit 7 (since Linux 4.4) Dump private DAX pages.bit 8 (since Linux 4.4) Dump shared DAX pages.

默认配置是0x33,也就是说bits 0 (anonymous private mappings), 1 (anonymous shared mappings), 4 (ELF headers) and 5 (private huge pages) 都会被dump出。如果想改变bitmask,可以使用如下方法:

echo 0x00000001 > /proc/[pid]/coredump_filter

也可以配置在当前shell生效的coredump_filter

# 如果没有下面的文件,请检查内核参数CONFIG_ELF_CORE是否配置 $ echo 0x7 > /proc/self/coredump_filter $ ./some_program

注意:

如果你想设置全局的coredump_filter,可以参考这篇文章MMIO的页永远不会被dump出来产生core-dump的方法发信号SIGABRT,会终止进程gcore,gcore会调用gdb产生coredump,不会终止进程,但是产生core的时候进程会处于stopped状态设置信号处理函数,信号处理函数fork()后abort()google-coredumper上述的方法1终止进程,方法2会暂停进程,所以谷歌就做了个coredump库,支持在运行时coredumpgcoregcore实际上就是gdb里面的一个命令,它的作用是把进程的memory全部dump出来,和系统调用abort()等方法的实现方式是不同的。最直观的感受是gcore会把进程全部的VIRT内存dump出来。产生的core文件有可能会很大,并且它的大小不受ulimit -c限制。使用gcore dump出的core文件,在gdb中使用info files查看每段内存的大小,比使用abort()dump出的要大的多,原因应该是gcore把没有用到的虚拟内存也dump出来了gcore执行过程中程序处于stopped状态命令行中的gore命令其实是RedHat linux制作的一个shell script用来调用gdb,所以如果你调用了命令行gcore [pid],它实际上会执行如下的gdb命令,如下,以进程40923为例:gdb --nx --batch -ex set pagination off -ex set height 0 -ex set width 0 -ex attach 40923 -ex gcore core.40923 -ex detach -ex quit

所以,如果你没有gcore命令,也可以使用如下命令产生gcore

gdb --pid=40923 --batch -ex gcoresignal 函数信号处理函数signal 规定了在某种信号signo情况下调用func处理正在处理的时候,其他信号是不能递交的,必须等当前信号处理完毕,其他信号才能递交#include typedef void Sigfunc(int); Sigfunc *signal(int signo, Sigfunc *func)SIGCHLD子进程终止时,会给父进程发一个SIGCHLD信号(其实这个信号是由内核在进城终止时发给父进程的(《UNIX网络编程》P103)),如果父进程不处理的话,子进程机会变成僵尸进程父进程只需要在信号处理函数里面调用wait即可。如果不想子进程产生僵尸进程,可以设置SIG_IGN c signal(SIGCHLD, SIG_IGN);signal(SIGCHLD, sig_chld); void sig_chld(int signo) { pid_t pid; int stat; pid = wait(&stat); printf("child %d terminated\n", pid); return; }僵尸进程的危害

所谓僵尸进程,形象来说,进程已死,但其尸体还在,没人收尸啊,冤魂不散,仍然占用一个进程号,如果主进程不妥善处理,当僵尸进程数量巨大之后,就没法再次fork了,所以对于大型并发服务器来说,当建立了进程池,一定要想办法处理掉所有僵尸进程。

SIGPIPE

《UNP》中文版113页

A与B连接, B异常终止了,这是B会终止socket连接并且给A发一个fin,这时如果A再给B发一个写, B的套接字会回一个RST如果A再再给B发一个写, 会引发SIGPIPE信号, 这个信号试图终止进程A, 如果A不情愿被终止,那么必须signal捕获该信号并处理,但是无论如何,写操作都会fail并且errno=EPIPEsignal函数最简单的方法就是把SIGPIPE置成SIG_IGN,这样进程就会忽略SIGPIPE信号。signal(SIGPIPE, SIG_IGN);SIGIO

信号驱动式I/O模型, 利用信号,让内核在描述符就绪时发送SIGIO信号通知进程

其他相关函数sigation在一些较早的系统上(《UNP》P105),signal设置的信号句柄只能起一次作用,信号被捕获一次后,信号句柄就会被还原成默认值了。我们现在用的linux系统应该没有关系的sigaction设置的信号句柄,可以一直有效,直到你再次改变它的设置。struct sigaction sa; sa.sa_handler = SIG_IGN; sigaction( SIGPIPE, &sa, 0 );

sigation的定义:

struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; // 一般置0, 有一些特殊的标志位会用到这个, 如SA_NOCLDSTOP等 void (*sa_restorer)(void); };wait和waitpid函数

wait 函数可以用来处理已终止的子进程

#include pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int *statloc, int options); // 成功返回进程ID, 出错返回0或-1通过返回,返回已终止子进程的ID通过statloc指针返回子进程终止状态waitpid()

《UNIX网络编程》 P110

通过waitpid设置WNOHANG选项,可以告知waitpid在有尚未终止的子进程在运行时不要阻塞

参考链接Linux信号(一):信号类型What's the easiest way to detect what signals are being sent to a process?signal(7) — Linux manual page信号的不同用处core(5) — Linux manual page线上内存泄漏的正确查找姿势


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3