关于FD_CLOEXEC的一个故事 http://leave001.blog.163.com/blog/static/162691293201251810343121/

来源:互联网 发布:windows 10 iso bt 编辑:程序博客网 时间:2024/04/28 13:26

关于FD_CLOEXEC的一个故事  

2012-06-18 10:34:03|  分类: linux |  标签:fd_cloexec  |举报|字号 订阅

下载LOFTER客户端
周末翻开《UNIX环境高级编程》,读到有关FD_CLOEXEC的章节时,想到以前碰到一个案例。我只记得跟FD_CLOEXEC有关系,但忘了问题的症状和细节。年代久远啊,都过去3、4年了,当时熟悉的代码和构架都忘了。

今天再仔细回忆了一下,终于想出了一些细节。我决定把它记下了,免得以后忘了。

当时那个系统有一个logic进程,用来管理各子模块的的进程。在这些子模块中,有一个语音模块voice。logic通过fork和exec来运行子进程voice。我们碰到了一个问题:语音模块运行一阵子(经过一系列的摘机、通话、挂机)后,logic会挂住。

在cm_logic中加打印跟踪,发现在对一个fd的read处阻塞住了。仔细查看这一部分代码,没有发现任何问题,有问题的只可能是voice进程。但我们当时这样认为,voice即便有问题,也不应该影响到父进程cm_logic啊。

这个问题经过了很长时间都没有解决,直到我们在voice中解决了另一个bug。建立每次通话时,voice会创建一路socket连接收rtp,然后用这个fd来索引一个连接控制块。通话结束时,需要关闭这个fd。我们发现这些fd该关闭的没有关闭,一直增加,很快就超过了一个预设的控制块数组范围,导致资源用尽,建立通话失败。这个问题比较好查,最终发现是close时传入的fd有问题。我们使用fd来索引控制块,应该传入的是该索引。但该控制块中恰巧有一个fd变量,一个兄弟误将这个作为close参数了。

在解决这个问题后,cm_logic挂死也消失了。后来分析的原因是这样:cm_logic在fork和exec执行voice时,没有指定event fd的FD_CLOEXEC属性,从而该fd在子进程voice中仍然有效。voice中关闭那个错误fd时,由于这是一个野值,在某次通话后碰巧关闭了event fd,这样就操作了event fd对应的v-node节点。v-node是系统共用,不是进程独有的,因此导致父进程cm_logic对它的读写出现异常。

这里附上APUE中对fd、open file table和v-node的讲解:
关于FD_CLOEXEC的一个故事 - leave - leave
 

总结起来,在解决voice中那个问题前,其实可以在运行voice前通过设置event fd的FD_CLOEXEC属性(fcntl(fd, SET_FD, FD_CLOEXEC))来解决这个问题。但根源是在voice中,因此后来就没动logic代码。之前一直认为子进程不会影响父进程的想法是错误的。
0 0
原创粉丝点击