안녕하세요.
이전 글에서는 프로세스를 관리하는 자료 구조로 task_struct, thread_info 구조체를 확인했습니다.
커널 입장에서는 프로세스 속성 정보가 있는 이 구조체에 자주 접근해서 프로세스를 처리가 필요합니다. 그런데 디바이스 드라이버 코드에서는 이 구조체에 접근하지 못하게 하고 있으나 매크로 함수(current_thread_info(), current)로 대신 접근할 수 있게 하고 있습니다.
1. current 매크로
current 매크로의 제공 배경은 책에서 설명 있긴한데, 여기서는 간단하게 요약하자면 시스템에 영향을 주지 않는 형태로 태스크 디스크립터의 주소에 접근하는 매크로를 필요 요구사항에 의해 만들어졌다고 합니다.
current 매크로는 현재 구동 중인 프로세스의 태스크 디스크립터 주소를 알려주므로 직접 태스크 디스크립터 필드에 접근할 수 있습니다.
1) current 매크로 함수 사용 하는 함수 확인 1
파일 디스크립트를 할당하는 get_unused_fd_flags() 함수의 545번 줄을 보면 current 매크로로 current->files 필드에 접근해서 __alloc_fd() 함수의 첫 번째 인자로 사용하고 있습니다.
linux# vim fs/file.c
currunt 매크로가 task_struct 구조체 주소를 포인터 형태로 반환하기에 files 필드에 접근할 수 있습니다.
2) current 매크로 함수 사용 하는 함수 확인 2
더 이상 필요하지 않은 task_struct 구조체를 정리하고 메모리를 해제하는 역할을 하는 __put_task_struct() 함수의 683번 줄을 보면 전달된 tsk 인자와 current가 같은지 검사합니다.
3) current 매크로 함수 내부 확인
위에서 대략 이렇게 사용되고 있구나 확인했다면, 어떻게 구현되어 있는지 확인해보겠습니다.
current 매크로 함수는 current.h 파일에 구현부가 있습니다.
linux# vim include/asm-generic/current.h
7번 줄을 보면 get_current() 함수로 치환되고 1번 줄을 보면 current_thread_info()->task로 치환됩니다.
여기서 ccurrent_thread_info() 함수는 thread_info 구조체의 시작 주소이며 그중 task 필드에는 프로세스의 태스크 디스크립터 주소를 반환합니다.
4) current_thread_info() 매크로 함수 내부 확인
current_thread_info() 매크로 함수의 프로세스가 실행 중일 때 thread_info 구조체가 있는 스택의 최상단 주소를 계산해서 반환합니다.
81번 줄을 보면 asm("sp") 어셈블리 명령어로 현재 실행 중인 프로세스 스택 주소를 전역변수에 저장합니다. 그리고 90, 91번 줄에서 THREAD_SIZE 즉, 스택사이즈 여기서는 0x2000을 기준으로 비트 연산을 통해 최상단 주소를 계산합니다.
커널이 프로세스 스택 주소를 할당할 때 0x2000 바이트를 기준으로 정렬을 맞춰서 할 당하기 때문에 아래와 같은 규칙으로 계산이 가능합니다.
스택주소 예)
0xD000 2248 & 0xE000 = 0xD000 2000
0xD000 3248 & 0xE000 = 0xD000 2000
0xD000 4248 & 0xE000 = 0xD000 4000
0xD000 5248 & 0xE000 = 0xD000 4000
감사합니다.
<참고 자료>
1. [도서] 디버깅을 통해 배우는 리눅스 커널의 구조와 원리 p252 ~ 259, wikibook