SIGTTIN: 当一个后台进程组试图读取其控制终端时,终端驱动程序产生此信号。在下列例外情况不产生次信号: a、读进程忽略或者堵塞此信号 b、读进程所属的进程组是孤儿进程组,此时读操作返回出错,errno设置未EIO。
SIGTTOU: 当一个后台进程组试图写其控制终端时,终端驱动程序产生此信号。与SIGTTIN信号不同,一个进程可以算着允许后台进程写控制终端。 如果不允许写控制终端,则与SIGTTIN相似,也有两种特殊情况: a、写进程忽略或者堵塞此信号 b:写进程所属的进程组是孤儿进程组,此时读操作返回出错,errno设置未EIO。
SIGTTIN 和 SIGTTOU 信号的默认动作是暂停进程。
下图代码,进程启动,fork 出子进程,子进程设置进程组,调用tcsetpgrp 将自己设置为前端进程组,父进程就变成了后端进程组。在read的时候,暂停。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
//打印进程信息
void pr_process(char * name){
printf("%s pid:%d,ppid:%d,pgid:%d,sid:%d,grrp:%d\n",name,getpid(),getppid(),getpgid(getpid()),getsid(getpid()),tcgetpgrp(STDIN_FILENO));
}
void handler(int sig){
printf("receive %d sig\n",sig);
}
int main(int argc,char *argv[]){
pid_t pid ;
pid_t fpgid = tcgetpgrp(STDIN_FILENO);
if((pid = fork()) < 0){
perror("fork error");
exit(1);
}
if(pid == 0){
signal(SIGTTOU,SIG_IGN);
setpgid(getpid(),getpid());
pr_process("child before set:");
if(tcsetpgrp(STDIN_FILENO,getpid()) == -1){
printf("set error\n");
exit(2);
}
pr_process("child after set");
exit(1);
}
pr_process("parent1");
waitpid(pid,NULL,0);
pr_process("parent2");
char buf[100];
// signal(SIGTTIN,handler);
if(read(STDIN_FILENO,buf,100) < 0){
perror("read error");
printf("error\n");
exit(127);
}
printf("sucess\n");
return 0;
}
补充: 上面的代码中,在进程中设置了忽略SIGTTOU信号。
因为在tcsetpgrp 的手册中是这样说的:如果tcsetpgrp 被一个后端进程组中的一员调用,并且调用进程没有阻塞或忽略 SIGTTOU,那么SIGTTOU 信号会被发送给这个后端进组的所有成员。
我们在在子进程fork一个进程实验一下如果tcsetpgrp。
实验一:将上述程序的 signal(SIGTTOU,SIG_IGN); 改为 signal(SIGTTOU,handler); 执行打印结果: 一直在发送SIGTTOU信号,在收到中断信号后,标记执行tcsetpgrp 失败。
相关文章
暂无评论...