第13章 守护进程
父进程ID为0的进程通常是内核进程,作为系统引导装入过程的一部分而启动。
init是个例外,它是一个由内核在引导装入时启动的用户层次的命令。
内核进程通常存在于系统的整个生命期内,以超级用户特权运行,无控制终端,无命令行。
Linux使用kthreadd创建其他内核进程,所以它表现为其他内核进程的父进程。而用户层守护进程的父进程是init
编程规则
- 调用umask将文件模式创建屏蔽字设置为一个已知值而不是继承值。
- 调用fork再使父进程exit,这保证了子进程不是一个进程组的组长,这是setsid调用的先决条件
- 调用setsid创建一个新会话,使调用进程:(a)成为新会话的首进程,(b)成为一个新进程组的组长进程,(c)没有控制终端。第c点在有的系统无法保证,所以可以在此再次调用fork然后终止父进程,继续使用子进程,这就保证该子进程不会是会话首进程,可以防止它取得控制终端。
- 将当前工作目录设为根目录或者某个指定位置
- 关闭不需要的文件描述符,包括下面3个
- 将标准输入,标准输出和标准错误重定向到/dev/null,是该进程无交互
出错记录
守护进程因为没有控制终端,所以无法将错误写到标准错误上。利用syslogd守护进程记录出错信息。
内核例程调用log函数,大多数用户守护进程调用syslog函数,还可将日志发送到UDP514端口,不过需要自行网络编程。
openlog(), syslog(), closelog(), setlogmask().
单实例守护进程
某些守护进程应该只有一个以避免错误,文件和记录锁机制提供了基础:如果每一个守护进程创建一个有固定名字的文件,并在文件加一把写锁,在此之后创建写锁的尝试都将失败,这相当于告诉后续守护进程副本已有一个副本在运行。
守护进程惯例
- 锁文件存储在/var/run/name.pid
- 配置文件在/etc/name.conf
- 在/etc/inittab中为该进程包括respawn,它如果被关闭将被init自动重启
守护进程常被作为服务器进程,用户进程就被看作客户进程。
为了防止安全问题,可以设置执行时关闭(close-on-exec)标志。