현생/TCP 소켓 프로그래밍

10-5 시그널 핸들링 - sigaction, 좀비 프로세스 해결 [TCP/IP][C][LINUX]

푸더기 2022. 1. 30. 13:42
반응형

sigaction 함수는 signal 함수를 대체할 수 있고 더 안정적입니다. sigaction 함수는 유닉스 계열 운영체제 별 동작방식에 따른 차이를 보이지 않기 때문입니다. 따라서 요즘은 signal 함수 대신 sigaction 함수를 사용합니다.

 

#include<signal.h>

int sigaction(int signo, const struct sigaction * act, struct sigaction * oldact);
//success: 0   fail: -1

//signo: 시그널의 정보
//act  : 시그널 발생시 호출될 함수의 정보
//oldact: 이전에 등록되었던 시그널 핸들러의 함수 포인터를 얻는데 사용, 필요 없으면 0 전달

 

위 함수의 호출을 위해서는 sigaction이라는 이름의 구조체를 선언 및 초기화해야합니다.

struct sigaction{
	void (*sa_handler)(int);
    sigset_t sa_mask;
    int sa_flags;
}

sa_handler에는 함수 포인터 값을 저장하고 sa_mask의 모든 비트를 0으로, sa_flags도 0으로 초기화 하면 됩니다.

 

#include<stdio.h>
#include<unistd.h>
#include<signal.h>

void timeout(int sig){
	if(sig==SIGALRM)
		puts("Time out");
	alarm(2);
}


int main(int argc, char *argv[]){
	int i;
	struct sigaction act;
	act.sa_handler=timeout;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	sigaction(SIGALRM, &act, 0);
	
	alarm(2);
	
	for(i=0; i<3; i++){
		puts("wait...");
		sleep(100);
	}
	
	return 0;
}

sigaction 함수를 사용한 예제코드입니다. sigaction 구조체를 설정해주고, 2초마다 Time out을 출력하는 시그널핸들링을 해주었습니다. 앞서 10-4에서 보았듯이 시그널이 발생하면 블로킹이 해제되므로 sleep(100)에 의해 총 300초를 잠들어야하지만 10초 이내로 실행이 종료됩니다.

 

이제 sigaction 함수를 이용해서 좀비 프로세스를 소멸시키는 방법을 알아보겠습니다. 

 

자식 프로세스가 종료된 상황에 대한 시그널 이름이 SIGCHLD임을 이용하면 위의 내용만으로 손쉽게 예제코드를 작성할 수 있습니다.

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>

void read_childproc(int sig){
	int status;
	pid_t id = waitpid(-1, &status, WNOHANG);
	if(WIFEXITED(status)){
		printf("Removed proc id: %d\n",id);
		printf("Child send: %d \n",WEXITSTATUS(status));
	}
}

int main(int argc, char *argv[]){
	pid_t pid;
	struct sigaction act;
	act.sa_handler=read_childproc;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	sigaction(SIGCHLD, &act, 0);
	
	pid=fork();
	if(pid==0){ //자식 프로세스 실행 영역
		puts("Hi! I'm child process");
		sleep(10);
		return 12;
	}
	else{ //부모 프로세스 실행 영역
		printf("Child proc id: %d \n",pid);
		pid=fork();
		if(pid==0){ //자식2 프로세스 실행 영역
			puts("Hi! I'm child process");
			sleep(10);
			exit(24);
		}
		else{ // 부모 프로세스 실행 영역
			int i;
			printf("Child proc id: %d \n", pid);
			for(i=0; i<5; i++){
				puts("wait...");
				sleep(5);
			}
		}
	}
	return 0;
	
}

자식 프로세스의 종료, 즉 SIGCHLD 시그널이 발생하면 act 함수가 실행되도록 짠 예제코드입니다. 첫 번째 자식은 10초를 기다린 후 12를 반환하고 두 번째 자식은 10초를 기다린 후 24를 인자로 가진 exit를 호출합니다. 둘 모두 정상적으로 종료되어 값을 전달하게 됩니다.

반응형