Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

103258
1323
114605


[리눅스커널] 시그널: 유저 공간에서 pause() 함수 호출 시 커널 실행 흐름 파악하기 12. Signal

유저 공간에서 pause() 함수를 호출하면 커널 공간에서 어떤 함수가 실행할까요? 다음 시그널 설정 흐름도에서 가장 하단에 표시된 박스를 확인합시다.
 
[그림 ] 유저 공간에서 pause() 함수 호출 시 실행 흐름도

pause() 함수는 시그널을 기다릴 때 호출합니다.

라즈베리파이에서 다음 명령어를 입력해 pause 명령어에 대한 매뉴얼을 확인합시다. 
root@raspberrypi:/home/pi# info pause
PAUSE(2)                  Linux Programmer's Manual                 PAUSE(2)
NAME         top
       pause - wait for signal

매뉴얼에서 출력하는 결과와 같이 시그널을 기다리는 역할을 수행합니다.

시스템 콜 발생으로 sys_pause() 함수 호출 과정
이번엔 pause() 함수를 유저 공간에서 실행했을 때 커널에서 실행 흐름을 다른 각도로 살펴봅시다.
 
[그림 ] 유저 공간에서 pause() 함수 호출 시 시스템 콜 발생 흐름도

위 그림과 같이 유저 공간에서 pause() 함수를 호출하면 해당 시스템 콜 핸들러인 sys_pause() 함수가 실행합니다. 유저 공간과 커널 공간별 처리 과정은 다음과 같습니다.

유저 공간
1. r7 레지스터에 sys_pause() 함수에 해당하는 시스템 콜 번호인 29를 지정
2. “svc 0” ARM 어셈블리 명령어로 시스템 콜 처리를 위해 소프트웨어 인터럽트를 발생해서 커널 공간 스위칭

커널 공간 
3. vector_swi 레이블 실행
4. 유저 공간에서 저장한 시스템 콜 번호인 29를 r7 레지스터에서 읽음
5. 시스템 콜 테이블인 sys_call_table 심볼에 접근해서 시스템 콜 핸들러인 sys_pause 시스템 콜 핸들러로 분기

각 단계별로 처리 과정을 살펴봤으니 이어서 소스 코드를 분석하겠습니다.

sys_pause() 함수 분석하기
pause() 함수에 대한 시스템 콜 핸들러는 sys_pause() 함수입니다. 

먼저 sys_pause() 함수 구현부를 살펴볼까요? 
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/include/linux/syscalls.h]
asmlinkage long sys_pause(void);

sys_pause() 함수 선언부를 확인하니 void형으로 인자를 받지 않는다는 사실을 알 수 있습니다.

이어서 sys_pause() 함수 코드를 보겠습니다.
[https://github.com/raspberrypi/linux/blob/rpi-4.19.y/kernel/signal.c]
1 SYSCALL_DEFINE0(pause)
2 {
3 while (!signal_pending(current)) {
4 __set_current_state(TASK_INTERRUPTIBLE);
5 schedule();
6 }
7 return -ERESTARTNOHAND;
8 }

3번째 줄 코드에서 while 문 조건을 먼저 점검합시다. signal_pending() 함수를 호출해서 false를 반환하면 4~5번째 줄 코드를 실행합니다. 그러면 signal_pending() 함수는 어떤 기능일까요?

   " 프로세스에 시그널이 전달됐으면 true, 아니면 false를 반환한다."

signal_pending() 함수의 의미를 알았으니 3~6번째 줄 코드는 다음과 같이 동작합니다.

   " 프로세스에 전달된 시그널이 없으면 프로세스를 TASK_INTERRUPTIBLE 상태로 바꾸고 
     schedule() 함수를 호출해서 휴면에 진입한다."

팬딩 시그널이란 프로세스에게 시그널이 전달되어 처리해야 할 시그널이 있는 상태를 의미합니다.

여기서 한 가지 의문이 생깁니다.

   "그러면 프로세스가 시그널을 받아서 다시 깨어나면 어떤 코드를 실행할까?" 

3번째 줄 코드를 실행합니다. 프로세스에게 시그널이 전달되면 signal_pending() 함수는 true를 반환하니 while 문을 종료한 후 7번 코드를 실행해서 –ERESTARTNOHAND를 반환합니다. 바로 sys_pause() 함수 실행을 종료한 후 ret_fast_syscall 레이블로 이동해 시그널을 받아 처리를 합니다.

이번 절에서 유저 공간에서 2개 함수 분석으로 다음 내용을 알게 됐습니다.
1. 유저 공간 sigaction() 함수 호출
  - 커널 공간에서 sys_rt_sigaction() 함수 호출
  - do_sigaction() 함수를 실행 해 시그널 설정 정보 저장
         ; 프로세스의 태스크 디스크립터 struct task_struct sighand->action[] 배열에  
        접근한 후 시그널을 설정 

2. 유저 공간 pause() 함수 호출
  - 커널 공간에서 sys_pause() 함수를 호출해 시그널을 받을 때까지 휴면에 진입

유저 공간에서 시그널 함수를 호출하면 리눅스 커널은 위와 같은 동작을 한다는 사실을 확인할 수 있습니다.


#Referene 시그널
시그널이란
시그널 설정은 어떻게 할까
시그널 생성 과정 함수 분석
프로세스는 언제 시그널을 받을까
시그널 전달과 처리는 어떻게 할까?
시그널 제어 suspend() 함수 분석 
시그널 ftrace 디버깅

"혹시 궁금점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답글 올려드리겠습니다!" 



핑백

덧글

댓글 입력 영역