• Tidak ada hasil yang ditemukan

1. 시그널 개념

N/A
N/A
Protected

Academic year: 2023

Membagikan "1. 시그널 개념"

Copied!
15
0
0

Teks penuh

(1)

9장. 시그널

유닉스 프로그래밍 및 실습

(2)

1. 시그널 개념

시그널 생명 주기

 시그널이 발생한다.

 커널이 해당 시그널을 쌓아둔다.(동일한 시그널이 오는 경우 하나만)

 가능한 시점에서 커널이 적절하게 처리한다

커널의 처리 방법

 시그널 무시

아무런 동작을 하지 않는다

절대 무시할 수 없는 시그널

SIGKILL

SIGSTOP

 시그널을 붙잡아 처리

현재 코드 경로를 따라가는 실행을 중단하고, 시그널마다 등록된 함수로 점프

 기본 동작

대부분 프로세스 종료

일부는 무시

시그널 식별자

 SIG로 시작하는 상징적 이름

 <signal.h>에서 정의

 p.392 ~ p.397 시그널 이름과 특징 확인

(3)

2. 기초적인 시그널 관리(1)

signal() 함수

 signal()이 성공하면 시그널을 받았을 때 수행할 현재 처리기를 제거하고, 대신 handler로 명시된

처리기 등록

 handler() 예

 현재 시그널을 무시하거나, 기본 값을 수행하도록 지정할 수도 있음

SIG_DFL

SIG_IGN

모든 시그널 기다리기

 프로세스를 잠들게 한 후 붙잡을 수 있는 시그널이 오면 깨어남

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signo, sighandler_t handler);

void my_handler(int signo);

#include <unistd.h>

int pause(void);

(4)

2. 기초적인 시그널 관리(2)

 예제 (p.400, p.401)

 실행과 상속

 exec() 수행시 새로 만들어진 프로세스는 시그널에 대해 각각

기본동작으로 설정

 부모가 이를 무시하도록 설정한 경우에만 그대로 상속

 fork()는 부모, 자식이 주소공간을 공유하므로 동일한 시그널 설정

상속

 시그널 번호를 문자열에 사상하기

 정적 문자열 검색 방법(가장 최선)

 BSD 계열 – psignal()

 비표준 - strsignal()

extern const char * const sys_signal[];

(5)

3. 시그널 보내기

 kill

pid 0인 경우 호출한 프로세스가 속한 프로세스 그룹 전체에게

pid -1인 경우 호출한 프로세스가 시그널을 보낼 권한이 있는 모든 프로세스에게

pid -1보다 작은 경우 프로세스 그룹 –pid에 속한 모든 프로세스에게

 권한 – CAP_KILL

 예제 p.406

 자신에게 시그널 보내기

 프로세스 그룹 전체에게 보내기

#include <sys/types.h>

#include <signal.h>

int kill(pid_t pid, int signo);

#include <signal.h>

int raise(int signo);

#include <signal.h>

int killpg (int pgrp, int signo);

(6)

4. 재진입 가능성

 시그널 처리기는 관련 프로세스가 중단되었을 때 무엇을 하고 있었는지에 대한 어떤 가정도 하지 않아야 한다.

 전역 자료를 절대 손대지 않는 정책이 바람직

 일부는 재진입 불가능

 재진입 가능 함수는 정적 자료를 조작해서는 안되며, 스택에 할당된 자료나 호출한 쪽에서 제공한 자료만 조작해야 한다.

 재진입 보장 함수

 p. 409 표 9-2

(7)

5. 시그널 집합

 시그널 차단과 같은 기능은 시그널들의 집합을 대상으로 함

 시그널 집합을 관리하는 함수 필요

 추가적인 시그널 집합 함수

 리눅스의 비표준 함수

#include <signal.h>

int sigempty(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signo);

int sigdelset(sigset_t *set, int signo);

int sigismember(const sigset_t *set, int signo);

#define _GNU_SOURCE

#include <signal.h>

int sigisempty(sigset_t *set);

int sigorset(sigset_t *dest, sigset_t *left, sigset_t *right);

int sigandset(sigset_t *dest, sigset_t *left, sigset_t *right);

(8)

6. 시그널 차단하기

 임계 영역(critical section)

 일시적인 시그널 차단(blocking)

 시그널 마스크 관리 함수

SIG_SETMASK

SIG_BLOCK

SIG_UNBLOCK

 대기 중인 시그널 조회하기

 일군의 시그널 기다리기

#include <signal.h>

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

#include <signal.h>

int sigpending(sigset_t *set);

#include <signal.h>

int sigsuspend(const sigset_t *set);

(9)

7. 고급 시그널 관리

 sigaction

 플래그 sa_flags에 SA_SIGINFO를 설정하면 sa-sigaction에 함수 명시

 sa_flags 값 (p.416)

 siginfo_t 구조체 (p.417)

 si_code (p.419)

#include <signal.h>

int sigaction(int signo, const struct sigaction *act, struct sigaction *oldact);

struct sigaction {

void (*sa_handler)(int); /* 시그널 처리기 혹은 동작 */

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask; /* 차단할 시그널 */

int sa_flags; /* 플래그 */

void (*sa_restorer)(void); /* 폐기 */

};

void my_handler(int signo, siginfo_t *si, void *ucontext);

(10)

8. 페이로드와 더불어 시그널 보내기

 페이로드와 같이 보내기

 예제(p.423)

#include <signal.h>

int sigqueue(pid_t pid, int signo, const union sigval value);

union sigval {

int sival_int;

void * sival_ptr;

};

(11)

과제

 주문/서빙 프로세스

 반복적으로 사용자의 주문을 받아 주방 프로세스에게 전달

 주방 프로세스에서 요리가 완료되었다는 시그널을 받으면 사용자에게 메시지 출력

 주방 프로세스

 주문/서빙 프로세스에게 시그널을 받으면 요리 시작

 요리마다 일정 시간이 경과하면 요리 완료

 주문이 완료되기 전에 새로운 주문이 들어와도 처리가 가능해야 함

등록된 주문이 없는 경우 요리 소요 시간으로 알람 설정

요리 도중 새로운 주문이 들어오는 경우, 남은 요리시간 저장 후 알람을 끄고, 새로운 주문 추가

 힌트 : 추가할 때 현재 진행 중인 요리를 완성하기 위해 필요한 시간과, 앞서 등록된 요리들의 시간 값을 합산한 후 소요시간에서 그 값을 뺀 값으로 등록

중단된 남은 소요시간으로 다시 알람 설정

(12)

과제(계속)

 주방 프로세스 (계속)

처리할 시그널은 2종류

 주문 도착 : SIGUSR1

 조리 완료 : SIGALARM

SIGUSR1 처리

 Case 1 : 조리 중인 요리가 없는 경우

COOK_TIME으로 알람 설정 후 대기

 Case 2 : 현재 조리 중인 요리가 있는

경우

알람을 끄고 남은 시간 저장

대기 큐에 주문 추가

남은 시간으로 다시 알람 설정

SIGALARM 처리

 주문/서빙 프로세스에게 SIGUSR2 보내기

 대기 중인 요리가 있으면 큐 맨 처음에 있는 것을 꺼낸 후 그 안에 저장된 시간으로 알람 설정 후 대기

alarm(COOK_TIME);

r_time = alarm(0);

insert_queue(q_hdr, COOK_TIME, r_time);

alarm(r_time);

요리완료 처리

alarm(q_hdr->n_time);

q_hdr

n_time n_time

(13)

참고자료 (1)

 sigsetjmp와 siglongjmp

 시그널 처리한 후 돌아갈 위치 설정

 시그널 처리한 후 루프 맨 처음으로 이동하는 식으로 시그널을 받은 지점이 아닌, 다른

위치로 가도록 할 수 있음

 goto와 비슷한 성격을 지니므로 될 수 있으면

이용하지 않는 것이 좋다.

 다음 샘플 코드 실행 결과 비교

(14)

참고자료 (2)

공통부분

1 #include <sys/types.h>

2 #include <signal.h>

3 #include <setjmp.h>

4 #include <stdio.h>

5

6 void main_menu();

7 void goback(int);

8

9 sigjmp_buf position;

10

11 /********************************************************************/

12 void main_menu() 13 {

14 int choice;

15

16 printf("######################\n");

17 printf("### 1. Test1 ###\n");

18 printf("### 2. Test2 ###\n");

19 printf("### 3. Test3 ###\n");

20 printf("### 4. Test4 ###\n");

21 printf("######################\n");

22 printf("Choice ? : ");

23 scanf("%d", &choice);

24 printf("Choice = %d\n", choice);

25 printf("$$$$$$$$$$$\n");

26 } 27

(15)

참고자료 (3)

28 /***************************************/

29 void goback(int signo) 30 {

31 fprintf(stderr, "\nCatch INT\n");

32

33 siglongjmp(position, 1);

34 } 35

36 /***************************************/

37 int main() 38 {

39 static struct sigaction act;

40

41 act.sa_handler = goback;

42 sigaction(SIGINT, &act, NULL);

43 44

45 while(1) {

46 sigsetjmp(position, 1);

47 main_menu();

48 } 49

50 }

28 /***************************************/

29 void goback(int signo) 30 {

31 fprintf(stderr, "\nCatch INT\n");

32 33 } 34

35 /***************************************/

36 int main() 37 {

38 static struct sigaction act;

39

40 act.sa_handler = goback;

41 sigaction(SIGINT, &act, NULL);

42

43 while(1) {

44 main_menu();

45 } 46

47 }

Referensi

Dokumen terkait

함수의 리턴형 함수가 처리 결과로 리턴하는 값의 데이터 형 함수의 리턴형이 void형이면 함수의 리턴 값이 없다는 의미 함수의 리턴형을 생략하면 int형으로 간주된다... 함수의 이름 함수의 이름도 식별자를 만드는 규칙에 따라서 만들어야