시스템프로그래밍

시스템프로그래밍(12) - ecf-signals

gilola 2024. 12. 14. 04:22

Shell

-> kernel과 user을 연결해주는 interface

-> 사용자와의 interaction

    -> interaction: user의 입력을 받고 실행 결과를 화면에 출력

 

Shell에서 problem

-> fork 없이 exeve 호출하면 shell은 새로운 프로그램으로 존재하고 더 이상 존재 x

-> shell은 fg의 종료를 기다리고 reap

-> bg가 종료되면 zombie가 됨

-> shell은 zombie를 수거하지 않음 

-> memory leak발생

 

Solution 

-> ecf

-> bg 완료되면 정규 처리 중단, process 알림 (signal) 보냄

 

Signal

-> system에서 event 발생했음을 알리는 message

-> Signal => Stop => Reap => continue

-> kernel이 process로 signal 보냄

-> ID 로 신호 식별

-> signal에는 ID와 도착 여부 

 

Signal을 보내는 이유

1. System event 감지

-> ex) 0으로 나누기, 자식 process 종료

2. 다른 process가 kill system call 호출 -> 자식 process 종료

 

Signal에 대한 반응

1. Ignore

2. Terminate

3. Signal handler 실행

 

Signal 특징

-> 비동기적 처리

-> 동일 signal 중첩 X

-> signal을 차단할 수 있음

-> pending signal은 최대 한 번 수신

 

Pending Signal

-> 대기 중인 신호 집합을 나타냄

 

Blocked Signal

-> 차단된 신호 집합을 나타냄

-> sigprocmask()를 사용

 

Process Group

-> shell에서 child와 grouoppid를 분리하지 않으면 Ctrl + c 경우 process 뿐만 아니라 shell program도 종료

 

 Ctrl + c 

-> SIGINT (각 프로세스 종료)

-> fg group 모든 작업에 보냄

 Ctrl + z

-> SIGSTP (각 프로세스 중단)

-> fg group 모든 작업에 보냄

-> bg로 이동

 

Handler에서 signal처리

-> pnb = pending & ~blocked 계산

-> pnd는 대기 중이며 차단되지 않은 신호 집합

-> pnb = 0이면 새로운 process의 다음 명령어로 제어 전달

-> pnb != 0 이면 signal 강제 수신, 모든 pnb 비트가 처리될 때까지 반복

 

Signal의 동작

1. process terminate

2. process stop

3. signal ignore

 

Signal Handler 

-> handler_t * signal (int signum, handler_t * handler)

-> SIG_IGN: 신호 무시

-> SIG_DFL: 기본 동작으로 되돌림

 

Signal handler concurrent flow

-> main함수와 handler은 동시에 실행

-> 둘은 동일한 process

 

Nested Signal Handler

-> 동일한 프로세스에서 N개의 동시 흐름이 발생 가능

-> 예상치 못한 결과 초래할 수 있음

 

Implicit blocking mechanism

-> 동일한 signal은 blocking

Explicit blocking mechanism

-> sigprocmask() 함수 사용 하여 신호를 block / unblock

-> 서로 다른 sig들을 ordering

 

Shared data Problem

-> handler와 main은 동일한 global data 구조 공유

1. handler는 단순하게 유지

2. async-signal-safe가 보장된 함수만 호출

3. handler 진입/종료 시 errno 저장/ 복원

4. shared data 접근할 때 모든 sig 일시적 차단

 

Async-signal-safe 함수

-> reentrant (재진입 가능, stack에 모든 변수 저장, local 변수 사용) 하거나 

-> non-interruptible (신호 차단하여 실행 방해 방지) 해야함

 

Sio 함수

-> sio_puts: 문자열 출력

-> sio_putl: 정수 출력

-> sio_error: error 메세지 출력 후 종료

 

** Pending Signal은 각 유형에 대해 최대 하나의 신호만 가능하여 

신호를 event counting (자식 종료 횟수) 에 사용할 수 없음

-> 이를 해결하기 위해 wait 함수 사용

 

Sigaction 함수

-> 이식성 good

-> main과 handler가 concurrent 하기 때문에 race가 발생할 수 있음

-> addjob과 deletejob은 동기화가 필요

-> fork 전에 block , fork 후에 unblock

 

Sigchild waiting

-> sigchild를 받을 때까지 wait하는 것은 busy waiting 이므로 cpu 낭비

-> sleep을 써도 응답성 떨어짐

-> sigsuspend(const sigset_t *mask) 사용

-> 이전 bit vector과 sig_child 전달시 wakeup