硬件异常。 比如遇到除以0, 或者内存访问越界的情况。
kill 函数发相应的信号
软件条件发生。 比如向一个已经关闭的管道写数据会产生SIGPIPE,以及闹钟信号SIGALRM。或者网络上传来一个非规定波特率的数据,SIGURG
#include
#include
static void sig_alrm(int signo)
{
printf("Caught alarm signal\n");
}
int main()
{
if (signal(SIGALRM,sig_alrm)==SIG_ERR)
{
printf("Register SIGALRM failed\n");
return -1;
}
//register one second alarm
alarm(1);
pause();
printf("Exit main\n");
}
//输出
//Caught alarm signal
//Exit main
SIGPIPE的例子
#include
#include
#include
static void sig_pipe(int signo)
{
printf("Caught signal pipe signal\n");
}
int main()
{
int fd[2];
if(pipe(fd)<0)
{
printf("Create pipe failed\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid<0)
{
printf("fork error\n");
}
else if (pid>0)
{
close(fd[0]);
// register pipe signal
if(signal(SIGPIPE,sig_pipe)==SIG_ERR)
{
printf("register SIGPIPE error\n");
sleep(1);
exit(-1);
}
sleep(1);
printf("Parent Prcess begin\n");
//try to write a closed pipe
if(write(fd[1],'c',1)!=1)
printf("write pipe error\n");
close(fd[1]);
printf("Parent Prcess end\n");
}
else
{
printf("Child Prcess begin\n");
//here close read and write channel
close(fd[0]);
close(fd[1]);
}
}
输出
Child Prcess begin
Parent Prcess begin
Caught signal pipe signal
write pipe error
Parent Prcess end
Kill 函数的例子
#include
#include
static void sig_usr1(int signo)
{
printf("Get signal user1 \n");
}
int main()
{
if (signal(SIGUSR1, sig_usr1)==SIG_ERR)
{
printf("Register sig user1 failed\n ");
}
kill(getpid(),SIGUSR1);
printf("End of main\n");
}
3. 对待信号的三种方式: 捕抓,忽视或者系统默认。 SIGKILL, SIGSTOP不可忽略。
4. Signal 函数 void(* signal(int signo, void(*func)(int) ) ) (int), 好复杂。
typedef void Sigfunc (int)
然后再定义 Sigfunc* signal(int signo, Sigfunc*)
5. 程序后台启动时候shell 自动对SIGINT 和SIGQUIT 选择忽略
6. 进程创建时候子进程复制父进程的信号处理方式
#include
#include
#include
void sig_quit(int signo)
{
printf("caught SIGQUIT \n");
}
int main()
{
if (signal(SIGQUIT,sig_quit)==SIG_ERR)
{
printf("Register sigquit error\n");
}
pid_t pid ;
pid = fork();
if (pid< 0)
{
printf("fork error\n");
exit(-1);
}
else if(pid>0)
{
while(1)
pause();
}
else
{
while(1)
pause();
}
}
输入ctrl+\ 时候会得到两行,分别为子进程和父进程产生的
caught SIGQUIT
caught SIGQUIT
7. 中断的系统调用。
系统调用分为低速系统调用和其他系统调用。低速系统调用,信号发生时, 其不再执行。
低速系统调用包括:
a. pause 函数
b. 读某些文件,数据不存在;如果某进程为读打开FIFO,且此时没有为写的进程打开该FIFO
#include
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/fifotest"
#define BUF_LEN 512
int main()
{
int res;
extern int errno;
res = mkfifo(FIFO_NAME, O_CREAT| O_EXCL);
if ((res<0) && (errno!= EEXIST))
{
printf("We get an error %d, reason %s\n", errno, strerror(errno));
}
int fd = open(FIFO_NAME,O_RDONLY,0);
char buf[BUF_LEN];
int n;
if ((n=read(fd, buf,BUF_LEN))<0)
{
printf("read error %d, reason %s\n", errno, strerror(errno));
}
buf[n]= '\0';
printf("read data from fifo: %s\n", buf);
}
上面代码将一直阻塞,一直等到有其他程序写fifo为止。
下面代码将写相应的fifo,运行下面代码可使得上面读fifo的进程激活,并输出内容。
#include
#include
#include
#include
#include
#define FIFO_NAME "/tmp/fifotest"
int main()
{
int fd;
fd = open(FIFO_NAME, O_WRONLY,0 );
char* buf = "Greeting from fifo message\n";
if(write(fd, buf, strlen(buf))!= strlen(buf))
{
printf("Write error. errno= %d, reason is : %s\n", errno, strerror(errno));
}
}
c. 写某些文件,不能立即接受这些数据;打开文件时; 某种ioctl函数;某些进程间通信函数。
8. 可再入函数
典型的不可再入函数包括 a)malloc, free b) 操作静态区内容的函数, 比如getpwnam c)标准IO 函数
9. 信号未决
信号未决指的是信号产生,却还没有传递到进程的状态。
如果一个信号发生多次,那最终进程接收信号时,只会被传递一次。
10. Kill ,raise函数
Kill函数参数: a) pid>0, 则发送给对应pid进程。 b) pid == 0 , 发送信号给所在进程的进程组所有进程 c) pid< 0, 发送给绝对值等于PID的进程组中所有进程
#include
#include
static void sig_usr1(int signo)
{
printf("Get signal user1 \n");
}
int main()
{
if (signal(SIGUSR1, sig_usr1)==SIG_ERR)
{
printf("Register sig user1 failed\n ");
}
kill(getpid(),SIGUSR1);
printf("Test kill pid > 0 senario done\n");
pid_t pid;
if ((pid=fork())<0)
{
printf("Fork error\n ");
}
else if (pid> 0)
{
printf("pid = %d, group id = %d\n", getpid(), getpgrp());
while(1)
pause();
}
else
{
printf("pid = %d, group id = %d\n", getpid(), getpgrp());
kill(0,SIGUSR1);
}
}
测试了kill pid>0 和pid=0的情况
输出为:
Get signal user1
Test kill pid > 0 senario done
pid = 28220, group id = 28220
pid = 28221, group id = 28220
Get signal user1
Get signal user1
11. alarm 和pause 函数
alarm 提示系统多长时间向进程发送SIGALRM信号. alarm 函数后注册的闹钟会把前面注册的给覆盖掉。比方说下面的例子,printf两次之间应该只是相隔一秒钟时间。
time now is 1440655538
Caught alarm signal
time now is 1440655539
#include
#include
#include
static void sig_alrm(int signo)
{
printf("Caught alarm signal\n");
}
int main()
{
if (signal(SIGALRM,sig_alrm)==SIG_ERR)
{
printf("Register SIGALRM failed\n");
return -1;
}
//register one second alarm
printf("time now is %d\n", time(NULL));
alarm(2);
alarm(1);
pause();
printf("time now is %d\n", time(NULL));
pause函数则阻塞进程,直到进程得到信号。
用alarm, pause 和setjmp 设置的sleep 函数。缺点是当和其他信号发生冲突时,会有些问题。
#include
#include
#include
static jmp_buf buf;
static void sig_alrm(int signo)
{
longjmp(buf,1);
}
int sleep2(unsigned int seconds)
{
if (signal(SIGALRM, sig_alrm)==SIG_ERR)
{
printf("Register SIGALRM failed\n");
}
alarm(seconds);
if(!setjmp(buf))
{
printf("set jump first return\n");
pause();
}
else
{
printf("Set jump returned\n");
}
return seconds;
}
int main()
{
sleep2(1);
}
#include
#include
#include
static jmp_buf buf;
static void sig_alrm(int signo)
{
longjmp(buf,1);
}
int sleep2(unsigned int seconds)
{
if (signal(SIGALRM, sig_alrm)==SIG_ERR)
{
printf("Register SIGALRM failed\n");
}
alarm(seconds);
if(!setjmp(buf))
{
printf("set jump first return\n");
pause();
}
else
{
printf("Set jump returned\n");
}
return seconds;
}
static void sig_int(int signo)
{
printf("Sum is 0\n");
volatile int sum;
int i;
for(i=0;i<2000000000;i++)
sum += i*i;
printf("Sum is %d\n", sum);
}
int main()
{
if(signal(SIGINT,sig_int)==SIG_ERR)
{
printf("Register SIGINT failed\n");
}
sleep2(5);
}
int sigemptyset(sigset_t * )
int sigfillset(sigset_t *)
int sigdelset(sigset_t* ,int signo)
int sigaddset(sigset_t* ,int signo)
int sigismember(const sigset_t *, int signo)
int sigprocmask(int how, const sig_set* new, sig_set* old)
sigprocmask是个好函数,一个函数既可以获取当前信号屏蔽字,也可以设置信号屏蔽。
how 等于SIG_BLOCK, SIG_UNBLOCK,SIG_SETMASK。前面为取并,第二个为取交,最后一个直接设置。 打印当前屏蔽字的demo
#include
#include
#include
#include
void printmask()
{
int result;
sigset_t new,old;
if (sigprocmask(SIG_BLOCK,NULL, &old)<0)
{
printf("Sigprocmast failed. errno = %d, error is: %s\n", errno, strerror(errno));
return;
}
if (sigismember( &old,SIGALRM))
printf("sig_alrm has been in signal mask\n");
printf("End of print mask\n");
}
int main()
{
sigset_t new,old;
if(sigemptyset(&new)<0 || sigemptyset(&old)<0 || sigaddset(&new, SIGALRM)<-1)
{
printf("sigemtpy set error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
if (sigprocmask(SIG_BLOCK,&new, &old)<-1)
{
printf("sigprocmask set error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
printmask();
}
int sigpending(sigset_t*) 正确返回0,未决信号存储在参数中。下面代码执行后,中间按两次ctrl + c,得到结果
SIGINT is in pending status
Caught sig int
#include
#include
#include
#include
static void sig_int(int signo)
{
printf("Caught sig int \n");
}
int main()
{
sigset_t new,old;
sigset_t pending;
if (signal(SIGINT,sig_int) ==SIG_ERR)
{
printf("signal error\n");
return;
}
if(sigemptyset(&new)<0 || sigemptyset(&old)<0 || sigemptyset(&pending)<0 || sigaddset(&new, SIGINT)<-1)
{
printf("sigemtpy or sigemptyset error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
if (sigprocmask(SIG_BLOCK,&new, &old)<-1)
{
printf("sigprocmask set error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
sleep(5);
if (sigpending(&pending)<-1)
{
printf("sigpending error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
if (sigismember(&pending, SIGINT))
printf("SIGINT is in pending status\n");
if (sigprocmask(SIG_SETMASK,&old, NULL)<-1)
{
printf("sigprocmask set error. errno = %d, error is : %s\n",errno,strerror(errno));
return -1;
}
}
int sigaction(int signo, const sigaction* act, sigaction* oact)
struct sigaction
{
void (*sighandler)(); //signal process function
sigset_t mask; //mask 为信号屏蔽字,在sighandler 函数返回之前,会屏蔽信号。返回后再解除屏蔽,这样做的目的是保证sighandler的执行不会受到影响。
int sa_flags;
};
14. sigsetjmp, setjmp, setlongjmp 和longjmp
siglongjmp 从信号函数跳出后会恢复信号屏蔽字,而longjmp从信号函数跳出后则不会恢复信号。
下面代码,当用sig开头函数时,每次向进程发送SIGUSR1信号时都会输出一次:
Get signal usr1
Returned from sigsetjmp
而不用sig开头函数时,只有第一次向进程发送SIGUSR1才会输出:
Get signal usr1
Returned from sigsetjmp
#include
#include
#include
#include
#include
#include
static jmp_buf buf;
static void sig_usr(int signo)
{
printf("Get signal usr1\n");
//siglongjmp(buf,1);
longjmp(buf,1);
}
int main()
{
if (signal(SIGUSR1,sig_usr)==SIG_ERR)
{
printf("Register singal error %d. reason:%s\n", errno, strerror(errno));
exit(-1);
}
//if(!sigsetjmp(buf,1))
if(!setjmp(buf))
{
printf("sigsetjmp buf\n");
}
else
{
printf("Returned from sigsetjmp\n");
}
while(1)
pause();
}
#include
#include
#include
#include
#include
static void sig_usr1(int signo)
{
printf("Get signal\n");
}
int main()
{
printf("Begin main()\n");
if (signal(SIGUSR1,sig_usr1)==SIG_ERR ||signal(SIGINT,sig_usr1)==SIG_ERR )
{
printf("Register sig_usr1 failed. errno=%d, error = %s", errno,strerror(errno));
return -1;
}
sigset_t oldset, newset, pendmask;
if(sigemptyset(&oldset)<0 || sigemptyset(&newset)<0 ||sigemptyset(&pendmask)<0 || \
sigaddset(&newset,SIGUSR1)<0 ||sigaddset(&newset,SIGINT)<0 || sigaddset(&pendmask,SIGUSR1)<0)
{
printf("sigemtpyset or sigaddset error. errno=%d, error = %s", errno,strerror(errno));
return -1;
}
if (sigprocmask(SIG_BLOCK,&newset,&oldset)<0)
{
printf("sigprocmask error. errno=%d, error = %s", errno,strerror(errno));
return -1;
}
printf("Critical section\n");
sleep(5);
sigsuspend(&pendmask);
printf("Awake by signal");
if (sigprocmask(SIG_SETMASK,&oldset,NULL)<0)
{
printf("sigprocmask error. errno=%d, error = %s", errno,strerror(errno));
return -1;
}
}
16. abort函数
书上的abort函数有些啰嗦,不懂后面哪一段代码有什么必要。懂的同学可以评论下,让我知道。
#include
#include
#include
#include
#include
#include
void mabort(void)
{
struct sigaction action;
sigset_t set,oldset;
if(sigaction(SIGABRT,NULL,&action)<0)
{
printf("sigaction error:%d, reason: %s\n", errno,strerror(errno));
exit(-1);
}
if(action.sa_handler==SIG_IGN)
{
action.sa_handler == SIG_DFL;
sigaction(SIGABRT,&action,NULL);
}
if(action.sa_handler==SIG_DFL)
fflush(NULL);
if(sigfillset(&set)<0 || sigdelset(&set,SIGABRT)<0)
{
printf("sigfillset error:%d, reason: %s\n", errno,strerror(errno));
exit(-1);
}
if(sigprocmask(SIG_SETMASK,&set,NULL)<0)
{
printf("sigaction error:%d, reason: %s\n", errno,strerror(errno));
exit(-1);
}
kill(getpid(),SIGABRT);
printf("we are here\n");
printf("we are here\n");
fflush(NULL);
}
int main()
{
printf("we are in main\n");
mabort();
printf("we are end main\n");
return;
}
POSIX 2.0 要求system 函数忽略SIGINT , SIGQUIT,并且阻塞SIGCHLD。测试代码如下:
#include
#include
#include
#include
#include
int mysystem(const char* cmd)
{
struct sigaction ignore,saveintptr, savequitptr;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
pid_t pid;
int status;
//ignore sigint and sigquit
if (sigaction(SIGINT,&ignore,&saveintptr)<0 || sigaction(SIGQUIT,&ignore, &savequitptr)< 0 )
{
printf("sigaction failed. errno: %d, reason: %s",errno, strerror(errno));
return -1;
}
sigset_t childmask,savemask;
if (sigemptyset(&childmask)<0 || sigaddset(&childmask,SIGCHLD)<0)
{
printf("sigemtpyset failed. errno: %d, reason: %s",errno, strerror(errno));
return -1;
}
if (sigprocmask(SIG_BLOCK,&childmask,&savemask)<0)
{
//printf("sigaction failed. errno: %d, reason: %s",errno, strerror(errno));
return -1;
}
if((pid=fork())<0)
{
printf("fork error. errno: %d, reason: %s",errno, strerror(errno));
return -1;
}
else if(pid==0)
{
//child
sleep(5);
sigaction(SIGINT,&saveintptr,NULL);
sigaction(SIGQUIT,&savequitptr,NULL);
sigprocmask(SIG_SETMASK,&savemask,NULL);
execl("/bin/sh","sh","-c", cmd, (char*)0);
//why not print this, because, execl with no return if succeed
printf("returning child %d\n", pid);
fflush(NULL);
_exit(127);
}
else
{
//here should be blocked, just while in case of error
while(waitpid(pid, &status,0) <0)
{
printf("wait pid is %d\n", pid);
//why we use EINTR, EINTR is for slow system, which get signal, here in case of execl for slow function
if(errno!=EINTR)
{
status =-1;
break;
}
}
//waitpid(pid, &status,0) ;
printf("waiting %d\n", pid);
}
sigaction(SIGINT,&saveintptr,NULL);
sigaction(SIGQUIT,&savequitptr,NULL);
sigprocmask(SIG_SETMASK,&savemask,NULL);
return status;
}
int main()
{
int status = mysystem("ls -lt");
printf("status is %d\n", status);
}
18 sleep 函数实现
#include
#include
static void sig_alrm()
{
return;
}
unsigned int msleep(unsigned int nsecs)
{
sigset_t pendmask,oldmask,susmask;
struct sigaction action,oldaction;
action.sa_handler = sig_alrm;
if(sigemptyset(&action.sa_mask)<0)
return -1;
if(sigaction(SIGALRM,&action,&oldaction)<0)
return -1;
sigemptyset(&pendmask);
sigaddset(&pendmask, SIGALRM);
sigprocmask(SIG_BLOCK,&pendmask,&oldmask);
alarm(nsecs);
susmask = oldmask;
sigdelset(&susmask,SIGALRM);
sigsuspend(&susmask);
int uslept = alarm(0);
sigaction(SIGALRM,&oldaction,NULL);
sigprocmask(SIG_BLOCK,&oldmask,NULL);
return uslept;
}
int main()
{
msleep(5);
}