2017-08-18

第十章 信号


10.2 信号概念

产生信号的条件:

  • 用户按下某些终端键时,引发终端产生的信号
  • 硬件异常产生信号(除数为0,无效的内存引用等)
  • kill函数/kill命令
  • 软件条件

信号的处理:忽略,捕捉,执行系统默认动作
SIGKILL和SIGSTOP无法被忽略或者捕捉,只能执行系统默认动作

信号名称 说明 默认动作
SIGABRT 异常终止 终止+core
SIGALRM 定时器超时(alarm) 终止
SIGBUS 硬件故障 终止+core
SIGCHLD 子进程终止/停止 忽略
SIGCONT 使暂停进程继续 继续/忽略
SIGEMT 硬件故障 终止+core
SIGFPE 算术运算异常 终止+core
SIGHUP 连接断开 终止
SIGILL 表示进程已执行一条非法硬件指令 终止+core
SIGINT 中断(Delete/Ctrl+C) 终止
SIGIO(等效于SIGPOLL) 终止
SIGIOT(等效于SIGABRT) 终止+core
SIGKILL 杀掉进程 终止
SIGPIPE 写至无读进程的管道 终止
SIGPOLL 可轮询事件 终止
SIGPWR 蓄电池也不能支持工作时候,发送该信号 终止
SIGQUIT Ctrl+\类似于SIGINT,但是同时产生core文件 终止+core
SIGSEGV 无效的内存引用 终止+core
SIGSTOP 停止 停止进程
SIGSYS 指示一个无效的系统调用 终止+core
SIGTERM 终止 终止
SIGTRAP 硬件故障 终止+core
SIGTSTP Ctrl+Z 停止进程
SIGTTIN 后台读控制tty 停止进程
SIGTTOU 后台写向控制tty 停止进程
SIGURG 紧急情况(套接字) 忽略
SIGUSR1/SIGUSR2 用户定义信号 终止
SIGWINCH 终端窗口大小改变 忽略
SIGXCPU 超过CPU限制 终止+core
SIGXFSZ 超过软文件长度限制 终止+core

10.3 函数signal

函数原型:

#include 
void (*sinal(int signo, void (*fun)(int)))(int);
返回值:成功返回以前的信号处理配置;失败返回SIG_ERR

或者写成:

typedef void sigfunc(int);
sigfunc *signal(int,sigfunc *);

用法如下:
第一个参数为信号
第二个参数为SIG_DFL/SIG_IGN或者函数地址:
SIG_IGN表示忽略该信号
SIG_DFL表示系统默认动作
当为函数地址时,调用该函数处理信号

中:
#define SIG_ERR (void(*)())-1
#define SIG_DFL (void(*)())0
#define SIG_IGN (void(*)())1

程序启动时:
exec函数将原先设置为要捕获的信号都更改为默认动作,其他信号的状态不变

进程创建时:
子进程继承父进程的信号处理方式

10.4 不可靠的信号

早期版本的UNIX系统中,信号是不可靠的。

  1. 在进程每次接到信号对其进行处理时,随即将该信号动作重置为默认值
int sig_int();
...
signal(SIGINT,sig_int);
...
sig_int()
{
    signal(SIGINT,sig_int);
    ...
}
  1. 在进程不希望某种信号发生时,它不能关闭该信号。进程能做的就是忽略该信号。
int sig_int();
int sig_int_flag;
...
int main()
{
    signal(SIGINT,sig_int);
    ...
    while(sig_int_flag == 0)
        pause();
    ...
}
sig_int()
{
    signal(SIGINT,sig_int);
    sig_int_flag = 1;
}

10.5 中断的系统调用

早期UNIX系统的一个特性是:
如果进程在执行一个低速系统调用而阻塞期间捕获一个信号,则该系统调用就被中断而不再执行。该系统调用返回出错,其errno设置为EINTR。
低速系统调用 VS 其他系统调用
低速系统调用(可能会使得进程永远阻塞的一类系统调用)包括:

  • 如果某些类型文件的数据不存在,则读操作可能会使调用者永远阻塞
  • 如果这些数据不嗯给你被相同的类型文件立即接受,则写操作可能会使得调用者永远阻塞
  • 在某种条件发生之前打开某些类型文件,可能会发生阻塞
  • pause函数和wait函数
  • 某些ioctl函数
  • 某些进程间通信函数

与被中断的系统调用相关的问题是必须显式地处理出错返回
典型的代码序列(假定进行一个读操作,它被中断,我们希望重新启动它)

again:
    if(n = read(fd,buf,BUFFSIZE) < 0){
        if(errno == EINTR)
        goto again;
    }

4.2BSD引进自动重启动的系统调用:ioctl、read、readv、write、writev、wait、waitpid
前五个函数只有对较低速设备进行操作时才会被信号中断
wait和waitpid在捕获信号时总是被中断

10.6 可重入函数

可重入函数是在信号处理程序中保证调用安全的函数
即使信号处理程序调用的是可重入函数,但是对于errno变量要进行处理

10.7 SIGCLD语义

SIGCLD
对SIGCLD的早期处理方式如下:

  1. 当将该信号的配置设置为SIG_DFL时,即不会理会这一个信号,但是没有调用wait/waitpid,产生了僵死进程
  2. 当将该信号的配置设置为SIG_IGN时,子进程在终止时的状态被丢弃,即不会产生僵死进程。但是如果父进程调用wait/waitpid,那么它将阻塞到所有子进程都终止,然后wait/waitpid返回-1,并且将errno设置为ECHILD
  3. 当将该信号的配置设置为信号处理函数的地址,则内核立即检查时候有子进程准备好被等待。注意会产生循环,所以在处理SIGCLD时,应该先wait处理掉了信号信息后,再调用signal。

SIGCHLD在配置信号处理方式时,是不会立即检查是否有子进程准备好被扽带,也不会在此时调用信号处理函数。

10.8 可靠信号术语和语义

  • 当造成信号的事件(硬件异常、软件条件、终端产生的条件、调用kill函数)发生时,为进程产生一个信号
  • 递送:当一个信号产生时,内核在进程表中以某种形式设置一个标志
  • 信号未决:信号处于产生和递送之间的时间间隔内
  • 阻塞信号递送:若进程产生一个阻塞的信号,而且对该信号的动作是系统默认动作/捕获该信号,则该进程将此信号保持为未决状态,直到该进程对此信号解除阻塞/对此信号的动作更改为忽略。sigpending函数可以判定信号是否被设置为阻塞并处于未决状态
  • 信号屏蔽字:规定了当前要阻塞递送到该进程的信号集(sigset_t)

10.9 kill 和 raise 函数

#include 
int kill (pid_t pid, int signo);//将信号发送给进程/进程组
int raise(int signo);//进程向自身发送信号
若成功,返回0;出错,返回-1

raise(signo); == kill(getpid(),signo);
kill的pid参数有四种情况:

  1. pid>0 将信号发送给进程ID为pid的进程
  2. pid==0 将信号发送给与发送进程属于同意进程组的所有进程,而且发送进程要具有权限向这些进程发送信号。这里的所有进程不包括系统进程集(内核进程和init(pid==1))
  3. pid<0 将信号发送给进程组ID等于|pid|,而且发送进程要具有权限向这些进程发送信号。这里的所有进程不包括系统进程集(内核进程和init(pid==1))
  4. pid==-1 将信号发送给发送进程有权限向他们发送信号的所有进程

关于权限

  • 超级用户可将信号发送给任一进程
  • 非超级用户:发送者的实际用户ID/有效用户ID == 接收者的实际用户ID/有效用户ID。EXCEPT:若实现支持_POSIX_SAVED_IDS,则检查接受者的保存设置用户ID(而不是有效用户ID)
  • 若被发送的信号是SIGCONT,则进程可将它发送给属于同一对话的任一其他进程

信号编号0定义为空信号。
若signo参数是0,则kill仍执行正常的错误检查,但不发送信号。(该用途常被用作确定一个特定进程是否存在。若检查的进程并不存在,则kill返回-1,errno被设置为ESRCH。即使kill返回0,也不能保证一定存在该进程。

10.10 alarm 和 pause 函数

#include 
unsigned int alarm(unsigned int seconds);

10.11 信号集

#include 
int sigemptyset(sigset_t *set);
int sigfillset(siget_t *set);
int sigaddset(siget_t *set,int signo);
int sigdelset(siget_t *set,int signo);
若成功返回0;出错返回-1

int sigismember(const siget_t *set,int signo);
真返回1,假返回0
假如用int类型来实现
#define sigemptyset(ptr) (*(ptr) = 0)
#define sigfillset(ptr)  (*(ptr) = ~(sigset_t)0,0)

#include 
#include 

#define SIGBAD(signo) ((signo) <= 0 || (signo) >= NSIG)

int sigaddset(sigset_t *set, int signo)
{
    if(SIGBAD(signo)){
        errno = EINVAL;
        return(-1);
    }
    *set |= 1 << (signo - 1);
    return(0);
}

10.12 sigprocmask函数

#include 
int sigprocmask(int how,const sigset_t * restrict set,sigset_t *restrict oset);
成功返回0;错误返回-1
  1. 首先,oset如果是非空指针,那么进程的当前信号屏蔽字通过oset返回
  2. 其次,如果set是一个非空指针,则参数how指示如何修改当前信号屏蔽字。
    |how|说明|
    |:---:|:---:|
    |SIG_BLOCK|该进程新的信号屏蔽字是当前信号屏蔽字和set指向的信号集的并集。于是set包含了希望阻塞的附加信号|
    |SIG_UNBLOCK|该进程新的信号屏蔽字是当前信号屏蔽字和set所指向的信号集补集的交集。于是set包含了希望解除阻塞的信号|
    |SIG_SETMASK|该进程新的信号屏蔽字是set所指向的值|
  3. 如果set是空指针,则不改变该进程的信号屏蔽字,how也随之没有意义

10.13 sigpending函数

#include 
int sigpending(sigset_t *set);//set返回被阻塞不能递送的信号集
成功返回0;出错返回-1
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,932评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,554评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,894评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,442评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,347评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,899评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,325评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,980评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,196评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,163评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,085评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,826评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,389评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,501评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,753评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,171评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,616评论 2 339

推荐阅读更多精彩内容