LoginSignup
24
36

More than 3 years have passed since last update.

Linuxでデーモンプロセスを作ってみた

Last updated at Posted at 2018-10-05

最近デーモンについて学んだのでメモ代わりに書いてみました。

デーモンって??

デーモン (daemon)とはLinuxやUNIXにおいてメモリ上に常駐してるプロセス。
デーモンの意味は,悪魔の「demon」ではなく守護神の「daemon」。ここ大事

詳しくはwikiを読むのがベストだと思います。
デーモン (ソフトウェア)

ぶっちゃけて言えば無限ループのプログラム。
ループ中に要求があればそれに答えるといったイメージです。

ちょっと細かく書くと

  • (通常は)親プロセスのプロセスID (PID) が 1 (init)
  • 制御端末 (tty) を持たない

寄り道

ちょっと横道に反れます。
プロセスの話になるとよく聞くゾンビプロセスと孤児プロセスについてちょっと解説

  • 孤児プロセス
    子プロセスよりも先に親プロセスが死んだとき、その子プロセスは道連れにはされません。
    孤児となった子プロセスは init プロセスによって引き取られ、親が死んでも子は生き続けます。

  • ゾンビプロセス
    親プロセスが子プロセスの終了情報をキューから取り出さない限り、子プロセスの情報はシステムに残り続けます。
    psコマンドでのゾンビプロセスの場合、STAT に Z と表示されます。

ソース

では、具体的なソースを記載します。
プロセス生成といえばfork(2)が有名ですがここでは手軽にデーモン化する関数があるので、
daemon(3)を利用します(POSIX標準ではな無いのが注意点)。

daemnをがっつり作るなら下記のような作りこみが必要です。

  • プロセスを端末から切り離す
  • 入出力を一度閉じる(使うなら明示的にオープンしたものを使おう)
  • chdir(2) によりカレントワーキングディレクトリをシステムルート ("/") にする
  • umask(2) によりファイル作成モードマスクに 0 をセットする.
  • SYSLOGなり何がしかの出力ファイルに動作を出力する
  • SIGNALを受け取る
  • PIDファイルを作る

今回はさっくと手軽にデーモン作成を作成ってことで省略します。

daemon.c
#include <stdio.h>
#include <unistd.h>

void mainLoop() {
    while(1) {
        // ループさせたい処理
        sleep(3); 
    }
}


int main(void) {
    //ここで子プロセスを生成し親は終了
    if(daemon(0, 0) == 0) {
        mainLoop();
    } else {
        printf("error\n");
    }
    return 0;
}

上記をコンパイルしてプロセスを確認してみましょう
自身のPIDは164で親は1でinitとなっています。

$ ./daemon
$ ps -ef | grep -E "datemon|PID"
UID        PID  PPID  C STIME TTY          TIME CMD
daemon+    164     1  0 21:42 ?        00:00:00 ./daemon

上記はperlスクリプトなどもデーモンとして動かすことができます。
実際自作デーモンするくらいなら優秀なスケジューラにjobを設定すればいい話ですが
今回はちょっと踏み込んで調べてみました。

間違い等あればご指摘お願いします。

おまけソース

#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fs.h>

int main(int argc, char **argv)
{
  pid_t pid;
  int i;

  /* create new process */
  pid = fork();
  if (pid == -1)
    return -1;
  else if (pid != 0)
    exit(EXIT_SUCCESS);

  /* create new session and process group */
  if (setsid() == -1)
    return -1;

  /* set the working directory */
  if (chdir("/") == -1)
    return -1;

  /* close all open files*/
  for (i = 0; i < NR_OPNE; i++)
    close(i);

  /* redirect stdout,stdin,stderr */
  opne("/dev/null", O_RDWR);
  dup(0)
  dup(0)

  return 0;
}
24
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
36