Linux Kernel(4.19) Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

83235
1036
103653


[리눅스커널] 커널동기화: 레이스 컨디션은 왜 발생할까? 9장. 커널동기화(스핀락/뮤텍스)

이전 소절에서 레이스 컨디션과 임계 영역의 개념에 대해서 소개했습니다. 이 내용을 읽으니 자연스럽게 다음과 같은 의문이 생깁니다.

   " 레이스 컨디션과 동시성은 왜 발생할까?"

이번 시간에는 그 이유에 대해 살펴보겠습니다.

SMP(symmetric multiprocessing)
레이스 컨디션이 발생하는 첫 번째 이유는 리눅스 시스템에서 SMP(symmetric multiprocessing)를 적용하기 때문입니다. 여기서 SMP란 무엇일까요?

   "하나의 시스템에 다수의 CPU가 한 개의 메모리를 쓰는 컴퓨터 시스템 아키텍처이다."

이렇게 SMP에 대한 정의를 읽고 나면 SMP를 적용한 후 레이스 컨디션이 왜 발생하는지 잘 이해가 가지 않습니다. 소프트웨어적 보면 SMP 시스템에서는 다음과 같이 실행을 한다고 볼 수 있습니다.

   "다수의 CPU에서 병렬로 프로세스가 실행을 한다.

만약 리눅스 시스템에 CPU 4개를 탑재한 SMP 시스템에서는 4개의 CPU에서 병렬로 서로 다른 프로세스들이 실행할 수 있는 것입니다. 이는 다음과 같은 상황을 초래합니다.

   "서로 다른 CPU에서 실행 중인 프로세스가 같은 코드나 함수에 접근할 수 있다."

이런 현상을 동시성(Concurrency)이라고 말합니다. 달리 보면 SMP 시스템은 동시성이 발생할 수 밖에 없는 조건입니다.

현재 대부분 리눅스 시스템은 SMP 환경에서 구동합니다. 여러분이 쓰고 있는 휴대폰을 포함해 대부분 리눅스는 SMP 시스템에서 실행합니다. 라즈베리파이도 쿼드코어 CPU(4개 CPU)를 사용합니다. 

선점 스케줄링 
레이스가 발생하는 두 번째 요인은 리눅스 커널이 선점 스케줄링을 지원하기 때문입니다. 현재 대부분 리눅스 커널은 선점형 스케줄링 환경에서 실행되며 이를 다음과 같이 말할 수 있습니다.

   "우리가 입력한 코드 블락이 실행되는 도중 선점 스케줄링될 수 있다. "

이 내용을 읽고 나면 자연히 다음과 같은 의문이 생깁니다.

   "선점 스케줄링으로 레이스 컨디션이 발생할까? " 

선점 스케줄링으로 다양한 레이스가 발생할 수 있습니다. 이해를 위해 한 가지 예를 들어보겠습니다. 여러분이 작성한 코드가 rpi_set_synchronize() 함수에서 실행 중이라고 가정하겠습니다. A 프로세스가 rpi_set_synchronize() 함수 실행 도중 선점 스케줄링이 된 후 B 프로세스가 다시 rpi_set_synchronize() 함수를 호출하면 어떻게 될까요? 중요한 자료 구조를 처리하는 코드 구간을 B 프로세스가 다시 실행한다면 레이스가 발생할 수 있습니다.

선점 스케줄링이 발생해 다른 프로세스가 rpi_set_synchronize() 함수를 호출하지 않아도 다른 문제를 겪을 수 있습니다. 만약 rpi_set_synchronize() 함수 내에서 알고리즘 연산이나 정확한 딜레이를 주는 코드를 실행 중이라고 가정하겠습니다. 이 때 선점 스케줄링으로 실행하는 코드를 멈추고 다른 프로세스로 스케줄링되면 오동작을 유발할 수 있습니다.

이렇게 동시성이 발생하는 원인 중 하나가 선점 스케줄링입니다. 

인터럽트 발생 
어떤 CPU에서도 인터럽트는 언제든 발생할 수 있습니다. 여러분이 작성한 코드가 실행 도중 인터럽트가 발생하면 실행을 멈추고 인터럽트 핸들러를 호출할 수 있습니다. 만약 rpi_set_synchronize() 함수 실행 도중 인터럽트가 발생 해 다시 rpi_set_synchronize() 함수에 진입하면 어떻게 될까요? 이 상황도 체크해야 할 것입니다.

유저 프로세스에서 스레드 핸들링 
유저 어플리케이션에서 스레드를 생성해 한 개의 파일을 다수의 스레드가 접근할 수 있습니다.
이 과정에서 동시성 혹은 레이스 컨디션이 발생할 수 있습니다.

동시성 발생 사례 소개
임베디드 리눅스를 처음 접하는 분들은 동시성 문제가 왜 발생하는지 감이 잘 안옵니다. 이해를 돕기 위해 리눅스 커널 커뮤니티에서 SMP 환경에서 동시성 문제가 발생하는 사례를 소개하겠습니다.

먼저 첫 번째 사례를 소개합니다.
[https://lore.kernel.org/patchwork/patch/901442/]
01         CPU0                    CPU1
02         ----                    ----
03    lock(&mm->mmap_sem);
04                                 lock(bpf_event_mutex);
05                                 lock(&mm->mmap_sem);
06    lock(bpf_event_mutex);
07
08   *** DEADLOCK ***

03번째 줄을 보면 CPU0에서 &mm->mmap_sem으로 락을 걸고 있습니다.
락을 거는 구간에서 05번째 줄과 같이 CPU1이 &mm->mmap_sem으로 락을 다시 걸고 있습니다. 

이번에는 다른 사례입니다.
[https://lore.kernel.org/patchwork/patch/880120/]
01 CPU0                                    CPU1
02 mmap syscall                           ioctl syscall
03 -> mmap_sem (acquired)                 -> ashmem_ioctl
04 -> ashmem_mmap                            -> ashmem_mutex (acquired)
05    -> ashmem_mutex (try to acquire)       -> copy_from_user
06                                              -> mmap_sem (try to acquire)

03번째 줄에서 CPU0이 mmap_sem() 함수에 접근해 락을 획득했습니다.
그런데 거의 동시에 CPU1에서 06번째 줄과 같이 mmap_sem() 함수에 접근하고 있습니다.

두 가지 사례의 공통점은 다음과 같습니다. 

   "2개 이상 CPU에서 실행 중인 프로세스가 동시에 같은 코드 블락을 실행한다. "

여기까지 2개 CPU에서 실행 중인 프로세스가 같은 코드 블록에 동시에 접근하는 사례를 살펴봤습니다. 그런데 이 부분을 읽은 독자분들은 다음과 같이 불만을 토로할 수 있습니다.

   "문제의 원인과 해결 방법에 대해 조금 더 자세히 설명할 수는 없나?"

이번에는 2개 CPU가 같은 코드 블락을 실행할 수 있다는 사실에 초점을 맞춰 설명을 드렸습니다. 이어서 다음 소절에서 리눅스 커뮤니티에서 논의된 레이스 관련 패치를 분석하면서 레이스에 대해 더 알아보겠습니다.


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

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

#Reference(커널 동기화)
커널 동기화 기본 개념 소개
레이스 발생 동작 확인
커널 동기화 기법 소개
스핀락
뮤텍스란
커널 동기화 디버깅




핑백

덧글

댓글 입력 영역