由uwsgi联想到的shell信号

最近有个功能,是通过uwsgi+python os调用nohup放在后台实现的功能,但是发现重启uwsgi之后放在后台的进程同样会退出,于是联想到了之前遇到的一个类似的问题:就是shell调用nohup启动了一个server,之后ctrl+c杀死进程的话,会导致已经放在后台的进程退出,但是使用kill 杀死shell脚本不会出现这个问题,这个问题当时折腾了好久,最终查到了资料,放在最后,大意就是说摁下ctrl +c之后是发送了sinint信号给当前的进程组,而不是说仅仅是发送给当前进程。说到进程组,印象中进程组的id是shell运行进程之后创建的,id等于第一个进程的pid,之后由该进程启动的多有的进程都属于这个进程组的,可以使用如下命令查看进程组:

ps axo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm,args,

联系到今天uwsgi的情况就是uwsgi创建了进程组,之后虽然启动了子进程并且放在了后台,子进程的父进程id也变成了1,但是仍然是属于该进程组,所以会出现子进程退出的情况:)



First, read the Wikipedia article on the POSIX terminal interface all of the way through.

The SIGINT signal is generated by the terminal line discipline, and broadcast to all processes in the terminal’s foreground process group. Your shell has already created a new process group for the command (or command pipeline) that you ran, and told the terminal that that process group is its (the terminal’s) foreground process group. Every concurrent command pipeline has its own process group, and the foreground command pipeline is the one with the process group that the shell has programmed into the terminal as the terminal’s foreground process group. Switching “jobs” between foreground and background is (some details aside) a matter of the shell telling the terminal which process group is now the foreground one.

The shell process itself is in yet another process group all of its own and so doesn’t receive the signal when one of those process groups is in the foreground. It’s that simple.

——————————————–


Signals by default are handled by the kernel. Old Unix systems has default 15 signals, now they have more. You can check </usr/include/signal.h> (or kill -l). CTRL+C is the signal with name SIGINT.

The default action for handling each signal is defined in the kernel too, and usually it is terminate the proces who is received the signal.

All signals (but SIGKILL) can be handled by program.

And this is what the shell do:

When the shell running in interactive mode, he has a special signal handling for this mode. When you run a program, for example find, the shell:

the shell fork itself and for the child set the default signal handling
replace the child with the given command (e.g. with find) when you press CTRL+C, parent shell handle this signal but the child will receive it - with the default action - terminate. (the child can implement signal handling too)
You can trap signals in your shell script too…

And you can set signal handling for your interactive shell too, try enter this at the top ot you ~/.profile. (Ensure than you’re a already logged in and test it with another terminal - you can lock out yourself)

trap ‘echo “Dont do this”‘ 2

Now, everytime when you press CTRL+C in your shell, will print a message. Don’t forget remove the line!

If interested, you can check the plain old /bin/sh signal handling in the source code here.

At the above there were some misinformations in the comments (now deleted), so if someone interested here is a very nice link - how the signal handling works.