我是一个进程,一出生就被塞了一张长长的任务单,上面是密密麻麻的任务指令,像什么 mv 了, cp 了, while 了..... 我一个都看不懂。
人类程序员告诉我这叫 shell 脚本,我的任务就是跑跑腿,到 shell 大街上找到能够执行这些指令的人,让他们去执行。
这个活儿听起来并不复杂,我按照人类的指示,进入了 shell 大街。
初试身手
shell 大街上热闹非凡,各种进程来来往往,两旁的街道是大大小小、形形色色的门店,我左看右看,眼睛都不够使了。
比如我旁边这家店,招牌巨大,上面写着 【我们不生产文件,我们只是文件系统的搬运工】,这是 “mv” 旗舰店。还有街口这家店,招牌也气势非凡:【你负责从 0 到 1,我搞定 1 到 100】,原来这家店专门负责抄录备份文件,叫做 cp ,也是旗舰店。
我从怀里掏出任务单,看看我要干的活, 我希望指令是 mv 或者 cp,这样我就可以去逛逛旁边这两家旗舰店了。
可是,第一条指令是 “pidof xyz”, 我环顾四周,怎么在 shell 大街上看不到 pidof 店铺?
这时候街上的大喇叭响了:进程管理局将于 4:30 下班,需要查询进程id的速速前往 shell 大街 0x37859 号。
下班真够早的,我一溜小跑,来到 0x37859 号,在办事窗口小姐姐的帮助下查到了 “xyz” 的进程id:8681, 按照要求,我把它记录在了变量 $process_id 中。
杀手组织
这个工作看起来很简单嘛, 我马上查看第二条指令,真是不看不知道,一看吓一跳,这条指令是:
- kill $process_id
我揉揉眼睛再确认一下,没错,就是 kill , 那个 $process_id 不就是我刚刚查出来的吗?8681!没想到查询这个 pid 的值居然是为了干掉这个进程, 也不知道他做错了什么。
我还没办过这种差呢,kill,看这个名字这是个杀手组织吧,肯定都是杀进程不眨眼的那种,太可怕了!
这个叫 kill 的店可真不好找,多亏 cp 旗舰店的小二给我指了一条路,我才来到这个店铺门口, 我以为这里肯定是严密把守,门口会有彪形大汉站岗,没想到只是一个平平常常的小店!门口挂着两个随风飘扬的大灯笼,上面写着:“送” “信”。
这就是 kill 门店?杀手组织的驻地就这样?怀着忐忑的心情,我走进店中。
出乎我的意料, 小二非常热情,他马上满脸堆笑地迎上来:“客官您要办点什么业务呢,咱们这儿的信件是最全的,应有尽有,任君挑选”。
看到墙上还贴着 "微笑服务” 四个字,我差点怀疑走错片场了,我把他拉到一边,压低声音说:"我不是来送信的,我这次来是要杀一个进程,你们能办吗?"
我一边说,一边做了一个杀头的手势。
小二看了看我的任务单,说道:“客官是第一次来吧,你要办的这个是常规业务,我们最拿手了。不过你说的这个杀进程我们保证不了,小店只提供送信服务, 这封信送出去,进程能不能杀得掉就不归我们管了。”
“你们不是负责杀人吗?怎么和送信这种没技术含量的业务扯到一起了?”
小二笑道:“这是外界对我们的误解了,我们不是一个杀手组织, 我们的业务很单纯,只负责送信给进程。而且这封信还得通过内核老大转交呢!比如你这次要 kill 8681, 我们就会发送一封叫做 SIGTERM 的信,意思是终止进程。”
小二边给我解释,边掏出系统调用专用手机发送了一个 "15 8681",这下我知道了, SIGTERM 对应的信号值就是 15,小二通过系统调用发给了内核。
“杀人” 的活儿就这么办完了,我付了 3 块的 CPU 币, 满怀疑虑地离开了这个“送信”的店铺。
死循环
下一个指令竟然是个 while 循环,它让我隔一会儿就去进程管理局查询一下,直到 $process_id (也就是 8681 )不存在了才能执行后续的任务。 我心里很清楚,这是要保证那个8681的进程被杀死。
我一趟趟地往进程管理局跑,累死个人了,可是这个进程管理局的小姐姐每次都告诉我,这个 8681 号进程活得好好的,正在shell大街的某个角落呼呼大睡呢!
肯定是“送信”的那个店小二把我骗了 !趁着 while 循环的间隙,我怒气冲冲地回到了“送信”店铺,质问小二为什么收了我的钱不干活!
店小二脾气挺好:“我们送信,绝对不会出错的,但是,我们不能保证进程被杀死。”
我说到:“那你给我退钱,我去找别的杀手。”
小二哈哈笑道:“客官有所不知,你到哪里都是一样,对于 SIGTERM 信号,一般内核老大确实会干掉对应进程,但如果进程提前打过招呼,留下了一个自己的 SIGTERM 处理函数,那么按照约定老大就只会调用下这个函数。函数里面进程也许会做一些扫尾工作再退出,也许压根就不退出,继续逍遥快活。甚至进程还可以直接屏蔽掉这个信号呢。我猜 8681 号进程就是如此,赖着不退出。”
我满脸愁色:“那这样不相当于从生死簿上勾去姓名,长生不老了吗?!不管怎么样,你得把它给杀掉!"
小二闻言露出了老江湖的笑容:“客官听说过江湖传言吗?kill 一笑,生死难料,杠九一(安)排 ,世间白来。”
我若有所悟,连忙问道: "杠九是什么意思,是 9 号信件吗?"
小二闻言露出赞许的目光:“看来你还是挺机灵的,一点就通。9 号信件那就是大名鼎鼎的 SIGKILL 了。虽然大多数信件都允许进程注册自定义信件处理函数,但有几个特别的信件,例 SIGKILL 和 SIGSEGV 是不允许注册处理函数的,一旦内核老大收到 我们送的 SIGKILL 信号,那就相当于杀无赦,斩立决,手起刀落毫不迟疑的。一般用 kill 杀不掉的进程,用上 kill -9 就可以干掉了。”
原来如此 !可是虽然知道了 SIGKILL ,但悲惨的是我只能按照任务单来执行任务,不能擅自更改为 kill -9 $process_id
天哪!难道我真的就被困在这里了吗?!
定身法
生活不易,进程叹气,我无精打采地准备出门,继续去查询进程,估计进程管理局的小姐姐都很烦我了,每次都问同一个问题。
就在我准备迈出 kill 小店时,怪事发生了,我动不了了!就像是中了定身术一样。
小二跑上前来看了看说 :“哈哈, 看来你被挂起了!”
我焦急地问:“说清楚点,什么是挂起呀?”
小二从柜台拿出了一张信件清单给我看:“喏,看到这个 SIGTSTP 没,它会让进程挂起,我们店也有这项业务的。估计是人类程序员发现你迟迟没有执行下一个任务,开始调试了。只要他们按下 Ctrl+Z,就会发出 SIGTSTP ,内核老大就把你挂起了。你小子还挺幸运的,只是被挂起,上次有个进程办事出了点小差错,直接就被人类按下了 Ctrl+C,用 SIGINT 给干掉了。慢慢等着吧,人类慢得很呐!”
在 kill 小店真是学了不少东西,真希望人类程序员也能快点学会这些知识,解救我于水火之中。
不过我显然高估了人类,足足过了十几秒,我才看到另一个进程来到了 kill 小店中,他手中的任务单赫然写着 "kill -9 8681", 谢天谢地,人类找到解决方法了。
又过了漫长的好几秒,我才感到身体一轻,又可以活动了。
舒展下筋骨,我连忙跑到进程管理局去查询,这次查询结果是 "查无此pid",哈哈,我终于可以摆脱这个循环,继续我任务单的下一条了。
尾声
离开之前,进程管理局的小姐姐还告诉了我一个小道消息,原来这个害我不浅的 8681 进程并不是故意忽略 SIGTERM 的,他注册了一个信号处理函数,打算打印一句 log 再退出,但在执行的时候竟然死锁了,据说原因是打印函数不属于异步信号安全的函数,不能在信号处理时调用。
我管不了那么多了,赶紧去执行下一个任务,要不然又要被挂起了......