본문 바로가기
Server | Network

Daemon Process 작성시 주의사항

by 두루물 2011. 1. 27.


make >make.out 2>&1 &
----------------------------------------------------------------------------
 Daemon Process 작성시 주의사항
----------------------------------------------------------------------------

  Process Table Structure
+--------------------------+
|+ p_pid:                  |
|  kernel이할당             |
|  +-------------+         |
|  |             |         |
|  +-------------+         |
|+ p_pgrp:                 |
|  setpgrp()로 할당가능      |
|  +-------------+         |
|  |             |         |
|  +-------------+         |
|+ file descriptor         |
|  +-------------+         |     socket structure
|  |fd 0:        |         |    +---------------+
|  |fd 1:     ---+---------|--->| so_pgrp       |  <== fcntl(F_SETOWN)로세팅
|  | .           |         |    +---------------+   
|  | .           |         |      소켓Group ID로 SIGIO,SIGURG signal을 처리할
|  | .           |         |      process또는 process group를 구분하여준다.
|  | .           |         |
|  | .           |         |            file table
|  | .           |         |    +-------------+
|  |             |         |    | current     |         i-node table
|  |fd i:     ---+---------|--->|file position|        +-----------+
|  |             |         |    +-------------+        |i-node 정보|
|  +-------------+         |    |Inode pointer|------> |           |
|                          |    |             |        +-----------+
|                          |    +-------------+
|+control tty:             |
|  제어단말기가없을때NULL  |
|  +-------------+         |
|  |             | --------|--->tty structure
|  +-------------+         |    +------------+
|                          |    | t_pgrp:    | <==ioctl(TIOCSPGRP)로 세팅
|                          |    +------------+    단말기와 관계된 signal를
|                          |                      처리할 Process Group 구분.
+--------------------------+

*getty가 제어단말기(사용등록을 하는 단말기)를 할당한다


  -열려진 모든 file description number를 닫기
   데몬을 exec한 parent process의 속성을 상속받기때문이다.
   #include <sys/param.h>
   for(i=0;i<NOFILE;i++)
        close(i);

[설명]
   NOFILE =하나의 프로세스가 열수있는 최대파일수
           _NFILE,getdtablesize

   -현재작업디렉토리를 지정한다.
    chdir("/");

   -파일접근 mask를 리셋한다.
    umask(0);

   -Background 로 실행한다.
    그렇지않으면 단말기에 종속되므로 child를 fork하고
    자신은 exit한다

   -프로세스 그룹에서 분리한다
    프로세스는 자신을 exec한 프로세스로부터 프로세스
    그룹id를 상속받는다.
    특정프로세스그룹에 signal를 보내면 영향을받을수있으므로
    이것을 방지하기 위해 자신의 프로세스그룹을 생성해야한다.

    setpgrp();
    setpgrp(0,getpid());

    -단말기의 I/O signal를 무시한다
     제어단말기와 데몬의 관계를 끊어야한다.
     Background 프로세스에서 단말기로 출력을 무시한다.
     #ifdef SIGTTOU
        signal(SIGTTOU,SIG_IGN);
     #endif
    -제어단말기와 분리한다
     1.System V

     if(fork()!=0)
         exit(0);//parent
     setpgrp();

     2.4.3BSD 계열
     if(fork()!=0)
         exit(0);//parent
     setpgrp(0,getpid());
     if((fd=open("/dev/tty",O_RDWR))>=0)
     {
        //control tty 분리
        ioctl(fd,TIOCNOTTY,(char *) o);
        close(fd);
     }

     -종료포착
      4.3BSD에서는 SIGERM signal을 사용한다.
      init Process가 이 signal을 보내고 5초(4.3BSD),20초(System V)
      후에도 종료하지 않으면 ignore 불가한 SIGKILL signal 을 보낸다.
      따라서 SIGTERM signal을 포착하고 종료할수 있어야 한다.

     -SIGCLD signal을 처리한다.
      child process 의 exit로 인해 발생하는 SIGCLD 를 처리하지않으면
      child process는 Zombie가되고 system resource가 낭비된다.
      system V에서는 SIG_IGN으로 처리하고 4.3BSD에서는 다음이 이신호를
      처리한다.

      sig_childexit()
      {
       int pid;
       union wait status;
       while((pid=wait3(&status,WNOHANG,(struct rusage *)0))>0);
      }

[예제] System V

startDaemon(ignore_sigcld)
int ignore_sigcld;
{
  int cpid,fd;
  if(getppid()==1) //root
        goto last;
  //제어단말기와 신호분리
  signal(SIGTOU,SIG_IGN);
  signal(SIGTTIN,SIG_IGN);
  signal(SIGTSTP,SIG_IGN);

  if((cpid=fork())<0)  perror("can't 1st child");
  else if(cpid>0)
      exit(0);//parent process

  if(setpgrp()==-1)
        perror("can't change");
  signal(SIGHUP,SIG_IGN);//제어단말기가 종료되었을때 종료를 무시한다.

  if((cpid=fork())<0)
     perror("can't 2nd child");
  else if(cpid>0)
     exit(0);//1st child

last:
  for(fd=0;fd<NOFILE;fd++)
     close(fd);
     errno=0;
  chdir("/");
  umask(0);
  if(ignore_sigcld)
  {
    signal(SIGCLD,SIG_IGN);
  }
}

From My old study memo,
E.A.S.T W.O.O.D KRKIM 1998