dram.me

Daemon程序中的pidfile

pidfile一般用于daemon程序,主要作用是保证在系统中只存在该daemon的一个进程,同时也便于系统统一管理这些daemon程序。

那么程序在实现pidfile功能时具体需要做哪些处理呢?可以从这个纯Python实现中入手。 一般的daemon程序,不管最终接口是直接用C实现还是用SHELL包装,都需要提供start,stop及restart功能。

start过程需要处理的问题:

- 1.1 确保系统中没有该daemon的进程。如果有,则不能启动程序。 - 1.2 在daemon化之后,创建pidfile,写入pid。 - 1.3 注册atexit(),确保在程序退出时清除pidfile文件。

stop过程做的处理:

- 2.1 如果pidfile不存在,无需其它动作。 - 2.2 如果pidfile存在,kill原有进程,并确认进程不存在。在旧进程异常退出时,比如直接用_exit(2)退出程序时,可能pidfile不会被删除,所以在kill进程之后还要确认pidfile文件已被删除。

restart动作:

- 3.1 stop - 3.2 start

下面再来看一下NetBSD,FreeBSD以及Debian对于pidfile的不同处理方式。

在NetBSD中,pidfile的创建工作是由daemon程序通过pidfile(3)库函数完成,而其它动作则是通过在/etc/rc.subr中的run_rc_command中执行。pidfile(3)函数主要完成1.2及1.3的动作。NetBSD相关代码可以在这里找到。

FreeBSD与NetBSD相似,也是主要通过run_rc_command实现对daemon程序的管理。只是1.1功能FreeBSD通过pidfile_open()实现,内部使用了flopen(3),相当于用flock(2)实现进程间的互斥。而1.2在FreeBSD中则是以pidfile_write()实现。另外,对于pidfile的清理工作,FreeBSD提供了pidfile_remove(),由于FreeBSD是通过flock机制实现互斥,而不是单纯通过文件是否存在判断,所以不需要严格地考虑删除问题,也就不需要用到atexit()了。FreeBSD的代码可以看这里

而在Debian中是通过start-stop-daemon程序实现对pidfile的处理。start-stop-daemon中的pidfile是可选的,如果不建pidfile的话,它会类似于killall用文本匹配的方式查找进程。start-stop-daemon中的pidfile可以是由程序创建,也可以由start-stop-daemon建立。具体关于start-stop-daemon的说明可以看这里。如是对具体实现感兴趣,可以在dbpkg源码包中找到。