[질문] SIGCHLD 처리에 대한 질문입니다.
글쓴이: minij / 작성시간: 화, 2004/06/15 - 9:49오전
안녕하세요.
리눅스에서 코딩을 처음 하는 초보입니다.
지금 간단한 리모트 쿼리에 간단한 응답을 날리는 동시 접속 서버 프로그램을 작성중입니다.
리퍼런스 책과 이곳 게시판을 참조해서 작업중인데,
Child signal을 처리해 주지 않으면 child 프로세스가 좀비 상태로 남는다는 말을 들었습니다.
이거 저거 참고해서 SIGCHLD를 처리하고 작업을 일단 마무리 했는데,
이 처리 부분에서 가끔 시간이 매우 많이 걸리는 현상이 일어납니다.
다음은 소스 코드입니다.
/************************************************************************************************ child_signal_handler ************************************************************************************************/ static void child_signal_handler(int sig) { int stat; pid_t pid_child; /* Process dead child */ do { pid_child = waitpid(-1, &stat, WNOHANG); } while (pid_child != -1); /* Reset child signal handler */ set_child_signal_handler(); } /************************************************************************************************ set_child_signal_handler ************************************************************************************************/ int set_child_signal_handler(void) { int res; struct sigaction actsig; /* Setting */ actsig.sa_handler = child_signal_handler; sigfillset(&(actsig.sa_mask)); actsig.sa_flags = 0; /* Set child signal handler */ res = sigaction(SIGCHLD, &actsig, NULL); return res; } /************************************************************************************************ main ************************************************************************************************/ int main(int argc, int *argv[]) { /* Initialize Globals */ initialize_globals(); /* Set shild signal handler */ if (set_child_signal_handler() == -1) { terminate_server("Setting child signal handler failure !"); } /* Ignore SIGPIPE signal */ signal(SIGPIPE, SIG_IGN); /* Run main server */ run_server(); /* Will not be processed */ return 0; }
보시다시피 메인에서 SIGCHLD 시그널 핸들러를 설정하고, SIGPIPE를 무시하고, 바로 서버를 돌립니다.
서버 프로그램은 포크로 자식을 분기하는 일반적인 루틴입니다.
테스트 중에 한 클라이언트가 종료하고 난 후에,
서버 프로그램의 CPU 점유율이 99%로 올라가는 현상을 발견했습니다.
디버깅을 해보니 child_signal_handler의 while 문에서 많은 시간이 흘러가고 있었고, 경우에 따라서 몇 분씩 걸릴 때도 있었습니다.
여기 저기서 보고 만든 것이라, 제가 한 방법이 틀릴 수도 있을 것입니다.
작은 힌트에서부터 커다란 도움까지 모두 환영합니다.
도와 주세요. ㅠ.ㅠ
Forums:
child가 두개이상 생기게 되면,waitpid()가 0을 리턴하는
child가 두개이상 생기게 되면,
waitpid()가 0을 리턴하는 경우가 생기게 되죠.
그러면? do while 이...
[quote="yoocj9"]child가 두개이상 생기게 되면,wai
그럼 0을 리턴해도 Child Process는 정상 종료되는 건가요?
Aim high !
while 문의 ret 값 체크를 > 0 로 바꿔 주십시오.
while 문의 ret 값 체크를 > 0 로 바꿔 주십시오.
man waitpid의 WNOHANG와 return value 0를 참조하시길..
I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?
코드 상으로는 별 문제 없어 보이는데요,,로그를 찍어보세요.. ^^
코드 상으로는 별 문제 없어 보이는데요,,
로그를 찍어보세요.. ^^
Posix계열 signal handling은 reliable 하니까
다시 SIGCHLD를 설정해주실 필요는 없을 것 같고요.
Solaris쪽 waitpid() man페이지를 보니까
같은 부분이 보이네요.
child는 있는데 status가 available하지 못하면 0이 리턴될 수도 있다고 하네요.
테스트해 보니까 child process가 STOP 되는 경우
(해당 process에 kill -STOP 으로 STOP시그널을 주었습니다.)
waitpid()가 0을 리턴하면서 무한루프에 빠지는경우가 발생하네요.
WUNTRACED 옵션을 주어서 상태를 얻어올 수 있는데
그 다음번 waitpid() 시에 곧바로 0이 리턴되어서 해결책은 안되는 듯 싶습니다.
waitpid() 가 0을 리턴했을때도 signal handler를 빠져나가는 것도 방법일 듯 싶은데,
실제로 exit()한 녀석들(status가 available한)과 STOP된 녀석들이 waitpid()시에 동시에 있을 때
STOP된 녀석을 맨 마지막에 wait해 줄지가 보장이 되어있지 않고,
STOP된 녀석을 wait한 후에 0이나 해당 프로세스 ID를 리턴한 후
(WUNTRACED 옵션에 따라서 틀림), 다음번에 waitpid를 호출했을 때
그 다음 대기하고 있는 child process를 wait해 줄지, 아니면 STOP된
녀석이 계속 wait되어 0이 리턴될지에 대한 내용이 스펙에 기술이 안되어 있는 문제가 있습니다.
Posix 쪽에서는
라고해서 status가 available한 경우에 그 순서는 정해져있지 않다고 하고,
status가 available한 process와 available하지 않은 process간의 순서에
대한 사항은 명확히 나와있지 않습니다.
테스트 해 본 결과로는 STOP된 프로세스는 맨 마지막에 wait가 되었습니다.
status 에 NULL을 주어서 상태를 얻어오지 않아도 역시 0을 리턴했습니다.
또 interrupt에 의해서도 0을 리턴하는 것 같은데,
현재 코드에서는 모든 시그널을 마스킹 해 놓으셨으니까
이 경우는 아닌 듯 싶고요.
답변주신 최종호님, 웃는남자님, yoocj9님 감사합니다.덕분에 이
답변주신 최종호님, 웃는남자님, yoocj9님 감사합니다.
덕분에 이 문제를 해결할 수 있었습니다.
이제 또 다른 테스트에 들어가야지요. ^^
또 모를 때, 질문드리겠습니다.
행복하시구, 좋은 하루가 되시기를 !
Aim high !
[quote="최종호"]Posix계열 signal handling은
왜 이걸 다시 설정해야 하는지 무지 궁금한 부분이었는데... Reliability 문제였군요.
여러 가지로 테스트까지 해주시고 신경 써 주셔서 감사합니다. ^^
Aim high !
댓글 달기