在树莓派(最近的树莓派)上,我编写了一个应用程序,它通过网络请求按需生成一个应用程序,并通过不同的网络请求按需杀死它。生成机制只是 fork/exec。使用 kill(childPid, SIGQUIT) 完成杀戮。正如您所想的那样,它就像一块简单的 C++,并且运行良好。
也就是说,它工作正常,除非我从 /etc/rc.local 启动它。从那里启动它的命令只是一个适当的 cd 然后
./effectPlayer &
它启动正常,接收请求正常,生成正常(它跨越一个 aplay,因此判断它何时工作是微不足道的)但完全无法根据请求杀死 aplay 子进程。它正常调用 kill() 并且 kill() 返回 0。但是 aplay 继续播放。
我认为这与从 /etc/rc.local 生成它在 fork 或 kill 中赋予它一些特殊行为这一事实有关,但我不明白是什么。我错过了什么?
编辑:添加问题的答案。从 /etc/rc.local 运行并打开日志记录,应用程序报告:
23:10:06 10-11-2019 (effectPlayer) 7: P1 64 elvenHall #command to start playing
23:10:06 10-11-2019 (sound) launched 1083: /usr/bin/aplay -q -... #what it forks/execs
23:10:10 10-11-2019 (effectPlayer) 7: X1000 #command to stop playing
23:10:10 10-11-2019 (sound) sending 3 to 1083, result 0 0 #what kill() is asked to do
翻译,它被要求播放一个特定的效果并产生一个 aplay 来处理它。它可以工作(我听到音频),然后我发送一个命令停止所有播放。它使用正确的信号成功地在正确的 PID 上调用 kill(),并且 kill() 返回 0 且 errno=0。除了 aplay 仍在运行。
当我从命令行执行相同的序列时,它的作用都是一样的,除了 aplay 实际上死了。
当我将 SIGQUIT 换成 SIGKILL 时,它按预期工作:无论 effectsPlayer 如何启动,aplay 都会死掉。
我现在要把它归结为游戏中的一些奇怪之处。我不喜欢使用 SIGKILL - 可能会跳过重要的清理工作。但它的工作...
可能是您从引导脚本继承了对 SIGQUIT 的忽略,因为 fork 和 exec 不理会这些。在你的父程序中将 SIGQUIT 重置为默认状态来试试这个。
由于在 rc.local 下运行不太可能导致这种情况。
首先,检查父进程是否真的在发送信号(您可能需要一些调试行)并且子进程没有被杀死(运行 pgrep aplay,让父进程杀死,然后再次执行 pgrep aplay)。我还将假设您在这里没有任何 SELINUX 或其他 MAC 异常。
没有响应 kill() 的进程归结为几件事:权限、处理和 PID。听起来您有一个父进程“effectPlayer”,它会产生一个子进程“aplay”,并且 effectPlayer 正在向子进程发送信号 QUIT。
假设您没有对 setuid 和朋友做任何奇怪的事情,父母和孩子都将拥有相同的所有者,所以这没关系。
可以屏蔽退出信号,但我很确定 aplay 不会那样做。所以这是一种可能。您可以将 SIGQUIT 更改为 SIGKILL 以查看它是否会改变。
最后是PID。你确定它是正确的pid吗?再次,一些调试行说明您尝试杀死的 PID 并将其与 ps 命令匹配将对此进行测试。有时您可能会在 shell 中使用 exec 并且您正在杀死错误的进程。