这有点长...对于初学者我在Linux 2.6.33,gcc 4.4.4。
我编写了一个小程序,它创建一个命名管道并读取它,直到它看到某个字符串,然后它取消了FIFO,然后重新执行。
#include<unistd.h>
#include<fcntl.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
int fifo;
#define put(x) write(1, x, (sizeof x)-1)
void reader(int a)
{
char buf[26];
int n;
while((n=read(fifo, buf, 25))>0){
buf[25] = '\0';
if(!strncmp(buf, "moo", 3)){
put("exec()-ing\n");
close(fifo);
unlink("lefifo");
execl("/home/dave/a.out", "a.out", 0);
}
write(1, buf, n);
}
}
main()
{
signal(SIGIO, reader);
mknod("lefifo", 0600|S_IFIFO,0);
fifo = open("lefifo", O_RDONLY|O_NONBLOCK );
fcntl(fifo, F_SETOWN, getpid());
fcntl(fifo, F_SETFL, O_ASYNC);
for(;;)
pause();
}
编译后,在后台运行时,我可以回显lefifo
并按预期工作,直到我输入一个以“moo”开头的字符串。以下示例会话:
$ gcc fifo.c
$ ./a.out&
$ echo klar > lefifo
klar
$ echo moo > lefifo
exec()-ing
$ echo klar2 > lefifo
$ echo where did you go > lefifo
$ echo moo > lefifo
$ pkill a.out
生成此痕迹(修剪一些脂肪):
execve("./a.out", ["./a.out"], [/* 36 vars */]) = 0
mknod("lefifo", S_IFIFO|0600) = 0
open("lefifo", O_RDONLY|O_NONBLOCK) = 3
getpid() = 3945
fcntl(3, F_SETOWN, 3945) = 0
fcntl(3, F_SETFL, O_RDONLY|O_ASYNC) = 0
pause() = ? ERESTARTNOHAND (To be restarted)
--- SIGIO (I/O possible) @ 0 (0) ---
read(3, "klar\n"..., 25) = 5
write(1, "klar\n"..., 5) = 5
read(3, ""..., 25) = 0
sigreturn() = ? (mask now [])
pause() = ? ERESTARTNOHAND (To be restarted)
--- SIGIO (I/O possible) @ 0 (0) ---
read(3, "moo\n"..., 25) = 4
write(1, "exec()-ing\n"..., 13) = 13
close(3) = 0
unlink("lefifo") = 0
execve("/home/dave/a.out", ["a.out"], [/* 36 vars */]) = 0
mknod("lefifo", S_IFIFO|0600) = 0
open("lefifo", O_RDONLY|O_NONBLOCK) = 3
getpid() = 3945
fcntl(3, F_SETOWN, 3945) = 0
fcntl(3, F_SETFL, O_RDONLY|O_ASYNC) = 0
pause() = ? ERESTARTNOHAND (To be restarted)
--- SIGTERM (Terminated) @ 0 (0) ---
正如你所看到的,第一次,制作FIFO没有问题,SIGIO生成就好了;但在exec()
之后,新FIFO将不会产生任何信号。旧的显示成功关闭,似乎成功删除。
我很难过为什么会这样做。有什么想法吗?
答案 0 :(得分:5)
当您使用signal()
安装信号处理程序时,在默认配置中,glibc将给出BSD信号语义:该信号将在信号处理程序执行时被阻止,并在返回时被解锁。
当您从信号处理程序调用{{1}}时,信号处理程序不会返回,因此exec()
仍然被阻止。进程信号掩码在SIGIO
上继承,因此它在进程的新实例中仍然被阻止。
在exec()
开始时使用SIGIO
明确取消阻止sigprocmask()
,您应该得到您所追求的行为。
答案 1 :(得分:3)
当调用信号处理程序时,信号被阻塞,直到执行信号处理程序。一旦信号处理程序完成,就会调用sigreturn()来解锁信号。你可以在你的工作案例中看到。但是,当你键入'moo'时,你从信号处理程序调用execl并且execl()不会返回,所以信号处理程序不会返回。如果信号处理程序没有返回,则不会调用sigreturn(),也不会从阻止列表中删除信号。
您可以使用cat / proc // status查看信号状态。您运行程序并查看/ proc // status,在那里您可以看到sigio正在等待,并且它也被阻止。
访问www.rulingminds.com获取Linux内核文章。
答案 2 :(得分:1)
我建议将execl
(或任何其他处理)移出信号处理程序。您可以在信号处理程序中设置一个标志,并在main
中对其进行轮询。