在POSIX系统上,我如何可靠地跟踪子进程/孙子进程?

3
我有一个(至少对我来说)有趣的问题:在某些情况下,我无法可靠地和可移植地获取子进程的信息。我正在尝试让一个名为AllTray的应用程序在某些奇怪的情况下正常工作,其中它的子进程会生成一个子进程,然后退出。 AllTray 的任务基本上是将应用程序停靠到任务托盘中,这通常是指定为 AllTray 要调用的命令行(即,alltray xterm 会启动 xterm,并在 AllTray 中管理它)。
大多数GUI软件在AllTray下运行得很好。它在其窗口上设置_NET_WM_PID属性(或小部件库这样做),一切都很好,因为_NET_WM_PID == fork()的子进程。然而,在某些情况下(例如在运行oowriter时,或者在为KDE编写的软件(如K3b)下运行时),AllTray运行的子进程是一个包装器,无论是shell脚本(如OO.o的情况)还是一个奇怪的程序,它fork()和exec()自身并有效地将自己后台化,因为父进程很早就死了。
我想到不收割我的子进程,以便在进程表中保留我的孙子的父进程ID,以便我可以通过从底部到顶部遍历家族树将它们链接回到我身上。然而,这并不起作用:一旦我的子进程死亡并变成僵尸,系统就认为我的孙子进程是一个孤儿,并且init会接管它。这似乎至少在Linux 2.6和NetBSD上是这种情况;我会认为这可能是常态,而POSIX似乎没有指定这种情况,所以我希望相反。
由于这种方法行不通,我考虑使用LD_PRELOAD拦截子进程对fork()的调用,并将信息传递回父进程。然而,我担心这不如理想的解决方案具有可移植性,因为不同系统对动态链接器执行LD_PRELOAD等操作的规则不同。对于Linux系统上没有设置helper库的setuid/setgid GUI应用程序也无法工作。总的来说,这对我来说是一个糟糕的想法,感觉很hackish。

因此,我希望有人能提出如何解决这个问题的想法,或者如果依赖像LD_PRELOAD这样的机制是我唯一的选择,除了打补丁内核(这是不会发生的),还有什么其他的选择吗?

1个回答

1

您可以调查使用进程组来跟踪进程组的可能性。进程组是一个属性(只是一个数字),您可以在分叉之前设置它,然后子进程会自动继承它。

AllTray可以为每个使用它启动的应用程序创建一个新的进程组。您可以向进程组的所有成员发送信号。我想这里最有用的信号应该是TERM和KILL,以便杀死在AllTray中管理的应用程序。

我不确定是否有方便的方法来确定进程组的所有成员是否已经退出。您可能需要通过整个进程列表并为每个进程调用getpgid来查看是否还有任何进程留在进程组中。

请注意,进程组对于创建自己的新进程组的应用程序无效。但这相对较少见,您可能不需要担心这样的应用程序。


嗯,我会研究一下这个问题,看看会发生什么。虽然这个想法听起来不错。但是,创建一个新的单一进程组不足以满足需求吗?目前AllTray只管理一个应用程序,但它最终将管理更多应用程序。如果一个单一的pgid可以找到应该被监控的进程,那就足够了,我认为。 - Michael Trausch
我可以想象如果包装器通过kdeinit启动KDE <=3或>4.3,或者Firefox已经有其他窗口打开等情况下,会导致操作失败......在这些情况下,新窗口是由完全不同的树中的进程创建的。 - ephemient
@ephemient 我知道KDE应用程序会做一些奇怪的事情,而它们正是我正在尝试解决的案例之一。但是,当已经有一个进程在运行时,我对于FF或gnome-terminal能做的事情并不多,尽管我有一些想法来尝试让它做用户想要的事情,我认为这是可能的。 - Michael Trausch
谢谢Ville,这正是我需要做的。而且KDE应用程序比我想象的还要奇怪...但现在我已经让它们(和OOo)工作了。非常感谢! - Michael Trausch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接