linux信号以及core

CoreDumped.gif

何为信号

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

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

以上摘自《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
  • 每个进程也可以通过setrlimitRLIMIT_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

注意:

  1. 如果你想设置全局的coredump_filter,可以参考这篇文章
  2. MMIO的页永远不会被dump出来

产生core-dump的方法

  1. 发信号SIGABRT,会终止进程
  2. gcore,gcore会调用gdb产生coredump,不会终止进程,但是产生core的时候进程会处于stopped状态
  3. 设置信号处理函数,信号处理函数fork()abort()
  4. google-coredumper上述的方法1终止进程,方法2会暂停进程,所以谷歌就做了个coredump库,支持在运行时coredump

gcore

  • gcore实际上就是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 gcore

signal 函数

  1. 信号处理函数signal 规定了在某种信号signo情况下调用func处理
  2. 正在处理的时候,其他信号是不能递交的,必须等当前信号处理完毕,其他信号才能递交
#include <signal.h>
typedef void Sigfunc(int);
Sigfunc *signal(int signo, Sigfunc *func)

SIGCHLD

  1. 子进程终止时,会给父进程发一个SIGCHLD信号(其实这个信号是由内核在进城终止时发给父进程的(《UNIX网络编程》P103)),如果父进程不处理的话,子进程机会变成僵尸进程
  2. 父进程只需要在信号处理函数里面调用wait即可。
  3. 如果不想子进程产生僵尸进程,可以设置SIG_IGN
     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页

  1. A与B连接, B异常终止了,这是B会终止socket连接并且给A发一个fin,
  2. 这时如果A再给B发一个写, B的套接字会回一个RST
  3. 如果A再再给B发一个写, 会引发SIGPIPE信号, 这个信号试图终止进程A, 如果A不情愿被终止,那么必须signal捕获该信号并处理,但是无论如何,写操作都会fail并且errno=EPIPE
  4. signal函数最简单的方法就是把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 <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);  // 成功返回进程ID, 出错返回0或-1
  1. 通过返回,返回已终止子进程的ID
  2. 通过statloc指针返回子进程终止状态

waitpid()

《UNIX网络编程》 P110

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

参考链接

  1. Linux信号(一):信号类型
  2. What's the easiest way to detect what signals are being sent to a process?
  3. signal(7) — Linux manual page信号的不同用处
  4. core(5) — Linux manual page
  5. 线上内存泄漏的正确查找姿势
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,061评论 6 523
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,407评论 3 404
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,275评论 0 368
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,084评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,091评论 6 400
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,555评论 1 315
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,914评论 3 429
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,900评论 0 279
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,438评论 1 324
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,470评论 3 346
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,596评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,187评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,932评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,361评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,511评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,163评论 3 381
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,671评论 2 366

推荐阅读更多精彩内容

  • 摘要:在我们往期对coredump的分析中,是依赖于core文件的,而core文件中也几乎包含了程序当前的所有状态...
    鱼鲲_91f3阅读 2,936评论 0 3
  • Core dump实战分析(Java版) 背景 项目中的battleserver进程在某一段时间总是crash,无...
    landon30阅读 9,825评论 1 2
  • 在Linux下程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息)。使...
    随风化作雨阅读 46,051评论 2 15
  • 工具:GDB 分析 导致进程异常退出的这两类情况: 第一类:向进程发送信号导致进程异常退出; 第二类:代码错误导致...
    董春磊阅读 1,953评论 0 1
  • 理论部分 简单来说 信号是用来通知进程发生了异步事件 比如,在终端运行程序,按下ctrl+c就产生一个中端信号,大...
    捉虫大师阅读 1,757评论 0 2