多次被杀死的进程没有收到信号 SIGUSR1
process killed more than one time does't receive signal SIGUSR1
我有 2 个 .c 脚本。一个是 father.c:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
pid_t childPid;
void createChild(){
fprintf(stderr,"creating a new child\n");
childPid=fork();
if(childPid==0){
execlp("./child","child",NULL);
perror("err");
}
fprintf(stderr,"created child pid is %d\n",childPid);
}
void signalHandler(int signal){
if(signal==SIGUSR1){
kill(childPid,SIGINT);
createChild();
}
}
int main(int argc,char ** argv){
signal(SIGUSR1,signalHandler);
signal(SIGCHLD,SIG_IGN);
createChild();/*create first child*/
while(1){
sleep(2);
int ret=kill(childPid,SIGUSR1);
if(ret==-1){
perror("exit err ");
}
}
}
另一个是child.c:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signalHandler(int signal){
if(signal==SIGUSR1){
fprintf(stderr,"child process received signal\n");
kill(getppid(),SIGUSR1);
}
}
int main(int argc,char ** argv){
fprintf(stderr,"i'm the new child with pid %d\n",getpid());
if(signal(SIGUSR1,signalHandler)==SIG_ERR){
fprintf(stderr,"error");
}
while(1){}
}
当 father 启动时,每 2 秒它应该终止 child,分叉自身并启动一个新的 child。
child 通过向他发送 SIGUSR1 信号被杀死,该信号被处理并转发给父亲(使用另一个 SIGUSR1 信号),父亲用 SIGINT 杀死 child。
我面临的问题是第二次创建 child 时,它不再接收 SIGUSR1 信号。
有人可以帮忙吗?
编辑:感谢@CraigEstey(请参阅下面的回答),他发现从 child 向 parent 进程发送不同的信号确实可以完成工作。
按照这个建议,我上面发布的代码应该像这样更改(为了让它工作):在 father.c 中将 if(signal==SIGUSR1)
替换为 if(signal==SIGUSR2)
并将 signal(SIGUSR1,signalHandler);
替换为 signal(SIGUSR2,signalHandler);
。
在 child.c 中将 kill(getppid(),SIGUSR1);
替换为 kill(getppid(),SIGUSR2);
。
如果这不是您想要的,我建议您阅读@CraigEstey 的回答,他在其中详细解释了所有内容,并为 2 个进程提供了使用相同信号编号的工作代码。
几件事...
当 child 向 parent 发出信号时,parent 在 sleep
调用中。这会提前终止(例如 EINTR
)。
所以,在第二回合,parent会在之前杀死child[可能] child 已准备好接收信号。
我做了一些主要的黑客攻击来添加调试,waitpid
,等等
主要问题是 [要么] 第二个 child 没有从 parent 得到 SIGUSR1
。或者,child 没有向 parent 发送信号或 parent 被阻塞。从下面的第二个日志文件来看,似乎第二个 child 从未从 parent.
中获取 SIGUSR1
我添加了额外的 signal
调用来重新装备处理程序 [可能 不需要 。我添加了 waitpid
个电话
在 parent 和 child 使用 不同的 信号之前,我无法正常工作。即parent发送SIGUSR1
到child,child发送SIGUSR2
到parent。
这可能不是你想要的,我[还]不明白为什么信号数量差异很重要。
查看 /proc/pid/status
中的信号掩码可能有助于辨别可能发生的情况。
编辑: 让代码完全正常工作。有关详细信息,请参阅下面的更新部分。
这是“错误”日志。 parent 将在 child 可以进行设置之前发送第二个信号:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 0
creating a new child
created child pid is 738524
i'm the new child with pid 738524
while forever
killing child with SIGDN 738524
child got signal 10
child killing parent 738523
parent received signal 10
killing child with SIGINT 738524
waitpid on 738524
creating a new child
created child pid is 738525
killing child with SIGDN 738525
i'm the new child with pid 738525
while forever
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525
请注意,如果我们将 KILLERR
选项添加到构建中,SIGUSR1
从 parent 到 child 的 kill
调用将产生一个 ESRCH
错误(没有这样的过程)。
如果我们有 parent 的 sleep
调用循环并等待 2 秒(例如,它计算剩余的睡眠时间),我们会得到 不同的序列。 parent只会在child有时间设置后发送SIGUSR1
:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 1
creating a new child
created child pid is 739105
i'm the new child with pid 739105
while forever
killing child with SIGDN 739105
child got signal 10
child killing parent 739104
parent received signal 10
killing child with SIGINT 739105
waitpid on 739105
creating a new child
created child pid is 739106
i'm the new child with pid 739106
while forever
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106
这是工作日志:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 12
SIGFIX is 1
KILLERR is 0
QSLEEP is 1
creating a new child
created child pid is 740214
i'm the new child with pid 740214
while forever
killing child with SIGDN 740214
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740214
waitpid on 740214
creating a new child
created child pid is 740215
i'm the new child with pid 740215
while forever
killing child with SIGDN 740215
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740215
waitpid on 740215
creating a new child
created child pid is 740216
i'm the new child with pid 740216
while forever
killing child with SIGDN 740216
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740216
waitpid on 740216
creating a new child
created child pid is 740218
i'm the new child with pid 740218
while forever
killing child with SIGDN 740218
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740218
waitpid on 740218
creating a new child
created child pid is 740219
i'm the new child with pid 740219
while forever
更新:
最初,我听从了您使用 sigaction
的评论,所以我没有尝试。
但是,我添加了 sigaction
作为一个选项(以及 sigprocmask
调用以解锁信号——这可能更重要)。
这 有效 即使信号编号相同。
我已经更新了下面的代码,但是我已经从之前的 post.
中保留了 [上面] 的日志文件
这是源代码。我添加了 common.c
和 Makefile
:
==> child.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include "common.c"
pid_t ppid;
void
signalHandler(int signo)
{
xsignal2(SIGDN, signalHandler);
msg2("child got signal",signo);
if (signo == SIGDN) {
msg2("child killing parent",ppid);
qkill(ppid, SIGUP);
}
}
int
main(int argc, char **argv)
{
ppid = getppid();
xsignal(SIGDN, signalHandler);
msg2("i'm the new child with pid",getpid());
msg("while forever\n");
while (1) {
}
}
==> common.c <==
#include <time.h>
#include <stdlib.h>
#include <errno.h>
typedef long long tsc_t;
#define NSEC 1000000000
#ifndef SIGFIX
#define SIGFIX 0
#endif
#ifndef SIGACT
#define SIGACT 0
#endif
#ifndef KILLERR
#define KILLERR 0
#endif
#if SIGFIX
#define SIGDN SIGUSR1
#define SIGUP SIGUSR2
#else
#define SIGDN SIGUSR1
#define SIGUP SIGUSR1
#endif
#ifndef QSLEEP
#define QSLEEP 0
#endif
void
xsignal(int signo,void (*fnc)(int))
{
#if SIGACT
struct sigaction act;
sigset_t set;
memset(&act,0,sizeof(act));
act.sa_handler = (void *) fnc;
sigaction(signo,&act,NULL);
sigemptyset(&set);
sigaddset(&set,signo);
sigprocmask(SIG_UNBLOCK,&set,NULL);
#else
signal(signo,fnc);
#endif
}
void
xsignal2(int signo,void (*fnc)(int))
{
#if ! SIGACT
xsignal(signo,fnc);
#endif
}
tsc_t
tscget(void)
{
struct timespec ts;
tsc_t tsc;
clock_gettime(CLOCK_MONOTONIC,&ts);
tsc = ts.tv_sec;
tsc *= NSEC;
tsc += ts.tv_nsec;
return tsc;
}
void
msg(const char *str)
{
size_t len = strlen(str);
write(2,str,len);
}
void
num(tsc_t val)
{
char *rhs;
char *lhs;
char buf[100];
lhs = buf;
rhs = buf;
while (val > 0) {
*rhs++ = (val % 10) + '0';
val /= 10;
}
if (rhs <= buf)
*rhs++ = '0';
*rhs-- = 0;
for (; lhs < rhs; ++lhs, --rhs) {
int tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
msg(buf);
}
void
msg2(const char *str,tsc_t val)
{
msg(str);
msg(" ");
num(val);
msg("\n");
}
void
qkill(pid_t pid,int signo)
{
int err;
err = kill(pid,signo);
if (err < 0) {
err = errno;
#if KILLERR
msg2("qkill: failed -- err is",err);
exit(1);
#endif
}
}
void
qsleep(int sec)
{
tsc_t nsec;
tsc_t beg;
tsc_t now;
struct timespec ts;
nsec = sec;
nsec *= NSEC;
while (nsec > 0) {
beg = tscget();
ts.tv_nsec = nsec % NSEC;
ts.tv_sec = nsec / NSEC;
nanosleep(&ts,NULL);
now = tscget();
now -= beg;
nsec -= now;
}
}
==> parent.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <syscall.h>
#include "common.c"
pid_t childPid;
void
createChild()
{
msg("\n");
msg("creating a new child\n");
#if 0
childPid = fork();
#else
childPid = syscall(SYS_fork);
#endif
if (childPid == 0) {
execlp("./child", "child", NULL);
perror("err");
exit(1);
}
msg("created child pid is ");
num(childPid);
msg("\n");
}
void
signalHandler(int signo)
{
msg2("parent received signal",signo);
if (signo == SIGUP) {
xsignal2(SIGUP, signalHandler);
msg2("killing child with SIGINT",childPid);
#if 0
qkill(childPid, SIGTERM);
#else
qkill(childPid, SIGKILL);
#endif
msg2("waitpid on",childPid);
waitpid(childPid,NULL,0);
createChild();
}
}
int
main(int argc, char **argv)
{
msg2("SIGUSR1 is",SIGUSR1);
msg2("SIGUSR2 is",SIGUSR2);
msg2("SIGTERM is",SIGTERM);
msg2("SIGINT is",SIGINT);
msg2("SIGDN is",SIGDN);
msg2("SIGUP is",SIGUP);
msg2("SIGFIX is",SIGFIX);
msg2("SIGACT is",SIGACT);
msg2("KILLERR is",KILLERR);
msg2("QSLEEP is",QSLEEP);
xsignal(SIGUP, signalHandler);
signal(SIGCHLD, SIG_IGN);
createChild(); /* create first child */
while (1) {
#if QSLEEP
qsleep(2);
#else
sleep(2);
#endif
msg2("killing child with SIGDN",childPid);
int ret = kill(childPid, SIGDN);
if (ret == -1) {
perror("exit err ");
}
//msg2("waitpid on",childPid);
//waitpid(childPid,NULL,0);
}
}
==> Makefile <==
PGM += child
PGM += parent
all: $(PGM)
$(PGM):
cc -o $@ $@.c $(CFLAGS) -Wall
clean:
rm -f $(PGM)
我有 2 个 .c 脚本。一个是 father.c:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
pid_t childPid;
void createChild(){
fprintf(stderr,"creating a new child\n");
childPid=fork();
if(childPid==0){
execlp("./child","child",NULL);
perror("err");
}
fprintf(stderr,"created child pid is %d\n",childPid);
}
void signalHandler(int signal){
if(signal==SIGUSR1){
kill(childPid,SIGINT);
createChild();
}
}
int main(int argc,char ** argv){
signal(SIGUSR1,signalHandler);
signal(SIGCHLD,SIG_IGN);
createChild();/*create first child*/
while(1){
sleep(2);
int ret=kill(childPid,SIGUSR1);
if(ret==-1){
perror("exit err ");
}
}
}
另一个是child.c:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void signalHandler(int signal){
if(signal==SIGUSR1){
fprintf(stderr,"child process received signal\n");
kill(getppid(),SIGUSR1);
}
}
int main(int argc,char ** argv){
fprintf(stderr,"i'm the new child with pid %d\n",getpid());
if(signal(SIGUSR1,signalHandler)==SIG_ERR){
fprintf(stderr,"error");
}
while(1){}
}
当 father 启动时,每 2 秒它应该终止 child,分叉自身并启动一个新的 child。 child 通过向他发送 SIGUSR1 信号被杀死,该信号被处理并转发给父亲(使用另一个 SIGUSR1 信号),父亲用 SIGINT 杀死 child。 我面临的问题是第二次创建 child 时,它不再接收 SIGUSR1 信号。 有人可以帮忙吗?
编辑:感谢@CraigEstey(请参阅下面的回答),他发现从 child 向 parent 进程发送不同的信号确实可以完成工作。
按照这个建议,我上面发布的代码应该像这样更改(为了让它工作):在 father.c 中将 if(signal==SIGUSR1)
替换为 if(signal==SIGUSR2)
并将 signal(SIGUSR1,signalHandler);
替换为 signal(SIGUSR2,signalHandler);
。
在 child.c 中将 kill(getppid(),SIGUSR1);
替换为 kill(getppid(),SIGUSR2);
。
如果这不是您想要的,我建议您阅读@CraigEstey 的回答,他在其中详细解释了所有内容,并为 2 个进程提供了使用相同信号编号的工作代码。
几件事...
当 child 向 parent 发出信号时,parent 在 sleep
调用中。这会提前终止(例如 EINTR
)。
所以,在第二回合,parent会在之前杀死child[可能] child 已准备好接收信号。
我做了一些主要的黑客攻击来添加调试,waitpid
,等等
主要问题是 [要么] 第二个 child 没有从 parent 得到 SIGUSR1
。或者,child 没有向 parent 发送信号或 parent 被阻塞。从下面的第二个日志文件来看,似乎第二个 child 从未从 parent.
SIGUSR1
我添加了额外的 signal
调用来重新装备处理程序 [可能 不需要 。我添加了 waitpid
个电话
在 parent 和 child 使用 不同的 信号之前,我无法正常工作。即parent发送SIGUSR1
到child,child发送SIGUSR2
到parent。
这可能不是你想要的,我[还]不明白为什么信号数量差异很重要。
查看 /proc/pid/status
中的信号掩码可能有助于辨别可能发生的情况。
编辑: 让代码完全正常工作。有关详细信息,请参阅下面的更新部分。
这是“错误”日志。 parent 将在 child 可以进行设置之前发送第二个信号:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 0
creating a new child
created child pid is 738524
i'm the new child with pid 738524
while forever
killing child with SIGDN 738524
child got signal 10
child killing parent 738523
parent received signal 10
killing child with SIGINT 738524
waitpid on 738524
creating a new child
created child pid is 738525
killing child with SIGDN 738525
i'm the new child with pid 738525
while forever
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525
killing child with SIGDN 738525
请注意,如果我们将 KILLERR
选项添加到构建中,SIGUSR1
从 parent 到 child 的 kill
调用将产生一个 ESRCH
错误(没有这样的过程)。
如果我们有 parent 的 sleep
调用循环并等待 2 秒(例如,它计算剩余的睡眠时间),我们会得到 不同的序列。 parent只会在child有时间设置后发送SIGUSR1
:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 10
SIGFIX is 0
KILLERR is 0
QSLEEP is 1
creating a new child
created child pid is 739105
i'm the new child with pid 739105
while forever
killing child with SIGDN 739105
child got signal 10
child killing parent 739104
parent received signal 10
killing child with SIGINT 739105
waitpid on 739105
creating a new child
created child pid is 739106
i'm the new child with pid 739106
while forever
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106
killing child with SIGDN 739106
这是工作日志:
SIGUSR1 is 10
SIGUSR2 is 12
SIGTERM is 15
SIGINT is 2
SIGDN is 10
SIGUP is 12
SIGFIX is 1
KILLERR is 0
QSLEEP is 1
creating a new child
created child pid is 740214
i'm the new child with pid 740214
while forever
killing child with SIGDN 740214
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740214
waitpid on 740214
creating a new child
created child pid is 740215
i'm the new child with pid 740215
while forever
killing child with SIGDN 740215
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740215
waitpid on 740215
creating a new child
created child pid is 740216
i'm the new child with pid 740216
while forever
killing child with SIGDN 740216
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740216
waitpid on 740216
creating a new child
created child pid is 740218
i'm the new child with pid 740218
while forever
killing child with SIGDN 740218
child got signal 10
child killing parent 740213
parent received signal 12
killing child with SIGINT 740218
waitpid on 740218
creating a new child
created child pid is 740219
i'm the new child with pid 740219
while forever
更新:
最初,我听从了您使用 sigaction
的评论,所以我没有尝试。
但是,我添加了 sigaction
作为一个选项(以及 sigprocmask
调用以解锁信号——这可能更重要)。
这 有效 即使信号编号相同。
我已经更新了下面的代码,但是我已经从之前的 post.
中保留了 [上面] 的日志文件这是源代码。我添加了 common.c
和 Makefile
:
==> child.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include "common.c"
pid_t ppid;
void
signalHandler(int signo)
{
xsignal2(SIGDN, signalHandler);
msg2("child got signal",signo);
if (signo == SIGDN) {
msg2("child killing parent",ppid);
qkill(ppid, SIGUP);
}
}
int
main(int argc, char **argv)
{
ppid = getppid();
xsignal(SIGDN, signalHandler);
msg2("i'm the new child with pid",getpid());
msg("while forever\n");
while (1) {
}
}
==> common.c <==
#include <time.h>
#include <stdlib.h>
#include <errno.h>
typedef long long tsc_t;
#define NSEC 1000000000
#ifndef SIGFIX
#define SIGFIX 0
#endif
#ifndef SIGACT
#define SIGACT 0
#endif
#ifndef KILLERR
#define KILLERR 0
#endif
#if SIGFIX
#define SIGDN SIGUSR1
#define SIGUP SIGUSR2
#else
#define SIGDN SIGUSR1
#define SIGUP SIGUSR1
#endif
#ifndef QSLEEP
#define QSLEEP 0
#endif
void
xsignal(int signo,void (*fnc)(int))
{
#if SIGACT
struct sigaction act;
sigset_t set;
memset(&act,0,sizeof(act));
act.sa_handler = (void *) fnc;
sigaction(signo,&act,NULL);
sigemptyset(&set);
sigaddset(&set,signo);
sigprocmask(SIG_UNBLOCK,&set,NULL);
#else
signal(signo,fnc);
#endif
}
void
xsignal2(int signo,void (*fnc)(int))
{
#if ! SIGACT
xsignal(signo,fnc);
#endif
}
tsc_t
tscget(void)
{
struct timespec ts;
tsc_t tsc;
clock_gettime(CLOCK_MONOTONIC,&ts);
tsc = ts.tv_sec;
tsc *= NSEC;
tsc += ts.tv_nsec;
return tsc;
}
void
msg(const char *str)
{
size_t len = strlen(str);
write(2,str,len);
}
void
num(tsc_t val)
{
char *rhs;
char *lhs;
char buf[100];
lhs = buf;
rhs = buf;
while (val > 0) {
*rhs++ = (val % 10) + '0';
val /= 10;
}
if (rhs <= buf)
*rhs++ = '0';
*rhs-- = 0;
for (; lhs < rhs; ++lhs, --rhs) {
int tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
msg(buf);
}
void
msg2(const char *str,tsc_t val)
{
msg(str);
msg(" ");
num(val);
msg("\n");
}
void
qkill(pid_t pid,int signo)
{
int err;
err = kill(pid,signo);
if (err < 0) {
err = errno;
#if KILLERR
msg2("qkill: failed -- err is",err);
exit(1);
#endif
}
}
void
qsleep(int sec)
{
tsc_t nsec;
tsc_t beg;
tsc_t now;
struct timespec ts;
nsec = sec;
nsec *= NSEC;
while (nsec > 0) {
beg = tscget();
ts.tv_nsec = nsec % NSEC;
ts.tv_sec = nsec / NSEC;
nanosleep(&ts,NULL);
now = tscget();
now -= beg;
nsec -= now;
}
}
==> parent.c <==
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <syscall.h>
#include "common.c"
pid_t childPid;
void
createChild()
{
msg("\n");
msg("creating a new child\n");
#if 0
childPid = fork();
#else
childPid = syscall(SYS_fork);
#endif
if (childPid == 0) {
execlp("./child", "child", NULL);
perror("err");
exit(1);
}
msg("created child pid is ");
num(childPid);
msg("\n");
}
void
signalHandler(int signo)
{
msg2("parent received signal",signo);
if (signo == SIGUP) {
xsignal2(SIGUP, signalHandler);
msg2("killing child with SIGINT",childPid);
#if 0
qkill(childPid, SIGTERM);
#else
qkill(childPid, SIGKILL);
#endif
msg2("waitpid on",childPid);
waitpid(childPid,NULL,0);
createChild();
}
}
int
main(int argc, char **argv)
{
msg2("SIGUSR1 is",SIGUSR1);
msg2("SIGUSR2 is",SIGUSR2);
msg2("SIGTERM is",SIGTERM);
msg2("SIGINT is",SIGINT);
msg2("SIGDN is",SIGDN);
msg2("SIGUP is",SIGUP);
msg2("SIGFIX is",SIGFIX);
msg2("SIGACT is",SIGACT);
msg2("KILLERR is",KILLERR);
msg2("QSLEEP is",QSLEEP);
xsignal(SIGUP, signalHandler);
signal(SIGCHLD, SIG_IGN);
createChild(); /* create first child */
while (1) {
#if QSLEEP
qsleep(2);
#else
sleep(2);
#endif
msg2("killing child with SIGDN",childPid);
int ret = kill(childPid, SIGDN);
if (ret == -1) {
perror("exit err ");
}
//msg2("waitpid on",childPid);
//waitpid(childPid,NULL,0);
}
}
==> Makefile <==
PGM += child
PGM += parent
all: $(PGM)
$(PGM):
cc -o $@ $@.c $(CFLAGS) -Wall
clean:
rm -f $(PGM)