vlambda博客
学习文章列表

仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀


引言

“请教一个Bash的问题:有没有什么办法让一个新开的进程,一开始就处于暂停状态,直到我输入fg?”

巧了,上星期我在尝试使用ftrace根据进程号(PID)过滤、跟踪内核执行过程时,迫切需要一个 进程启动后处于暂停状态 ,与这位群友一样,也是满世界寻找Bash是否有内置类似该功能,为什么我需要它呢?

倘若一个应用程序是死循环,或者执行时间相对较旧,哪怕只执行1秒,我Left Golden Finger完全可以输入 “Ctrl+Z” 暂停它,借助pidof获取进程的PID号,将其填入set_ftrace_pid仅过滤该进程信息,输入 “fg” 恢复进程执行。

再看另一个应用场景,若某个进程执行耗时很短呢?例如“echo”命令转瞬即逝,完全没有反应的机会。

再举例,倘若我就想抓取从应用程序开始执行到“Ctrl+Z”之间几百毫秒的内核执行过程,我又该怎么?

“拿到源码重新编译,在main函数开始时添加足够的延时。”头上长尖角的小人说。

“耍流氓!无耻!偷换概念!”头上另一个长翅膀小人指责。

好吧,别辩论了,回归正题。

既然群友都和我一样没能找到Bash内置实现,再怎么说“阅码场”聊天群也是人类高质量码农的聚集地,我相信他也不是伸手党。那么是时候造车子了,写几行代码实现这个功能,没骗你,真几行,发个信号而已。

怎么做

先贴代码再解释。



首先要了解系统快捷键Ctrl+Z以及命令fg本质是做了什么,Ctrl+Z是向前端应用发送 SIGSTOP信号 ,fg恢复最近一个被暂停的应用发送 SIGCONT信号 ,并放到前台来执行。

SIGSTOP对应信号19、SIGCONT对应信号18,正如代码23行和31行所做的那样。你不相信,那就用API signal()去截获这两个信号的处理函数。

既然是信号触发,那就能用kill命令去替代Ctrl+Z和fg动作:

  • kill -19

  • kill -18

命令输入 “kill -l” 可查阅到所有信号。

仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀

写个测试程序

写另外一个测试程序child.c,仅打印进程的PID号,以及调试主进程是否能成功传递参数给子进程。

仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀

文稿贴的两张图是测试的方法,主进程传递给子进程3个参数“aa bb cc”,刚启动后子进程被信号暂停(T),左侧输入回车后子进程得以运行(S)。

仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀


仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀

使用新轮子

恩,轮子造好了,看看它的效果怎么样,用它协助ftrace抓取echo的执行。

思考

现在左边窗口输入./master.elf echo abcdefg,切换到右侧窗口输入脚本ftrace-pid.sh,这个脚本将抓取1秒的数据,再切换到左侧窗口按Enter键。打开trace文件/tmp/a.txt,怎么样了,echo命令的执行信息被抓取下来了。


仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀

实验里用到的ftrace-pid.sh脚本我把他的源码贴在下面。


思考

我在使用kill发送信号时有个疑问,既然应用程序收到SIGSTOP信号后就处于停止状态,既然停止了,为什么还能处理之后的SIGCONT信号呢?之前是进程可运行,才能被调度、能处理信号,很好理解。之后进程都停止了,又怎么能处理SIGCONT信号恢复执行呢?你能够用鼠标点击左下角“开始”菜单关闭计算机,却无法继续用鼠标使其开机。所以我猜测信号处理首先是由于调度器处理的。

第二个扩展问题,gdb调试应用程序是可以暂停应用程序执行的,它使用的是ptrace。你能否写一个应用程序,它利用ptrace原理去暂停子进程执行。我说的暂停位置可不是main,甚至在main之前。应用程序启动时 “第一个系统调用是什么?” 尝试找到它,并截获。

end



一口Linux 


关注,回复【1024】海量Linux资料赠送

精彩文章合集

文章推荐

【专辑】
【专辑】
【专辑】
专辑 入门
专辑
专辑
【干货】
【干货】


点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看