为支持系统调用被信号过不去而不再实施之风味。产生信号的规范。

  早期的UNIX系统的一个风味:如果经过在实践一个低速系统调用而围堵期间,捕捉到一个信号,则该体系调用就叫暂停而不再继续执行。该系统调用返回出错,其error被设置为EINTR。即便信号中断系统调用的实行
如此这般处理的说辞是:因为一个信号发生了,进程捕捉到了它,那么意味着已闹了某种事情,所以是独提醒
被死的网调用 的机。
为支持系统调用被信号过不去而不再履行之表征,将系统调用分为两像样:低速系统调用和任何系统调用。
低速系统调用是唯恐会见使进程永远阻塞的同一类似系调用,他们包括:
1.
read()、readv(),在宣读一些品种的公文(管道、终端设备和网络设施)时,如果数量并无在则可能会见要调用者永远阻塞;
2.
write()、writev(),在写这些品种的公文时,如果不克就接受这些数据,则也可能会见如调用者永远阻塞;
3.
开辟某些类型的文本,在某种条件来前也或会见如调用者阻塞(例如,打开终端设备,他一旦等直到所连接的调制解调器应答了对讲机)—>这种类型还没实际例子测试

第十章 信号


  1. pause()和wait();
  2. 某些ioctl;
  3. 某些进程中通信函数;

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 <signal.h>
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表示系统默认动作
当为函数地址时,调用该函数处理信号

<signal.h>中:
#define SIG_ERR (void(*)())-1
#define SIG_DFL (void(*)())0
#define SIG_IGN (void(*)())1

次第启动时:
exec函数将本安装为要捕获的信号还转移为默认动作,其他信号的状态不转换

经过创造时:
支行进程继续父亲进程的信号处理方式

嗬是网调用的活动还启动?
  当系统调用被信号中断时,并无回来,而是继续执行。如果read()阻塞等待,当进程接受到信号时,并无将read返回,而是继续阻塞等待。
何以而引入自动重新启动的?
  有时用户并不知道所祭的输入、输出设备是否是低速设备。如果编写的次第可以用交互方式运行,则他恐怕读、写低速终端设备。
  如果当次中捕捉到信号,而网调用并无提供更启动功能,则针对每次读、写系统调用都使开展是否出错返回的测试,如果是被信号中断,则又调用读、写系统调用。
好家伙时引入系统调用的活动还启动?
  4.2BSD支持某些被搁浅系统调用的全自动还启动。
  4.3BSD允许进程基于每个信号禁用自动重新启动功能(因为也存在一些应用程序并无指望系统调用被暂停后活动重新开)

10.4 不保险的信号

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

  1. 以过程每次收到信号对那个进展处理常,随即用该信号动作重置为默认值

int sig_int();
...
signal(SIGINT,sig_int);
...
sig_int()
{
    signal(SIGINT,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;
}

是的题材:如果当测试sig_int_flag之后,调用pause之前起信号,则这过程在调用pause时可能拿永久休眠。

默认自动还启动的体系调用包括:ioctl(),read(),readv(),write(),writev(),wait(),waitpid();其中前面5只函数只有当针对低速设备进行操作时才会为信号中断。而wait和waitpid在捕捉到信号时连为中止。

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在破获信号时老是被暂停
当信号处理程序是故signal函数时,被中止的系调用会再度启动。

函数 信号处理程序仍被安装 阻塞信号的能力 被中断系统调用的自动重启动
signal . . 默认
sigaction . . 可选

 

10.6 可另行称函数

而再可函数是在信号处理程序中确保调用安全之函数
就是信号处理程序调用的是只是再次可函数,但是对errno变量要拓展处理(调用前保存errno,调用后复原errno)。

自之测试环境是4.3BSD,下面为read()为例来说明机关还启动同叫中止。

10.7 SIGCLD语义

SIGCLD
对SIGCLD的初处理方式如下:

  1. 当用拖欠信号的配备安装为SIG_DFL时,即无见面理会这一个信号,但是没调用wait/waitpid,产生了僵死进程
  2. 当以该信号的配置安装也SIG_IGN时,子进程在悬停时的状态被丢弃,即非会见来僵死进程。但是倘若大进程调用wait/waitpid,那么它们将卡住到所有子进程都止,然后wait/waitpid返回-1,并且用errno设置也ECHILD
  3. 当用该信号的部署安装为信号处理函数的地方,则基本立即检查是不是有子进程准备好叫等候。注意会起循环,所以于处理SIGCLD时,应该先wait处理掉了信号信息后,再调用signal。

在Linux中,SIGCLD == SIGCHLD
SIGCHLD在安排信号处理方式时,是匪见面应声检查是不是有子进程准备好为扽带,也非会见当这调用信号处理函数。

 

10.8 可靠信号术语和语义

  • 当造成信号的风波(硬件很、软件条件、终端有的法、调用kill函数)发生常,为经过来一个信号
  • 送:当一个信号产生时,内核在进程表中坐某种形式设置一个表明
  • 信号未决:信号处于产生和投递之间的日子间隔内
  • 闭塞信号递送:若进程来一个绿灯的信号,而且针对性该信号的动作是系默认动作/捕获该信号,则该过程将此信号保持也未决状态,直到该过程对斯信号解除阻塞/对是信号的动作更改为忽略。sigpending函数可以判断信号是否被安装为堵塞并处在未决状态
  • 信号屏蔽字:规定了时若死递送到拖欠过程的信号集(sigset_t)

活动还启动:

10.9 kill 和 raise 函数

#include <signal.h>
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,也不能够保证一定在拖欠过程。

restart.c

10.10 alarm 和 pause 函数

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

#include <unistd.h>
int pause(void);
返回值:-1,error设置为EINTR

用alarm()和pause()模拟sleep()函数

#include <signal.h>
#include <unistd.h>

static void sig_alarm(int signo)
{
    //什么事都不做,只是返回来唤醒pause()函数
}

unsigned int sleep1(unsigned int seconds)
{
    if(signal(SIGALRM,sig_alarm) == SIG_ERR)
        return(seconds);
    alarm(seconds);
    pause();
    return(alarm(0));
}
存在的问题:
1. 如果在调用sleep1之前已经调用了alarm函数,则它被sleep1函数中的第一次alarm调用擦除
2. sleep1()修改了对SIGALRM的配置。
3. 在一个繁忙的系统中,可能alarm在调用pause之前超时。

之所以setjmp和longjmp改进后的sleep:

#include <signal.h>
#include <unistd.h>
#include <setjmp.h>

static jmp_buf env_alrm;

static void sig_alarm(int signo)
{
    longjmp(env_alrm,1);
}

unsigned int sleep2(unsigned int seconds)
{
    if(signal(SIGALRM,sig_alarm) == SIG_ERR)
        return(seconds);
    if(setjmp(env_alrm) == 0){
        alarm(seconds);
        pause();
    }
    return(alarm(0));
}
存在的问题:
如果SIGALRM中断了某个其他信号,则调用longjmp会提早终止该信号处理程序

alarm()还得不时用于可能阻塞的操作设置时间达限值

#include "apue.h"
static void sig_alrm(int);

int main(void)
{
    char line[MAXLINE];

    if(signal(SIGALRM,sig_alrm) == SIG_ERR)
        err_sys("signal(SIGALRM) error");

    alarm(10);
    if(read(STDIN_FILENO,line,MAXLINE) < 0)
        err_sys("read error");
    alarm(0);

    write(STDOUT_FILENO,line,n);
    exit(0);
}
static void sig_alrm(int signo)
{
    //什么都不做,只是返回中断read操作
}
存在的问题:
1. 第一次alarm调用和read调用之间有一个竞争条件,进程如果在这期间被切换至其他进程,则read会阻塞;
2. 如果系统调用是自动重启动,则当从SIGALRM信号处理程序返回时,read并不中断。

防止系统调用重启动

#include "apue.h"
static void sig_alrm(int);
static jmp_buf env_alrm;
int main(void)
{
    char line[MAXLINE];

    if(signal(SIGALRM,sig_alrm) == SIG_ERR)
        err_sys("signal(SIGALRM) error");
    if(setjmp(env_alrm) != 0)
        err_quit("read timeout");
    alarm(10);
    if(read(STDIN_FILENO,line,MAXLINE) < 0)
        err_sys("read error");
    alarm(0);

    write(STDOUT_FILENO,line,n);
    exit(0);
}
static void sig_alrm(int signo)
{
    longjmp(env_alrm,1);
}
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <signal.h>
 6 #include <errno.h>
 7 
 8 #define BUFSIZE (1024)
 9 
10 static void sig_alrm(int signo)
11 {
12     printf("caught alarm...\n");
13 }
14 
15 void sig_usr(int signo)
16 {
17     if (signo == SIGUSR1)
18         printf("received SIGUSR1\n");
19     else if (signo == SIGUSR2)
20         printf("received SIGUSR2\n");
21     else
22         printf("received signal %d\n", signo);
23 }
24 
25 int main(int argc, char** argv)
26 {
27     int nSize = 0;
28     char acBuf[BUFSIZE] = {0};
29 
30     signal(SIGUSR1, sig_usr);
31     signal(SIGALRM, sig_alrm);
32 
33     alarm(5);
34 
35 //    while(1)
36     {
37         
38         memset(acBuf, '\0', BUFSIZE);
39         nSize = read(STDIN_FILENO, acBuf, BUFSIZE); 
40         if (errno == EINTR)
41             printf("interrupt, size=%d\n", nSize);
42 
43         if (1 == nSize && acBuf[0] == 10)
44             ;
45         else if (nSize != -1)
46         {
47             printf("nSize=%d, acBuf=%s", nSize, acBuf);        
48         }
49     }
50 
51     return 0;
52 }

10.11 信号集

#include <signal.h>
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 <signal.h>
#include <errno.h>

#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 <signal.h>
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也随着没有意义
    以调用sigprocmask后如果生其他未决的、不再阻塞的信号,则在sigprocmask返回前,至少用里面某递送给该过程

图片 1

10.13 sigpending函数

#include <signal.h>
int sigpending(sigset_t *set);//set返回被阻塞不能递送的信号集
成功返回0;出错返回-1

定时器计数到5秒后,会发送alarm信号,从打印好看到真接到及了alarm信号,且read()并无回去而是继续阻塞接受规范输入;然后以手动发送一个SIGUSR1信号,同样,read()并没给搁浅,当输入jfdk后,read能健康读来。说明signal()默认是用信号设置也自发性还启动

10.14 sigaction函数

#include <signal.h>
int sigaction(int signo,const struct sigaction *restrict act,struct sigaction *restrict oact);
返回值:成功返回0,出错返回-1
struct sigaction{
    void (*sa_handler)(int);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_sigaction)(int, siginfo_t *, void *);
}
struct siginfo{
    int si_signo;
    int si_errno;
    int si_code;
    pid_t si_pid;
    uid_t si_uid;
    void *si_addr;
    int si_status;
    union sigval si_value;
}
struct sigval{
    int sival_int;
    void *sigval_int;
}

sa_mask:在调用该信号捕捉函数之前,这同样信号集要加到进程的信号屏蔽字被。仅当起信号捕捉函数返回时再也以经过的信号屏蔽字恢复为本来先值
附:在信号处理程序被调用时,操作系统建立的新信号屏蔽字包括正被递送的信号。所以,如果在处理一个信号的信号处理函数中,会阻塞这一个信号。

选项 说明
SA_INTERRUPT 由此中断的系统调用不再重启动(默认的处理方式)
SA_RESTART 由此中断的系统调用不再重新启动
SA_NOCLDSTOP 如果signo是SIGCHLD,子进程停止时,不产生此信号,子进程终止时才产生此信号
SA_NOCLDWAIT 如果signo是SIGCHLD,当调用进程的子进程终止时,不创建僵死进程。如果调用进程随后调用wait,则阻塞到它所有子进程都终止,此时wait返回-1,errno设置为ECHILD
SA_ONSTACK 如果用sigaltstack已声明一个替换栈,则此信号递送给替换栈上的进程
SA_NODEFER 当捕捉到此信号时,在执行其信号捕捉函数时,系统不自动阻塞此信号
SA_RESETHAND 在此信号捕捉函数开始时,将此信号的处理方式重置为SIG_DFL,并且清除SA_SIGINFO标志(但是,不能重置SIGILL和SIGTRAP这两个信号的配置)
SA_SIGINFO 若被设置,则使用sa_sigaction函数

用sigaction()实现的signal函数

#include "apue.h"
#include <signal.h>
typedef void Sigfunc(int);

Sigfunc* signal(int signo, Sigfunc* func)
{
    struct sigaction act, oact;
    act.sa_handler = func;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if(signo == SIGALRM){
#ifdef SA_INTERRUPT
        act.sa_flags |= SA_INTERRUPT;
#endif
    }
    else{
        act.sa_flags |= SA_RESTART;
    }
    if(sigaction(signo,&act,&oact) == -1)
        return(SIG_ERR);
    return(oact.sa_handler);
}

 

10.15 sigsetjmp和siglongjmp函数

#include <setjmp.h>
int sigsetjmp(sigjmp_buf env, int savemask);//savemask为非0值
直接调用返回0;若从siglongjmp调用返回,则返回非0;
void siglongjmp(sigjmp_buf env, int val);

于信号中断停止执行:

10.17 abort函数

#include <stdlib.h>
void abort(void);

abort()实现

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void abort(void)
{
    sigset_t mask;
    struct sigaction action;

    sigaction(SIGABRT,NULL,&action);
    if(action.sa_handler == SIG_IGN){//对SIGABRT的信号设置方式中的忽略和默认统一成默认方式,信号捕捉函数方式的不予改变
        action.sa_handler = SIG_DFL;
        sigaction(SIGABRT,&action,NULL);
    }
    if(action.sa_handler == SIG_DFL)
        fflush(NULL);

    sigfillset(&mask);
    sigdelset(&mask,SIGABRT);
    sigprocmask(SIG_SETMASK,&mask,NULL);//除了SIGABRT信号,其它信号都屏蔽掉
    kill(getpid(), SIGABRT);//在kill返回前SIGABRT信号传递到了该进程

    //以下是信号处理函数中并未exit(),而是退出之后产生的。
    fflush(NULL);
    action.sa_handler = SIG_DFL;
    sigaction(SIGABRT,&action,NULL);
    sigprocmask(SIG_SETMASK,&mask,NULL);
    kill(getpid(), SIGABRT);
    exit(1);
}

no_restart.c

10.18 system函数

POSIX要求:

  1. 以执行system时,应当阻塞对大人进程递送SIGCHLD信号。
  2. system的调用者在待命令就时当忽略SIGINT和SIGQUIT信号

#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>

int system(const char *cmdstring)
{
    pid_t pid;
    int status;
    struct sigaction ignore, saveintr, savequit;
    sigset_t chldmask, savemask;

    if(cmdstring == NULL)
    {
        return(1)l
    }

    ignore.sa_handler = SIG_IGN;
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if(sigaction(SIGINT, &ignore, &saveintr) < 0)
        return(-1);
    if(sigaction(SIGQUIT, &ignore, &savequit) < 0)
        return(-1);
    sigemptyset(&chldmask);
    sigaddset(&chldmask,SIGCHLD);
    if(sigprocmask(SIG_BLOCK, &chldmask, &savemask) < 0)
        return(-1);

    if((pid = fork()) < 0)
        status = -1;
    else if(pid == 0){
        sigaction(SIGINT,&saveintr, NULL);
        sigaction(SIGQUIT,&savequit,NULL);
        sigprocmask(SIG_SETMASK, &savemask, NULL);

        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127);
    } else{
        while(waitpid(pid,&status,0) < 0)
            if(errno != EINTR){
                status = -1;
                break;
            }
    }

    if(sigaction(SIGINT,&saveintr,NULL) < 0)
        return(-1);
    if(sigaction(SIGQUIT,&savequit,NULL) < 0)
        return(-1);
    if(sigprocmask(SIG_SETMASK, &savemask, NULL) < 0)
        return(-1);

    return(-1);
}
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <signal.h>
 6 #include <errno.h>
 7 
 8 #define BUFSIZE (1024)
 9 
10 static void sig_alrm(int signo)
11 {
12     printf("caught alarm...\n");
13 }
14 
15 void sig_usr(int signo)
16 {
17     if (signo == SIGUSR1)
18         printf("received SIGUSR1\n");
19     else if (signo == SIGUSR2)
20         printf("received SIGUSR2\n");
21     else
22         printf("received signal %d\n", signo);
23 }
24 
25 int main(int argc, char** argv)
26 {
27     int nSize = 0;
28     char acBuf[BUFSIZE] = {0};
29     struct sigaction act, oact;
30 
31     act.sa_handler = sig_usr;
32     sigemptyset(&act.sa_mask);
33     act.sa_flags = 0|SA_INTERRUPT;
34 
35     sigaction(SIGUSR1, &act, &oact);
36     signal(SIGALRM, sig_alrm);
37 
38     alarm(5);
39 
40     //while(1)
41     {
42         
43         memset(acBuf, '\0', BUFSIZE);
44         nSize = read(STDIN_FILENO, acBuf, BUFSIZE); 
45         if (errno == EINTR)
46             printf("interrupt, size=%d\n", nSize);
47 
48         if (1 == nSize && acBuf[0] == 10)
49             ;
50         else if (nSize != -1)
51         {
52             printf("nSize=%d, acBuf=%s", nSize, acBuf);
53         }
54     }
55 
56     return 0;
57 }

10.19 sleep,nanosleep,clock_nanosleep函数

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
返回0或者未休眠完的秒数

sleep函数要求,此函数使调用进程被吊于直到满足下面两只极有:

  1. 业已透过了seconds所指定的墙上时钟时间
  2. 调用进程捕捉到一个信号并于信号处理程序返回

#include "apue.h"

static void sig_alrm(int signo)
{
    //什么都没做,只是返回从而唤醒sigsuspend()
}

unsigned int sleep(unsigned int seconds)
{
    struct sigaction newact, oldact;
    sigset_t newmask,oldmask,suspmask;
    unsigned int unslept;

    //设置sa_handler,保存之前SIGALRM的信号处理设置
    newact.sa_handler = sig_alrm;
    sigemptyset(&newact.sa_mask);
    newact.sa_flags = 0;
    sigaction(SIGALRM, &newact, &oldact);


    //阻塞SIGABRM信号,保存当前信号屏蔽字
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGALRM);
    sigprocmask(SIG_BLOCK, &newmask, &oldmask);

    alarm(seconds);
    suspmask = oldmask;

    //让SIGALRM不被阻塞
    sigdelset(&suspmask, SIGALRM);

    //等待任何信号被捕捉
    sigsuspend(&suspmask);

    unslept = alarm(0);

    sigaction(SIGALRM,&oldact, NULL);

    sigprocmask(SIG_SETMASK, &oldmask, NULL);
    return(unslept);
}

#include <time.h>
int nanosleep(const struct timespec *reqtp, struct timespec *remtp);
若休眠到要求的时间,返回0,,出错返回-1

#include <time.h>
int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *reqtp, struct timespec *remtp);
若休眠到要求的时间,返回0,,出错返回-1

clock_nanosleep(CLOCK_REALTIME, 0, reqtp, remtp) == nanosleep(reqtp,remtp)

运转结果为:

10.20 sigqueue函数

运排队信号必须开的操作:

  1. 用sigaction函数安装信号处理程序时指定SA_SIGINFO标志。但是当Linux中,无需用SA_SIGINFO,也针对信号排队。
  2. 下sigaction结构中之sa_sigaction成员。
  3. 使用sigqueue()函数发送信号

#include <signal.h>
int sigqueue(pid_t pid, int signo, const union sigval value);
成功返回0,出错返回-1

Linux支持sigqueue()函数,但是不对SIGRTMIN和SIGRTMAX之外的信号排队。同时,无需用SA_SIGINFO,也针对信号排队。

图片 2

10.21 作业控制信号

SIGCHLD(大多数场面下拍卖该信号)
SIGCONT
已信号:SIGSTOP(不克叫捕捉和忽视),SIGTSTP,SIGTTIN,SIGTTOU
作业控制信号中有些交互。当对一个经过来停止信号中之自由一种植,对拖欠过程的凭一勿决SIGCONT信号被抛。当对一个进程来SIGCONT信号时,对同一进程的任一未决已信号为撇下。

#include "apue.h"

#define BUFFSIZE    1024

static void
sig_tstp(int signo) /* signal handler for SIGTSTP */
{
    sigset_t    mask;

    /* ... move cursor to lower left corner, reset tty mode ... */

    /*
     * Unblock SIGTSTP, since it's blocked while we're handling it.
     */
    sigemptyset(&mask);
    sigaddset(&mask, SIGTSTP);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);

    signal(SIGTSTP, SIG_DFL);   /* reset disposition to default */

    kill(getpid(), SIGTSTP);    /* and send the signal to ourself */

    /* we won't return from the kill until we're continued */

    signal(SIGTSTP, sig_tstp);  /* reestablish signal handler */

    /* ... reset tty mode, redraw screen ... */
}

int
main(void)
{
    int     n;
    char    buf[BUFFSIZE];

    /*
     * Only catch SIGTSTP if we're running with a job-control shell.
     */
    if (signal(SIGTSTP, SIG_IGN) == SIG_DFL)
        signal(SIGTSTP, sig_tstp);

    while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
        if (write(STDOUT_FILENO, buf, n) != n)
            err_sys("write error");

    if (n < 0)
        err_sys("read error");

    exit(0);
}

本条例子中,alarm信号还是机关重新启动,手动发送一个SIGUSR1信号后,SIGUSR1信号处理程序执行了晚,read()立马就回来了。

10.22 信号名和数码

#include <signal.h>
void psignal(int signo, const char *msg);

void psiginfo(const siginfo_t *info, const char *msg);

#include <string.h>
char *strsignal(int signo);

于点两个例中尚得看看signal()和sigaction()两单函数的反差,显然sigaction对信号的的拍卖越灵活。

相关文章