电子说
引言
上星期新加一好友,在好友的朋友圈动态里看到一张聊天截图,是署名为“阅码场”的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” 可查阅到所有信号。
写个测试程序
写另外一个测试程序child.c,仅打印进程的PID号,以及调试主进程是否能成功传递参数给子进程。
文稿贴的两张图是测试的方法,主进程传递给子进程3个参数“aa bb cc”,刚启动后子进程被信号暂停(T),左侧输入回车后子进程得以运行(S)。
使用新轮子
恩,轮子造好了,看看它的效果怎么样,用它协助ftrace抓取echo的执行。
思考
现在左边窗口输入./master.elf echo abcdefg,切换到右侧窗口输入脚本ftrace-pid.sh,这个脚本将抓取1秒的数据,再切换到左侧窗口按Enter键。打开trace文件/tmp/a.txt,怎么样了,echo命令的执行信息被抓取下来了。
实验里用到的ftrace-pid.sh脚本我把他的源码贴在下面。
思考
我在使用kill发送信号时有个疑问,既然应用程序收到SIGSTOP信号后就处于停止状态,既然停止了,为什么还能处理之后的SIGCONT信号呢?之前是进程可运行,才能被调度、能处理信号,很好理解。之后进程都停止了,又怎么能处理SIGCONT信号恢复执行呢?你能够用鼠标点击左下角“开始”菜单关闭计算机,却无法继续用鼠标使其开机。所以我猜测信号处理首先是由于调度器处理的。
第二个扩展问题,gdb调试应用程序是可以暂停应用程序执行的,它使用的是ptrace。你能否写一个应用程序,它利用ptrace原理去暂停子进程执行。我说的暂停位置可不是main,甚至在main之前。应用程序启动时 “第一个系统调用是什么?” 尝试找到它,并截获。
原文标题:仅40行代码,Linux如何以暂停状态启动新进程,当然是发送信号呀
文章出处:【微信公众号:一口Linux】欢迎添加关注!文章转载请注明出处。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !