시그널, signal
OS/리눅스 & 유닉스 2012. 2. 1. 19:421. 시그널의 개념
1)프로세스에 사건의 발생을 알려주는 소프트웨어적인 통지
2)하드웨어에 의해 발생되는 시그널 : 0으로 나누거나 잘못된 메모리 참조
3)비동기적 사건들의 발생을 프로세스에게 알려줌(인터럽트)
*비동기적 : 시그널을 보낸 쪽에서 받는 쪽의 응답을 기다리지 않음
*인터럽트 : 수행하고 있는 프로세스 중단(일시 중단)
4)시그널 처리 단계
ⓐ생성 - 프로세스가 수신해야 하는 이벤트가 일어남
ⓑ처리 - 프로세스가 시그널을 인지하고 그것에 적합한 동작을 수행함
*이 두 단계 사이에 위치할 때 시그널이 펜딩(지연) 되었다고 함
5)시그널 함수의 원형
#include (*signal(int sig, void(*func)(int)))(int);
*sig는 신호 번호, func는 신호처리 핸들러 함수이다.
이 함수는 신호를 처리하기 위해 이전에 설정되어 있던 핸들러 함수를 변환 하거나 SIG_INT또는 SIG_DFL를 반환한다.
SIG_IGN은 처리를 무시하라는 값이며 SIG_DEF는 기본 동작을 복구하라는 값
2. 유닉스 표준 시그널의 종류(POSIX 표준)
*SIGABRT - 프로세스 중단
*SIALARM - 알람 알림(비정상 종료)
*SIGBUS - 정의되지 않은 메모리 영역 접근
*SIGCHLD - 자식 프로세스의 종료, 중단 , 계속
*SIGCONT - 중단되었다면 재시작합낟.
*SIGFPE - 0으로 나누는 것과 같은 산술연산 에러
*SIGHUP - 제어 터미널(프로세스)의 중단(종료)
*SIGILL - 잘못된 하드웨어 명령어
*SIGINT - 사용자 인터럽트를 커널에 의하여 단말기와 연결된 프로세스에 보내짐(ctrl+c)
*SIGKILL - 종료(어떤 경우에도 프로세스 종료가 보장되는 신호) : 슈퍼유저가 통제하는 방법
*SIGPIPE - 읽는 프로세스가 없는 상황에서의 PIPE에 대한 쓰기 발생시
*SIGQUIT - 대화형 종료 : 코어 덤프(ctrl+i)
코어 덤프 : 종료 시점전까지의 데이터를 저장한 파일
*SIGSEGV - 잘못된 메모리 접근
*SIGSTOP - 실행 중지(처리되거나 무시될 수 없음)
*SIGTERM - 프로세스 종료 시그널 (kill 시그널 전송 전에 전송됨)
*SIGSTOP-터미널 중지
*SIGTTIN-백그라운드 프로세스가 읽기를 시도
*SIGTTOU - 백그라운드 프로세스가 쓰기를 시도
*SIGURG - 소켓에 높은 대여폭 데이터가 유용함
*SIGUSR1 - 유저 정의 시그널1
*SIGUSR2 - 유저 정의 시그널2
3. 시그널을 다루기 위한 시스템 호출/표준 라이브러리 함수
1)시그널 집합 생성
#incldue <stdio.h>
int sigemptyset(sigset_t *set); : 시그널이 없는 비어있는 상태로 초기화 int sigfillset(sigset_t *set); : 모든 시그널이 포함된 상태로 초기화 int sigaddset(sigset_t *set); : 시그널 추가 int sigdelset(sigset_t *set); : 시그널 삭제 int sigismember(const sigset_t *set, int signo) : 시그널 찾기 |
ⓐset - sigset_t형의 시그널 집합
*시그널 각각을 인수로 하면 동일한 작업을 수십번 해야 한다.
ⓑsignum - 시그널 번호
ⓒ반환값 : 호출이 성공하면 0, 실패하면 -1반환 sigisnumber만 성공하면 1이나 0을 반환하고 실패하면 -1을 반환한다.
ex)예제 프로그램
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
void main()
{
sigset_t set; //시그널 집합 선언
sigemptyset(&set);
result = sigisismember(&set, SIGALARM); //SIGALARM이 등록 결과 저장
printf("SIGALARM is %s a member\n", result ? "" : "not"); //삼항 연산자 사용 비교
sigaddset(&set, SIGALARM); //시그널 추가
result = sigisismember(&set, SIGALARM);
printf("SIGALARM is %s a member\n", result ? "" : "not");
sigfillset(&set); //모든 시그널이 포함된 상태로 초기화
result = sigismember(&set, SICHLD);
printf("SIGCHLD is %s a member\n", result ? "" : "not");
sigadelset(&set, SIGCHLD); //삭제
result = sigismember(&SET, SIGCHLD);
printf("SIGCHLD is %s a member\n", result ? "" : "not");
}
2)Sigaction
특정 시그널을 받았을 때 프로세스가 취해야 할 행동 지정
-signum으로 지정한 시그널에 대해서 act로 지정한 행동을 취한다.
-새로운 행동인 act가 등록되면서 기존의 행동은 oldact에 저장된다.
-원형
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); signum-시그널 번호 act-프로세스가 지정한 시그널에 대한 행동 저장 oldact-이전에 지정되어 있는 시그널 행동 저장, 보통 NULL 반환값 : 호출 성공시 0 실패시 -1 |
struct sigaction {
void (*sa_handler)(int); /*SIG_DFL, SIG_IGN*/ =주소값
void (*sa_sigaction)(int, siginfo_t*, void*); /*실시간 핸들러*/
sigset_t sa_mask; /*핸들러 실행 동안 추가 블록될 시그널*/
int sa_flag; /*옵션 값*/
}
ex)예제
①#include <signal.h>
②#include <unistd.h>
③#include <stdio.h>
④int num=0;
⑤void main()
{
⑥static struct sigaction act; //구조체 선언
⑦void int_handle(int);
⑧act.sa_handler = int_handle;
⑨sigfillset(&(act.sa_mask));
⑩sigaction(SIGINT, &act, NULL); //SIGINT 등록
⑪while(1) {
⑫printf("i'm sleepy..\n");
⑬sleep(1);
⑭if(num >= 3) {
⑮ act.sa_handler = SIG_DFL;
16.sigaction(SIGINT, &act, NULL);
}
}
}
void int_handle(int signum)
{
17.printf("SIGINT : %d\n", signum);
printf("int_handle called %d times\n", ++num);
}
*i'm sleepy를 계속 출력하다가 사용자가 ctrl+c를 입력하면 인터럽트 메세지를 출력하고 4번 출력시 종료
원리 : 1. 8번에서 act.sa_handler에 int_handle의 주소 저장
2. 9번에서 블록될 시그널의 목록을 저장한 상태로 초기화
3. 10번에서 sigaction의 act에 SIGINT를 받았을 때의 행동 저장.
4. 11번 수행을 하다가 SIGINT(ctrl+c)를 입력받으면 SIGINT의 signum(2)를 입력받는 int_handle함수로 이동
5. 받을 때마다 17번째 줄을 수행(3번 입력 전까지)
6. 3번 입력 받을시 14번으로 이동하고, act에 SIG_DFL저장
7. SIG_DFL이 SIG_INT이므로 SIGINT가 들어오면 프로그램 종료
3)sigprocmask
- 시그널 집합 단위로 봉쇄될 시그널들의 목록을 설정
- 시스템이 대단히 중요한 코드를 실행 중이면 시그널을 무시하고 작업 종료 후 시그널 봉쇄 해제
- 원형
int sigprocmask(int how, const sigset_t *set, sigset_t *oldest); how-행동 방식 결정 set-새롭게 적용하는 시그널 마스크 oldest-이전에 적용되어 있는 시그널 마스크 저장 반환값-호출이 성공할 경우 1, 실패할시 -1반환 |
int how
SIG_BLOCK : 현재 봉쇄된 시그널의 목록에 두 번재 인자 SET에 포함된 시그널을 추가한다.
SIG_UNBLOCK : 현재 봉쇄된 시그널의 목록에 두 번째 인자 set에 포함된 시그널을 제외
SIG_SETMASK : 현재 봉쇄 설정된 시그널의 목록에 두 번째 인자 SET에 포함된 시그널 대체
ex)예제
#incldue <unistd.h>
#include <stdio.h>
#include <signal.h>
void main()
{
sigset_t set;
int count = 3;
sigemptyset(&set);
①sigaddset(&set, SIGINT);
②sigprocmask(SIG_BLOCK, &set, NULL);
while(count)
{
③printf("don't disturb me (%d)\n", count--);
sleep(1);
}
④sigprocmask(SIG_UNBLOCK, &set, NULL);
⑤printf("you did not disturb me!!\n");
}
*사용자의 인터럽트 SIGINT를 봉쇄시켜서 시스템작업(while문 안의 문장수행)을 방해하지 못하게 함
인터럽트가 안들어올시 2번 3번 출력후 4번 출력, 들어올시 2번 출력후 완료
원리) ①1번에서 SIGINT를 시그널 집합에 추가
②블록될 시그널 목록에 SIGINT추가
③count가 영이 될 때까지 3번 문장 출력
④사용자 인터럽트 없을시 SIGINT를 언블록하고 5번 문장 출력
⑤사용자 인터럽트가 들어올 시, 3번을 3번 출력후 UBBLOCK된 SIGINT수행(종료)
4) KILL과 RAISE
-KILL은 특정 프로세스나 프로세스 그룹에게 지정한 시그널을 전달하고, RAISE는 자기 자신에게 지정한 시그널을 전달한다.
#include <sys/types.h> int kill(pid_t pid, int sig);
#include <signal.h> int raise(int sig);
pig=프로세스 식별 번호 sig=시그널 번호 반환값=호출 성공시 0, 실패시 -1 |
pid값에 따른 의미
pid>0 : 프로세스의 식별 번호. 해당프로세스에게만 시그널 보냄
pid=0 : 자신과 같은 그룹에 있는 모든 프로세스에게 시그널 보냄
pid=-1 : 자신과 같은 그룹에 있는 모든 프로세스에게 시그널을 보내지만, 프로세스 식별 번호가 1인 프로세스 제외.
pid<-1 : 프로세스 그룹 식별 번호가 -pid인 모든 프로세스에게 시그널 보냄.
5) Alarm
-지정 시간 경과후 자신에게 SIGALARAM 시그널을 보낸다
*unsigned int alarm(unsigned int seconds);
second : 초 단위의 시간, 지정한 시간 중 남은 시간 반환
ex) 예제
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void timeover(int signum)
{
printf("\n\ntime over!!\n\n");
exit(0);
}
void main()
{
char buf[1024];
char *alpha = "abcdefghijklmnopqrstuvwxyz";
int timelimit;
struct sigaction act;
act.sa_handler = timeover;
sigaction(SIGALARM, &act, NULL);
printf("input timelimit (sec)..\n");
scanf("%d", &timelimit);
alarm(timelimit);
printf("START!!\n");
scanf("%s", buf);
if(!strcmp(buf, alpha))
printf("well done..you succeed!\n");
else
printf("sorry.. you fail!\n");
}
6)pause
-시그널이 전달될 때까지 대기한다.
*int pause(void)
-항상 -1을 반환한다.
"pause를 실행하면 프로세스는 임의의 시그널이 수신될 때까지 대기 상태가 된다.
ex)예제
#include <unistd.h>
#Include <signal.h>
void main()
{
printf("pause return %d\n", pause());
}
-----ctrl+c를 입력해서 대기 상태 끝내기
'OS > 리눅스 & 유닉스' 카테고리의 다른 글
signal set 관련 함수 (sigemptyset, sigaddset, sigdelset, sigprocmask) (0) | 2012.02.01 |
---|---|
pthread_kill (0) | 2012.02.01 |
프로세스 끼리의 통신 UDS (0) | 2012.01.19 |
inittab (0) | 2012.01.19 |
공유 메모리 정보 / 변경 shmctl() (0) | 2012.01.12 |