시그널, signal

OS/리눅스 & 유닉스 2012. 2. 1. 19:42

1. 시그널의 개념

  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를 입력해서 대기 상태 끝내기

[출처] 2. 시그널 |작성자 닉s

'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
: