Unix/Linuxの世界において、デーモン(daemon)とは、バックグラウンドで実行されるプロセスです。
端末からの制御から独立しており、それぞれが異なる管理プロセスを実行しています。
今回は、プロセスをデーモン化させる手法をソースコードとともに解説していきます。
その前に、いくつか技術的なキーワードの解説から始めます。
プロセス
OS上でタスクを実行する主体
各プロセス毎にIDが付与されている。
フォアグラウンドプロセス
ユーザが操作対象としているプロセスのことをいう。
例えば、ターミナルでgrep,findなどを実行している時、grep,findはフォアグラウンドプロセスとなる。
ただし、grep & or find &とすることで、バックグラウンドプロセスとして実行出来る。
バックグラウンドプロセス
フォアグラウンドプロセスと逆意。
デーモンプロセス
制御端末を持たずバックグラウンドで動作するプロセス。
syslogd、httpd、inetd、crond、smbd、etcがある。
fork(フォーク)
プロセス(親)のコピーを行い、別プロセス(子)を生成する。
プロセス間で親子関係が発生し、親プロセスには、forkから子プロセスのIDが返され、子プロセスには、0を返す。
プロセスグループとセッション
プロセスグループ
一つ以上のプロセスの集まり。
各プロセスグループには、一意なプロセスグループIDが付与されている。
プロセスグループを代表するリーダーが存在する。
セッション
一つ以上のプロセスグループの集まり。
上図では、3つのプロセスグループからセッションが構成されている。
セッションを代表するリーダーが存在する。このリーダーが端末との接続を確立できる。
シグナル
プロセスに通知する非同期イベント
シグナル(SIGHUP)
プロセスの終了と再起動を実施するシグナル
プロセスデーモン化の流れ
forkを実行させ、親プロセスを終了させる。
子プロセスは、自動的にバックグラウンドで実行を継続する。
子プロセスは、親プロセスのプロセスグループIDを引き継ぎ、自身のプロセスIDでの実行を行う。
この時、子プロセスは、プロセスグループリーダーではない。
新しいセッションを作成するためのPosix関数。
この関数を呼び出すことで、新しいセッションのセッションリーダー、そして、プロセスグループのプロセスグループリーダーとなる。
かつ、コントロールターミナルを持たない状態となる。
SIGHUPシグナルを無視する設定を行い、再度fork実施
再forkの意図として、このforkで生成された子プロセスが、セッションリーダーではないことを保証する。
SIGHUPシグナル無視は、再fork後、親プロセス終了時に、子プロセスにSIGHUPシグナルがOSから送られるため。
ワーキングディレクトリをルートディレクトリに変更する。
デーモンが任意のファイルシステム上で実行される可能性があり、その場合、ファイルシステムをアンマウント出来なくなるため、
このオペレーションが必要となる。
デーモンプロセスとして、親プロセスがオープンしてるファイルディスクリプタをオープンする必要はこの時点ではないのでクローズ実施。
syslogdをラッパしたopenlogをコール。
以下、これを実装したソースコード
リチャードスティーブンスのサイトよりソースを引用。
http://www.kohala.com/start/unpv12e.html
プロセスのデーモン化
#include "unp.h"
#include <syslog.h>
#define MAXFD 64
int
daemon_init(const char *pname, int facility)
{
int i;
pid_t pid;
if ( (pid = Fork()) < 0)
return (-1);
else if (pid)
_exit(0); /* parent terminates */
/* child 1 continues... */
if (setsid() < 0) /* become session leader */
return (-1);
Signal(SIGHUP, SIG_IGN);
if ( (pid = Fork()) < 0)
return (-1);
else if (pid)
_exit(0); /* child 1 terminates */
/* child 2 continues... */
chdir("/"); /* change working directory */
/* close off file descriptors */
for (i = 0; i < MAXFD; i++)
close(i);
/* redirect stdin, stdout, and stderr to /dev/null */
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
openlog(pname, LOG_PID, facility);
return (0); /* success */
}
サーバプロセスをデーモン化するには?
デーモン化したいサーバプログラムの初期処理先頭部分で、上記デーモン化処理関数をコールするだけで、
サーバプロセスはデーモンとなる。
サーバプログラム内で、printf/fprintf関数を利用している場合は、err_msg関数を利用し、コンソール出力を
止める必要がある。