LWN: pidfd的API全齐了

640点击上方蓝色字关注我们~



Completing the pidfd API

By Jonathan Corbet
July 26, 2019


关联文章:LWN:给进程发signal的时候PID已经被别的进程占用了,怎么办?!


过去几版kernel里面,通过合入pidfd的几个patch,已经让kernel能够意识到pidfd这个概念了:一个代表着某个进程的文件描述符(file descriptor)。这个方案起初只是为了能够在给进程发送signal的时候能避免pid循环利用导致的可能发错进程的风险,现在已经逐步变成了一个更加完善的进程管理接口了。目前最后一步即将完成:利用pidfd来wait进程。当然,这个API也需要先经过几版patch set的迭代。


A pidfd recap

Unix类型的系统,一直喜欢把很多对象都用文件来表示,不过进程是个例外。进程都是由process ID(PID)来表示的,也就是都是一些小整数(缺省最大是32767,Linux系统里这个值可以改大)。这种表示方式带来一些问题,其中最大问题是PID会被重复回收利用。当某个进程退出的时候,它的PID不久之后就会被一个跟原进程无关的新建进程所重复利用。这里说的“不久”,在系统繁忙的情况下可能时间非常短。这其实就会出现一种race codition问题:有代码需要对某个进程进行一些操作的话,通常是给它发个signal,那么这里搞不好就会发给一个错误进程了。


pidfd则不用,它是用文件描述符fd来代表一个存在的进程。一个pidfd的生命周期里,只会代表特定的一个进程,这样用它来做发signal的对象时就不需要担心错误发给另一个进程了。这个功能非常有价值,现在已经有一些进程管理系统,例如Android里面在用的(译者注:应该是指activitymanager?),正在进行重写来希望尽快利用pidfd。


还有其他两种方式来创建pidfd。绝大多数场景下可以直接在调用clone()接口(或者不久之后的clone3() )使用CLONE_E_PIDFD flag。当进程创建成功之后,代表子进程的pidfd就会return给父进程。此外也可以利用pidfd_open()来获取一个已经存在的进程的pidfd,在5.3 kernel里面将会包含这个功能。


当某进程获取到目标进程的pidfd之后,可以使用pidfd_send_signal()来给目标进程发送信号:

 
 


Kernel 5.3里面也新增了一个功能,可以把某个pidfd传递给poll(),这样就能在此pidfd代表的进程退出时收到通知消息。


Waiting on a pidfd


虽然现在已经可以用poll()来在目标进程退出的时候获得通知,不过这对于进程管理系统来说还是不够的,还需要能指定等待这些目标进程退出并且在退出之后获取相应的exit信息。这就需要修改一下wait()系统调用了。Christian Brauner提议了一个新的系统调用:


此系统调用会等待pidfd指定进程,states参数用来指定关注哪些状态变化(例如要等进程收到stop signal,就用WSTOPPED)。flags指定了额外的参数,包括WNOHANG用来表明采用非阻塞操作。patch set的描述里面提供了完整的参数列表。


Brauner介绍道:“如果希望完全使用pidfd来管理进程的话,这个系统调用是目前所缺失的最后几片拼图之一”。不过这个方案看起来暂时还是没法获得承认。Linus Torvalds明确表示他不赞同这个做法。他对这个实现目标并不反对,但是他觉得不需要增加一个新的系统调用,建议直接扩展waitid()系统调用来增加一个新的flag就好。


因此Brauner采纳了意见,提供了新版的patch。waitid()增加了一个新的P_PIDFD的ID类型值,可以让提供的ID被作为pidfd来使用。这个方法缺失不需要增加新的系统调用了,并且改动也更少。目前还没有review意见反馈出来,很可能会合入5.4 kernel。


这个改动,除了能实现原有的目标(无歧义地指定等待哪个进程),还带了一个有意思的新功能:wait for a process的操作可以对不是子进程的进程来使用了。此前的waitid()没有这个功能。因为pidfd是一个文件描述符,可以通过SCM_RIGHTS等常用方式来传递给另一个进程,这样收到pidfd的进程(当然是在此patch set合入之后)就能够按照父进程能做的那些操作来对这个目标进程进行各种操作了,也包括wait操作。


在原有的pidfd_wait()方案里面还有一个很有趣的地方:新加的clone() flag CLONE_WAIT_PID可以让新创建的进程对大多数wait()调用都不可见。只有某种特殊的wait()操作才能获取到这个目标进程的exit信息。有些场景下面会想利用这个功能,例如某个函数库(library)如果想创建一个helper进程并且不希望调用此函数的进程在wait()操作的时候看到help进程,就可以利用这个功能实现了。在第二版的waitto()实现里面没有这个功能了,不过今后应该会有一个新的独立patch来实现此功能。


今后,肯定会出现其他一些基于pidfd的改进方案。目前pidfd功能还刚出现,需要不断思考来完善更多使用场景。不过现在加上的wait功能,应该已经算是完成了pidfd开发的第一轮工作了。这个改动本身正义不大,不过今后迁移到pidfd将会是Linux系统上进程管理的一个重大改动。


全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 
热烈欢迎转载以及基于现有协议上的修改再创作~


长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~


640?wx_fmt=jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值