希望shell和一个程序都同时接收一个ctrl-c,最好的办法就是将它们设置到一个进程组当中,并且把这个进程组设置为终端上的前台进程组,如下所示,其中2774是该终端上bash进程的pid:
void handler(int n)
{
printf("GOT SIGINT/n");
}
int main()
{
setpgid(0, 2774); //将test和bash设置成同一个进程组
signal(SIGINT, handler);
while (1) {
sleep(1);
//kill(0, SIGINT); //先注释掉
}
}
编译为test,在运行test之前先设置一下bash的trap,使得bash也能捕捉到SIGINT信号:
trap 'echo got sigint' INT
希望的情况是,运行test后按下ctrl-c,屏幕上显示GOT SIGINT和got sigint,可是一个也没有显示,为何?
这就涉及到了控制终端,进程组等概念了。bash没有打印got sigint是因为当bash调用fork-exec启动test的时候,已经调用了ioctl(fd, TIOCSPGRP, &子进程pid);而ioctl会将子进程即test的pid设置成tty的pgrp字段,这个事实通过两种方式可以了解到,第一可以通过strace命令,其次可以通过看一下bash和linux内核的源码,内核在接收到ctrl-c的时候会将此键码作为普通字符放入终端的接收缓冲中去,就是调用终端行规程的receive_buf。然后receive_buf最终发现ctrl-c控制字符后会调用isig函数,后者继续调用kill_pg(tty->pgrp, sig, 1);最终tty->pgrp决定了要发送信号给谁。bash既然已经将tty的pgrp改成了test的pid,而test又把自己交给了bash,在调用setpgid的时候,test会将自己从pgid表上detach,因此for_each_task_pid(tty->pgrp, PIDTYPE_PGID, p, l, pid)将一个进程也找不到,所以就谁也收不到了。
现在放开kill代码行的注释,再次编译运行,自己发送信号,GOT SIGINT成功显示了,可是bash的got sigint却没有显示,这是因为bash在wait子进程的结束,没有打印got sigint是因为此时终端被前台的test独占了,SIGINT其实已经pendding到bash了,不信的话将test结束掉,看看got sigint是不是打印出来了。既然是bash调用ioctl将tty的pgrp给改了,那么改回来是不是就可以了呢?倒是可以试一下,重新注释掉kill行并且添加下面的代码:
tcsetpgrp(fd, 2774);
或者下面的:
ioctl(fd, TIOCSPGRP, &id);
结果连调用都不成功...为何bash就可以将终端的的pgrp设置成别人的而test就不行呢?难道bash是什么特权进程吗?unix/linux中是没有特权进程的,所以还要从test本身来找原因,毕竟它非常短小。我们看到程序一开始有个setpgid的调用,这里面有点说法。内核是不负责设置pgid或者session的,这些都是bash的事情,内核函数copy_process中可以看出,只要不是创建线程,内核会将所有的进程都设置到一个进程组中,然而事实上系统的众多进程却不是属于同一个进程组,这就是bash在中间做了点事情,bash在启动新进程时会调用setpgid将新进程的pgid设置成其pid,因此所有的子进程都单独占有一个进程组,关键问题就是为何调用了setpgid之后就不能能再设置终端的pgrp了呢?这里面的原因在于POSIX的一个规定,那就是不能将孤儿进程组设置成tty的前台进程组,所谓的孤儿进程组就是组内的所有成员要么自己和父亲在同一个组,这样的话受影响是一致的,要么就是自己和父亲属于不同的session,如此一来终端信号将在父子之间隔离,而我们的test中经过第一行那么一设置之后,pgrp组就成了孤儿进程组,里面一共就两个进程,一个bash,一个test,因此后面的TIOCSPGRP调用将不会成功。
最后,如果非要实现ctrl-c影响两个进程的话,办法是有的,那就是执行test &,后面要加一个&号,bash在执行这一类进程的时候将不会调用TIOCSPGRP的ioctl让子进程独占终端,相反bash会让自己占据终端,这样执行后按下ctrl-c,将同时输出got sigint和GOT SIGINT
分享到:
相关推荐
《GNU C Library (glibc) 2.2详解》 GNU C Library,简称glibc,是GNU项目的一个关键组成部分,它是Linux系统中最基础且至关重要的动态链接库之一。glibc为程序员提供了大量的C语言编程接口,包括基本的I/O、字符串...
在使用`linuxthreads`时,开发者需要注意线程安全问题,如互斥锁(mutexes)、条件变量(condition variables)、信号量(semaphores)等同步机制的正确使用,以避免数据竞争和其他并发问题。同时,由于`...
winlibs-x86_64-posix-seh-gcc-11.3.0-llvm-14.0.3-mingw-w64msvcrt-10.0.0-r3.zip
标题“winlibs-x86-64-posix-seh-gcc-13.2.0-llvm-16.0.6-mingw-w64msvcrt”指的是一个专为Windows平台设计的C和C++编译工具链。这个工具链集成了GCC (GNU Compiler Collection) 13.2.0版本和LLVM 16.0.6编译器,...
在编程领域,尤其是在Windows平台上进行C/C++开发时,我们经常会遇到x86-64-posix-seh和MinGW-W64这两个关键概念。它们是构建和运行32位及64位程序的重要组成部分,尤其是对于那些依赖于GCC(GNU Compiler ...
支持c++23
标题中的"winlibs-i686-posix-dwarf-gcc-10.2.0-llvm-11.0.0-mingw-w64-8.0.0-r5.zip"表明这是一个针对Windows 32位平台的编译器工具链压缩包,其中包含了多个关键组件。首先,`i686`是指英特尔32位架构,说明这是为...
官方离线安装包,测试可用。请使用rpm -ivh [rpm完整包名] 进行安装
arm-none-linux-gnueabi-gcc.exe -v Using built-in specs. COLLECT_GCC=arm-none-linux-gnueabi-gcc.exe ...Thread model: posix gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite
"Mingw64-posix-sjlj.zip"是一个包含了MingGW64的版本,它使用了SJLJ(Set Jump/Long Jump)异常处理机制。SJLJ是一种在编译器中实现异常处理的方法,相比其他如DWARF或SEH(Structured Exception Handling)机制,...
官方离线安装包,测试可用。请使用rpm -ivh [rpm完整包名] 进行安装
本压缩包文件“posix-timers.rar_CLOCKS”专注于POSIX中的定时器和时钟功能。 首先,我们要理解什么是POSIX时钟。POSIX时钟是系统提供的一组时间源,用于跟踪和管理时间。它们包括以下几种类型: 1. `CLOCK_...
MSYS是Windows上模拟Unix-like环境的工具集,它允许开发者在Windows下运行许多基于POSIX的命令行工具,如`bash`、`gcc`等。`make-3.81.90-msys`是`make`在MSYS环境下的移植版,确保了开发者能在Windows环境中享受到...
在IT行业中,POSIX(可移植操作系统接口)标准是一组定义了操作系统必须提供的接口和服务的规范,以便软件可以在多种不同的操作系统上运行。这个名为“posix-clock.rar_posix”的压缩包文件,显然与POSIX时间相关,...
mavros-posix-sitl.launch
jruby-dist-9.1.15.0-bin.tar.gz JRuby是面向Ruby、基于Java虚拟机...New POSIX-friendly IO and Process Fully ported encoding/transcoding logic from MRI MD5:01c29690324d7eb414fba66e4c009c9e 大小:20.0 MB
jruby-dist-9.1.15.0-bin.zip JRuby是面向Ruby、基于Java虚拟机(JVM)...New POSIX-friendly IO and Process Fully ported encoding/transcoding logic from MRI MD5:2f55b66607f26cd460b5a75a8f209bb9 大小:21.5 MB
mingw编译器离线库,mingw-64.i686-6.3.0-posix-dwarf-rt_v5-rev1.mingw32。 文件夹路径:mingw-64/i686-6.3.0-posix-dwarf-rt_v5-rev1/mingw32/
6. `ncurses`:用于开发终端用户界面的库,编译过程中的部分工具可能需要。 7. `pthreads`:线程库,用于支持多线程编程。 8. `kernel-headers`:内核头文件,用于编译过程中生成系统调用接口。 执行以下命令安装...
除了基本的编译和匹配,还包括了诸如递归、命名捕获组、Unicode属性支持等高级特性。 2. **头文件解析:** - **pcre2posix.h**:此头文件包含了在C语言中使用POSIX接口的函数声明。通过包含这个头文件,开发者可以...