/* Copyright (C) HWPORT.COM All rights reserved. Author: JAEHYUK CHO <mailto:minzkn@minzkn.com> */ #if !defined(_ISOC99_SOURCE) # define _ISOC99_SOURCE (1L) #endif #if !defined(_GNU_SOURCE) # define _GNU_SOURCE (1L) #endif #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> int hwport_launcher(void); static void mysignal_handler(int s_signum); int main(int s_argc, char **s_argv); static int g_is_break = 0; int hwport_launcher(void) { pid_t s_pid; for(;;) { s_pid = fork(); /* 프로세스를 생성 */ if(s_pid == ((pid_t)(-1))) { /* fork 실패 */ return(-1); } else if(s_pid == ((pid_t)0)) { /* 자식프로세스 부분 - 실제 우리가 구현하는 목적의 코드들이 자식프로세스에서 실행되도록 합니다. */ /* ok. immortal process start */ /* need to default signal handler ! */ #if defined(SIGBUS) (void)signal(SIGBUS, SIG_DFL); #endif #if defined(SIGSTKFLT) (void)signal(SIGSTKFLT, SIG_DFL); #endif (void)signal(SIGILL, SIG_DFL); (void)signal(SIGFPE, SIG_DFL); (void)signal(SIGSEGV, SIG_DFL); break; } else { /* 부모프로세스 - 자식프로세스를 감시하고 비정상 종료를 감시하도록 하며 정상종료시에는 부모프로세스도 함께 종료합니다. */ pid_t s_waitpid_check; int s_status = 0; int s_options = 0; int s_signum = (-1); #if 1L /* DEBUG - SIGINT */ (void)signal(SIGINT, SIG_IGN); #endif (void)fprintf(stdout, "Start monitoring by hwport_launcher ! (pid=%ld)\n", (long)s_pid); /* 디버거에 의해서 step실행하게 될때 어떤 영향을 받는지 고민해봐야죠. */ #if defined(WUNTRACED) s_options |= WUNTRACED; #endif #if defined(WCONTINUED) s_options |= WCONTINUED; #endif do { s_waitpid_check = waitpid(s_pid, (int *)(&s_status), s_options); /* 자식프로세스의 종료를 기다립니다. */ if(s_waitpid_check == ((pid_t)(-1))) { /* 뭔가 자식프로세스를 확인하기 어려운 상황 */ /* what happen ? */ (void)fprintf(stderr, "Waitpid failed by hwport_launcher ! (pid=%ld)\n", (long)s_pid); exit(EXIT_SUCCESS); } if(WIFEXITED(s_status) != 0) { /* 일반적인 자식프로세스 종료상태 - main함수에서 반환 또는 exit함수에 의한 종료등 */ /* normal exit */ (void)fprintf(stdout, "Stop monitoring by hwport_launcher ! (pid=%long)\n", (long)s_pid); exit(EXIT_SUCCESS); } else if(WIFSIGNALED(s_status) != 0) { /* Signal 발생에 의한 종료 */ s_signum = WTERMSIG(s_status); if( #if defined(SIGBUS) (s_signum != SIGBUS) && #endif #if defined(SIGSTKFLT) (s_signum != SIGSTKFLT) && #endif (s_signum != SIGILL) && (s_signum != SIGFPE) && (s_signum != SIGSEGV) && (s_signum != SIGPIPE)) { /* 비정상 종료로 볼 수 있는 signal을 제외한 나머지 signal에 의한 종료인 경우 */ /* normal exit */ (void)fprintf(stdout, "Stop monitoring by hwport_launcher ! (pid=%long, signum=%d)\n", (long)s_pid, s_signum); exit(EXIT_SUCCESS); } } }while((WIFEXITED(s_status) == 0) && (WIFSIGNALED(s_status) == 0)); /* 자식프로세스가 종료된게 아닌 상황이면 다시 waitpid하는 loop - 보통 디버거상태를 추적하는 중일때 이 loop가 회전합니다. */ (void)fprintf(stdout, "Restarting by hwport_launcher ! (pid=%ld, signum=%d)\n", (long)s_pid, s_signum); sleep(3); /* 재시작 하기전에 약간 시간을 줘야 하는 경우가 프로그램 구현에 따라서 고려되어야 한다는 의미로... */ /* retry launch loop */ } } return(0); } static void mysignal_handler(int s_signum) { (void)fprintf(stderr, "CTRL+C\n"); g_is_break = 1; (void)signal(s_signum, &mysignal_handler); } int main(int s_argc, char **s_argv) { int s_ticks; (void)s_argc; (void)s_argv; (void)fprintf(stdout, "BEGIN TEST...\n"); if(hwport_launcher() == (-1)) { (void)fprintf(stderr, "hwport_launcher failed !\n"); } /* 이제부터 비정상 정료가 발생하면 hwport_launcher호출시점부터 다시 실행됩니다. */ (void)signal(SIGINT, &mysignal_handler); /* CTRL+C */ for(s_ticks = 0;(s_ticks < 60) && (g_is_break == 0);s_ticks++) { (void)fprintf(stdout, "alive (ticks=%d)\n", s_ticks); if(s_ticks == 10) { *((unsigned long *)0) = 1234; /* segment fault ! - 강제로 비정상 종료를 위해서 Fault상황을 발생해보죠. */ } sleep(1); } (void)fprintf(stdout, "END TEST...\n"); return(EXIT_SUCCESS); } /* vim: set expandtab: */ /* End of source */