信号只是一个数字,数字为0-31表示不同的信号,如下表所示。

编号

信号名

默认动作

说明

1

SIGHUP

进程终止

终端断开连接

2

SIGINT

进程终止

用户在键盘上按下CTRL+C

3

SIGQUIT

进程意外结束(Dump)

用户在键盘上按下CTRL+\

4

SIGILL

进程意外结束(Dump)

遇到非法指令

5

SIGTRAP

进程意外结束(Dump)

遇到断电,用于调试

6

SIGABRT/SIGIOT

进程意外结束(Dump)

7

SIGBUS

进程意外结束(Dump)

总线错误

8

SIGFPE

进程意外结束(Dump)

浮点异常

9

SIGKILL

进程终止

其他进程发送SIGKILL将导致目标进程终止

10

SIGUSR1

进程终止

应用程序可自定义使用

11

SIGSEGV

进程意外结束(Dump)

非法的内存访问

12

SIGUSR2

进程终止

应用程序可自定义使用

13

SIGPIPE

进程终止

管道读取端已经关闭,写入端进程会收到该信号

14

SIGALRM

进程终止

定时器到时

15

SIGTERM

进程终止

发送该信号使目标进程终止

16

SIGSTKFLT

进程终止

堆线错误

17

SIGCHLD

忽略

子进程退出时会向父进程发送该信号

18

SIGCONT

忽略

进程继续执行

19

SIGSTOP

进程暂停

发送该信号会使目标进程进入TASK_STOPPED状态

20

SIGTSTP

进程暂停

在终端上按下CTRL+Z

21

SIGTTIN

进程暂停

后台进程从控制终端读取数据

22

SIGTTOU

进程暂停

后台进程从控制终端读取数据

23

SIGURG

忽略

socket收到设置紧急指针标志的网络数据包

24

SIGXCPU

进程意外结束(Dump)

进程使用CPU已经超过限制

25

SIGXFSZ

进程意外结束(Dump)

进程使用CPU已经超过限制

26

SIGVTALRM

进程终止

进程虚拟定时器到期

27

SIGPROF

进程终止

进程Profile定时器到期

28

SIGMNCH

忽略

进程终端窗口大小改变

29

SIGIO

进程暂停

用于异步IO

29

SIGPOLL

进程暂停

用于异步IO

30

SIGPWR

进程暂停

电源失效

31

SIGUNUSED

进程暂停

保留未使用

注意在上标中的默认动作是指,在没有任何程序为相应的信号设置信号处理函数的情况下,内核接收到该信号的默认处理方式,但在实际中,有可能不是这样的。另外,在这里,进程终止一般是指进程通过do_exit()退出,进程意外结束(Dump)则表示进程遇到了一个异常。默认情况下,内核会根据进程当时的内存情况,在进程的当前目录中生成一个Core Dump文件,以后用户可以通过这个文件分析进程异常的原因。这个工作主要通过do_coredump()来完成。

由于早期只有31个信号,内核仅仅使用一个32位的变量signal来表示进程接收到的信号,因此如果要向一个进程发送一个信号,就把signal的第n位设置为1,这非常类似中断请求寄存器SRCPND寄存器,同时,还有一个blocked的变量,用来屏蔽信号,这类似中断屏蔽寄存器INTMSK。这样做的好处是可以“很快”判断出一个进程收到了哪些信号,如果采用链表或者数组,则需要扫描整个队列,但这也带来了新的问题,如果向一个进程发送了SIGINT信号,在这个信号处理之前,再次发送SIGINT,当这个进程开始处理信号时,它只知道收到了SIGINT信号,而无法判断出有几个SIGINT需要处理。此后加入了信号队列,把收到的信号保存在这个队列中,就可以很好的解决这个问题了。但是为了兼容的目的,仍能保留了旧的信号处理方式,因此1-32还是按原有的方式进行处理,而33-64则使用新的机制,为了区别对待,编号为33-64的信号又称为实时信号。需要注意的是:这里的“实时”和实时操作系统中的“实时”没有任何联系,实时信号在处理速度上并不会比普通信号快,它们之间的区别就是:普通信号会对多次的同一个信号进行“合并”处理,而实时信号会一一处理。因此我们这里仅讨论普通信号。

信号机制的相关管理结构位于task_struct结构中,其主要结构如下图所示。

实时信号引入了信号队列,为了处理上的方便,普通信号也使用了信号队列,仅仅从数字上无法区分实时信号和普通信号。由于在linux中,进程对象和线程对象都是task_struct,因此需要区别对待线程的信号和进程的信号。在上图中,Private Signal Queue是线程(在linux中称为轻权进程)信号队列,而Shared Signal Queue是进程(在linux中被称为进程组)信号队列。对于进程信号,则由进程组中的每一个线程共享。例如,在上图中,pending和shared_pending分别是Private Signal Queue和Shared Signal Queue其类型都是sigpending(/include/linux/signal.h),定义如下:

struct sigpending {

struct list_head list;

sigset_t signal;

};

list用于连接信号队列,signal是一个位图,每一位表示一个对应的信号,用于指示信号队列中有哪些信号等待处理,其类型为sigset_t(include/asm-arm/signal.h),其定义如下:

#define _NSIG  64

#define _NSIG_BPW 32

#define _NSIG_WORDS (_NSIG / _NSIG_BPW)

typedef struct {

unsigned long sig[_NSIG_WORDS];

} sigset_t;

sigset_t是一个数组,总共有64位,对应64个信号位图(32个普通信号和32个实时信号)。在以后的信号发送的分析中,我们会看到,对于普通信号,只需要把sigset_t中对应的位置1就可以了,而对于实时信号,还需要把相关信息添加到list的信号队列,信号队列类型为sigqueue(include/linux/signal.h),定义如下:

/*

* Real Time signals may be queued.

*/

struct sigqueue {

struct list_head list;

spinlock_t *lock;

int flags;

siginfo_t info;

struct user_struct *user;

};

sigqueue中的list是队列链表指针,info为这个信号的相关信息,其定义如下(include/asm-generic/siginfo.h):

typedef struct siginfo {

int si_signo;

int si_errno;

int si_code;

union {

int _pad[SI_PAD_SIZE];

/* kill() */

struct {

pid_t _pid;  /* sender's pid */

__ARCH_SI_UID_T _uid; /* sender's uid */

} _kill;

/* POSIX.1b timers */

struct {

timer_t _tid;  /* timer id */

int _overrun;  /* overrun count */

char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)];

sigval_t _sigval; /* same as below */

int _sys_private;      /* not to be passed to user */

} _timer;

/* POSIX.1b signals */

struct {

pid_t _pid;  /* sender's pid */

__ARCH_SI_UID_T _uid; /* sender's uid */

sigval_t _sigval;

} _rt;

/* SIGCHLD */

struct {

pid_t _pid;  /* which child */

__ARCH_SI_UID_T _uid; /* sender's uid */

int _status;  /* exit code */

clock_t _utime;

clock_t _stime;

} _sigchld;

/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */

struct {

void __user *_addr; /* faulting insn/memory ref. */

#ifdef __ARCH_SI_TRAPNO

int _trapno; /* TRAP # which caused the signal */

#endif

} _sigfault;

/* SIGPOLL */

struct {

__ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */

int _fd;

} _sigpoll;

} _sifields;

} siginfo_t;

上图中的sighand保存信号的处理函数指针,其作用类似于中断向量表,类型为sighand_struct(include/linux/sched.h),定义为:

struct sighand_struct {

atomic_t  count;

struct k_sigaction action[_NSIG];

spinlock_t  siglock;

};

_NSIG定义在asm-arm/signal.h中,为64,数组action,对应64个信号处理函数的相关信息,烈性为k_sigaction,在arm平台上,

struct k_sigaction {

struct sigaction sa;

};

sigantion(include/asm-arm/signal.h)的定义如下:

struct sigaction {

__sighandler_t sa_handler;

unsigned long sa_flags;

__sigrestore_t sa_restorer;

sigset_t sa_mask;  /* mask last for extensibility */

};

sa_handler就是信号处理函数指针。另外在task_struct结构中还有一个blocked可以用来屏蔽信号。明白了上面的主要数据结构的作用之后,很容易想到信号的处理主要有以下几方面。

设置信号回调函数:内核吧函数的相关信息保存到对应的sigantion结构中。

信号的发送:通过相关系统调用吧一个指定的信号发送到目标进程,如果该信号没有被屏蔽,就把信号的相关信息添加到信号队列中,如果有必要就唤醒目标进程。

信号响应:进程被唤醒后,根据信号队列中的信息,调用信号回调函数。

我们再来看一下信号回调函数,sa_handler的类型是__sihandler_t(include/asm-generic/singal.h),其定义为:

typedef void __signalfn_t(int);

typedef __signalfn_t __user *__sighandler_t;

linux通过信号回调函数,信号机制的管理结构 - Linux内核中的信号机制_Linux编程_Linux公社-Linux系统门户网站...相关推荐

  1. linux 信号优先级,linux内核中的信号机制

    linux内核中的信号机制--信号处理 Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net ...

  2. Linux内核中的platform机制

    Linux内核中的platform机制 从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver.Linux中大部分的设备驱动,都可以使用 ...

  3. 详解Linux2.6内核中基于platform机制的驱动模型

    原文地址:详解Linux2.6内核中基于platform机制的驱动模型 作者:nacichan [摘要]本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型.首先介绍了P ...

  4. 外网主机访问虚拟机下的Web服务器_服务器应用_Linux公社-Linux系统门户网站

    外网主机访问虚拟机下的Web服务器_服务器应用_Linux公社-Linux系统门户网站 之前在CentOS虚拟机上安装了LAMP,搭建起了自己的web服务器,具体流程见: http://www.lin ...

  5. linux内核不能识别u盘分区,一种在Linux内核中识别特定USB大容量存储设备的方法及系统与流程...

    本发明涉配usb设备识别技术领域,特别是涉及一种在linux内核中识别特定usb大容量存储设备的方法及系统. 背景技术: 在linux系统下对usb设备进行管控,一般而言有两种方法,一种是阻断新插入设 ...

  6. linux内核层是什么,从用户层到内核层 - Linux内核中的信号机制_Linux编程_Linux公社-Linux系统门户网站...

    1.简介 如果进程要处理某一信号,那么要在进程中注册该信号.注册信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个进程和该信号被传递给进程时,将执行何种操作.主要有两个函 ...

  7. linux异步io 回调函数,Linux异步IO

    Linux中最常用的IO模型是同步IO,在这个模型中,当请求发出之后,应用程序就会阻塞,直到请求满足条件为止.这是一种很好的解决方案,调用应用程序在等待IO完成的时候不需要占用CPU,但是在很多场景中 ...

  8. linux线程切换回调函数,linux C线程退出回调函数

    待补充.................... 函数原型 void pthread_cleanup_push(void (*routine)(void*), void *arg); void pthr ...

  9. Linux内核中的RCU机制

    http://blog.chinaunix.net/uid-23769728-id-3080134.html RCU的设计思想比较明确,通过新老指针替换的方式来实现免锁方式的共享保护.但是具体到代码的 ...

最新文章

  1. [团队公告]第二次技术交流主题征集
  2. 【转】 SED多行模式空间
  3. UVa 10258 - Contest Scoreboard
  4. ASA 9.21 in Vmware Workstation 10
  5. saltstack 基础入门文档
  6. IntelliJ IDEA中打开项目时用 Import Project(导入项目) 和 Open(打开项目) 的区别
  7. 【vue2.0进阶】vue-router10分钟快速入门
  8. 服务器信号怎么设置好,手机这样设置,WIFI信号马上提高!
  9. Android中文API(134) —— Account
  10. 伙伴系统二叉树可视化笔记
  11. 【“达观杯”冠军分享】预训练模型彻底改变了NLP,但也不能忽略传统方法带来的提升...
  12. 快速傅里叶变换蝶式运算 matlab,FFT快速傅里叶变换(蝶形算法)详解.ppt
  13. Google Open Images Dataset V4 图片数据集详解2-分类快速下载
  14. matlab怎么带根号积分,如何用matlab画带根号的方程曲线图。曲线=[0.33-0.16x^2+0.12x]^(1/2)。...
  15. 新巴塞尔资本协议(中英文)
  16. Cypress 增加自定义header访问
  17. 华为签约计算机大学,2020年,华为签约学生多的16所大学,你知道几个?
  18. 程序员戴耳机是为了撩妹子?感觉好酷的样子~
  19. [因果推断] 增益模型(Uplift Model)介绍(三)
  20. 【Android Gradle 插件】build.gradle 中的 android 配置 ( 配置项 | compileSdkVersion 配置 | buildToolsVersion 配置 )

热门文章

  1. EarthView-在桌面中俯视地球
  2. 华为鸿蒙系统要多大内存,华为鸿蒙系统实测:内存控制超神,吊打安卓真不是吹牛?...
  3. hocon配置文件_Scala - 使用 typesafe.config 管理你的配置文件
  4. 开启教室照明“服务认证“,提升企业竞争地位
  5. 【甲骨云】 vps重装一键系统脚本(一键DD脚本)
  6. Python第六天作业
  7. 有趣的Hack-A-Sat黑掉卫星挑战赛——跟踪卫星
  8. 使用机器学习和深度学习对PE进行二分类和多分类
  9. 厕所对联(纯属搞笑)
  10. halcon:标定助手标定测量