ARM Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

200239
1625
172597


[리눅스커널] 프로세스: thread_info 구조체 - cpu 필드에 대한 상세 분석 4. 프로세스(Process) 관리

thread_info 구조체의 cpu 필드는 프로세스가 실행 중인 CPU 번호를 저장합니다. 그러면 현재 코드가 어떤 CPU에서 구동 중인지 알려면 어떤 함수를 써야 할까요? 커널에서 제공하는 smp_processor_id() 함수를 호출하면 됩니다. 

smp_processor_id() 함수 분석

smp_processor_id() 함수를 보면서 세부 동작 방식을 확인해보겠습니다.

https://elixir.bootlin.com/linux/v4.19.30/source/include/linux/smp.h
1 # define smp_processor_id() raw_smp_processor_id()

https://elixir.bootlin.com/linux/v4.19.30/source/arch/arm/include/asm/smp.h
2 #define raw_smp_processor_id() (current_thread_info()->cpu)

선언부로 봐서 smp_processor_id() 함수는 매크로 타입의 함수임을 알 수 있습니다.

1~2번째 줄을 보면 smp_processor_id() 함수는 raw_smp_processor_id() 함수로 치환됩니다. 이어서 raw_smp_processor_id() 함수를 보면 current_thread_info()->cpu 코드로 치환된다는 사실을 알 수 있습니다.

위 선언부를 통해 알아본 smp_processor_id() 매크로 함수의 실체는 다음과 같습니다.

smp_processor_id() 
raw_smp_processor_id()
(current_thread_info()->cpu)

current_thread_info() 함수는 실행 중인 프로세스 스택의 주소를 읽어서 프로세스 스택의 최상단 주소를 얻어옵니다.

---
current_thread_info() 함수의 코드 분석은 4.10.2절에서 확인할 수 있습니다.
---

이번에는 smp_processor_id() 함수를 써서 현재 실행 중인 코드가 어떤 CPU에서 실행 중인지 식별하는 코드를 살펴보겠습니다. 

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/core.c
01 void resched_curr(struct rq *rq)
02 {
03 struct task_struct *curr = rq->curr;
04 int cpu;
...
05 cpu = cpu_of(rq);
06 
07 if (cpu == smp_processor_id()) {
08 set_tsk_need_resched(curr);
09 set_preempt_need_resched();
10 return;
11 }

5번째 줄에서는 함수의 인자인 런큐 구조체에서 런큐 CPU 번호를 cpu 지역변수에 저장합니다. 7번째 줄에서는 smp_processor_id() 함수를 호출해서 현재 wake_up_idle_cpu() 함수가 몇 번 CPU에서 실행 중인지 확인합니다. 이때 현재 실행 중인 CPU 번호와 런큐 CPU 번호가 같으면 8~9번째 줄을 실행하고 함수 실행을 종료합니다.

참고로 67번째 줄의 매크로를 풀어서 실제 동작하는 코드로 바꾸면 아래 코드와 같습니다.
if (cpu == current_thread_info()->cpu) {

smp_processor_id() 함수의 전체 흐름 파악
커널의 다양한 코드에서 smp_processor_id() 함수를 호출해 현재 실행 중인 CPU 번호를 읽습니다. 이번에는 resched_curr() 함수에서 smp_processor_id() 함수를 호출했을 때의 실행 흐름을 확인해 봅시다.

 
그림 4.20 실행 중인 CPU 번호를 로딩하는 smp_processor() 함수의 실행 흐름


위 함수 콜스택은 라즈베리 파이의 라즈비안에서 확인한 것입니다. SDIO 드라이버에서 워크 핸들러인 brcmf_sdio_dataworker() 함수를 실행합니다. 이 후 __wake_up() 함수를 호출해 프로세스 스케줄링 요청을 수행하는 resched_curr() 함수를 실행합니다.


그림 4.20에서 볼 수 있듯이 resched_curr() 함수에서 smp_processor_id() 함수를 호출하면 실행 중인 프로세스 스택의 최상단 주소에 접근해서 cpu라는 필드를 읽어 옵니다.

set_task_cpu() 함수 분석

실행 중인CPU 번호를 저장하는 thread_info 구조체의 cpu 필드는 set_task_cpu() 함수가 호출될 때 변경됩니다. set_task_cpu() 함수를 보면서 세부 동작 방식을 분석해보겠습니다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/core.c
void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
{
...
__set_task_cpu(p, new_cpu);
}

set_task_cpu() 함수에서는 두 번째 인자인 new_cpu를 __set_task_cpu() 함수로 전달하며 호출합니다.

이어서 __set_task_cpu() 함수를 보겠습니다.

https://elixir.bootlin.com/linux/v4.19.30/source/kernel/sched/sched.h
static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
{
...
task_thread_info(p)->cpu = cpu;

task_thread_info() 함수는 태스크 디스크립터를 입력으로 받아 프로세스 스택의 최상단 주소를 반환합니다. thread_info 구조체의 cpu 필드에 매개변수로 전달된 cpu를 저장합니다.

정리하면 set_task_cpu() 함수를 실행하면 다음과 같은 동작을 수행합니다. 

프로세스 스택의 최상단 주소에 접근
thread_info 구조체의 cpu 필드에 실행 중인 cpu 인자의 값을 저장 

그림 4.21을 보면서 set_task_cpu() 함수의 실행 흐름을 확인해 보겠습니다.


 
그림 4.21 실행 중인 CPU 번호를 저장하는 set_task_cpu() 함수의 흐름

set_task_cpu() 함수를 호출하면 __set_task_cpu() 함수를 호출합니다. 이때 프로세스 스택의 최상단 주소에 접근해 thread_info 구조체의 cpu 필드에 cpu 번호를 저장합니다. 그림 4.21에서는 4를 CPU 번호로 지정합니다.

지금까지 thread_info 구조체의 세부 필드가 어떻게 바뀌는지 살펴봤습니다. 코드 분석을 토대로 태스크 디스크립터보다 thread_info 구조체가 프로세스 세부 동작을 저장하는 역할을 수행한다는 사실을 확인했습니다.

다음 절에서는 프로세스가 생성될 때 thread_info 구조체를 초기화하는 과정을 알아보겠습니다.

* 유튜브 강의 동영상도 있으니 같이 들으시면 좋습니다. 




#프로세스

프로세스 소개 
프로세스 확인하기  
프로세스는 어떻게 생성할까?  
유저 레벨 프로세스 실행 실습  
커널 스레드  
커널 내부 프로세스의 생성 과정   
프로세스의 종료 과정 분석  
태스크 디스크립터(task_struct 구조체)  
스레드 정보: thread_info 구조체  
프로세스의 태스크 디스크립터에 접근하는 매크로 함수  
프로세스 디버깅  
   * glibc의 fork() 함수를 gdb로 디버깅하기  


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

Thanks,
Austin Kim(austindh.kim@gmail.com)


# Reference: For more information on 'Linux Kernel';

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2




핑백

덧글

  • 2020/04/28 02:28 # 삭제 답글 비공개

    비공개 덧글입니다.
  • AustinKim 2020/04/28 10:16 #

    1. 이 책을 읽을 수 있는지 ...

    * C 언어만 이해하면 '디버깅을 통해 배우는 리눅스 커널의 구조와 원리'이란 책을 읽고 이해할 수 있도록 구성해서 무리는 없을 것 같습니다.

    * 시스템 프로그래밍을 하시다가 커널이 어떻게 동작하는지 궁금하실 시점에 이 책을 보시면 더 좋을 것 같습니다.
    어떤 주제에 대해 등떠 밀려서 공부하는 것보다 뭔가 알고 싶단 호기심이 있을 때 더 빨리 배울 수 있거든요.

    2. 안드로이드 커널에 대해서..

    * 안드로이드 커널은 리눅스 커널의 소스 코드를 가져다가 안드로이드 구조에 맞게 커스터마이즈한 커널입니다.
    라즈베이 파이의 리눅스 커널과 우분투의 커널도 마찬가지입니다. 리눅스 커널 소스를 라즈베리 파이, 우분투에 맞게 커스터마이즈한 거죠.

    다음 공식으로 이해하면 무방합니다.
    * 안드로이드 커널 = 리눅스 커널 + 안드로이드에 맞게 구현된 리눅스 드라이버

    3. GDB를 사용하는지

    * 리눅스 개발자들은 GDB를 많이 사용합니다.

    4. 실력 있는 리눅스 개발자분들은 윈도 커널 관련해서도 공부를 하면 금방 적응

    * 리눅스 커널의 고수들은 윈도 커널을 접하면 쉽게 적응할 가능성이 매우 높습니다.
    프로세스나 인터럽트에 대한 동작은 운영체제마다 구현 방식은 다르나 기본 동작 원리는 비슷한 경우가 많기 때문입니다.

    (그런데 리눅스 커널의 고수들 중에 윈도 커널을 배우려는 분은 사실 상 거의 없습니다.
    요즘 운영체제의 대세가 리눅스로 넘어온지 오래라, 리눅스 프로젝트에서도 할 일이 많이 때문이죠.)

    5. ,window nt, max os, ios 커널은 어떻게 분석

    * 위에 언급된 운영체제는 소스 코드가 오픈돼 있지 않습니다.
    따라서 마이크로소프트나 애플의 커널 개발자 이외의 일반인은 위에 언급된 커널을 소스 코드 레벨로 분석할 수 없습니다.

    충분히 답을 드렸는지 모르겠네요. 즐거운 하루 보내시고 더 궁금하신 점이 있으면 댓글을 주시면 됩니다.

    Thanks,
    Austin Kim
  • AustinKim 2020/04/28 10:17 # 답글

    1. 이 책을 읽을 수 있는지 ...

    * C 언어만 이해하면 '디버깅을 통해 배우는 리눅스 커널의 구조와 원리'이란 책을 읽고 이해할 수 있도록 구성해서 무리는 없을 것 같습니다.

    * 시스템 프로그래밍을 하시다가 커널이 어떻게 동작하는지 궁금하실 시점에 이 책을 보시면 더 좋을 것 같습니다.
    어떤 주제에 대해 등떠 밀려서 공부하는 것보다 뭔가 알고 싶단 호기심이 있을 때 더 빨리 배울 수 있거든요.

    2. 안드로이드 커널에 대해서..

    * 안드로이드 커널은 리눅스 커널의 소스 코드를 가져다가 안드로이드 구조에 맞게 커스터마이즈한 커널입니다.
    라즈베이 파이의 리눅스 커널과 우분투의 커널도 마찬가지입니다. 리눅스 커널 소스를 라즈베리 파이, 우분투에 맞게 커스터마이즈한 거죠.

    다음 공식으로 이해하면 무방합니다.
    * 안드로이드 커널 = 리눅스 커널 + 안드로이드에 맞게 구현된 리눅스 드라이버

    3. GDB를 사용하는지

    * 리눅스 개발자들은 GDB를 많이 사용합니다.

    4. 실력 있는 리눅스 개발자분들은 윈도 커널 관련해서도 공부를 하면 금방 적응

    * 리눅스 커널의 고수들은 윈도 커널을 접하면 쉽게 적응할 가능성이 매우 높습니다.
    프로세스나 인터럽트에 대한 동작은 운영체제마다 구현 방식은 다르나 기본 동작 원리는 비슷한 경우가 많기 때문입니다.

    (그런데 리눅스 커널의 고수들 중에 윈도 커널을 배우려는 분은 사실 상 거의 없습니다.
    요즘 운영체제의 대세가 리눅스로 넘어온지 오래라, 리눅스 프로젝트에서도 할 일이 많이 때문이죠.)

    5. ,window nt, max os, ios 커널은 어떻게 분석

    * 위에 언급된 운영체제는 소스 코드가 오픈돼 있지 않습니다.
    따라서 마이크로소프트나 애플의 커널 개발자 이외의 일반인은 위에 언급된 커널을 소스 코드 레벨로 분석할 수 없습니다.

    충분히 답을 드렸는지 모르겠네요. 즐거운 하루 보내시고 더 궁금하신 점이 있으면 댓글을 주시면 됩니다.

    Thanks,
    Austin Kim
댓글 입력 영역