리눅스 커널 - Process and Interrupt Context Synchronization

프로세스 컨텍스트와 인터럽트 컨텍스트에 대한 내용은 다음 페이지에서 다루었다: 프로세스/인터럽트 컨텍스트


프로세스 컨텍스트와 인터럽트 컨텍스트에서 같은 critical section에 접근하는 시나리오에 대해서 생각해보자. 이 시나리오에서는 데드락이 발생할 수 있는데 상황은 아래와 같다.

1. 프로세스 컨텍스트에서 스핀락을 잡는다.

2. 인터럽트가 발생하여 인터럽트 핸들러가 동작하고 스핀락을 잡으려고 한다.

위와 같은 상황에서 프로세스 컨텍스트가 스핀락을 해제해야 하는데, 인터럽트 핸들러에 의해 CPU를 빼앗겨 스핀락을 해제할 수 없다. 인터럽트 핸들러는 스핀락을 잡을 수 없다. 아래 그림에서 Problem situation에 해당한다.

이러한 데드락 상황을 피하기 위해서, 프로세스 컨텍스트에서 인터럽트를 disable 후 스핀락을 얻으면 된다. 아래 그림의 Solution에 해당한다. spin_lock_irqsave() 함수로 현재 인터럽트 상태(disable이었는지 enable이었는지)를 저장하고 인터럽트를 disable 한 뒤 스핀락을 획득한다. spin_unlock_irqrestore()는 스핀락을 해제하고 저장해놨던 이전 인터럽트 상태를 복원한다.


이야기를 더 진행하기 위해 먼저 bottom half context를 소개한다. 이 컨텍스트는 인터럽트 컨텍스트의 일종인데, 인터럽트는 enable 되어 있고 블로킹 함수는 부르면 안 되는 상태이다. 인터럽트 핸들러에서 전반부 작업이 끝나고 나서 도는 softirqs와 tasklets이 bottom half context에서 도는 것이다 (이후에 ksoftirqd에 의해 도는 softirq는 프로세스 컨텍스트에서 돈다.).

Bottom half context와 critical section을 공유하는 프로세스 컨텍스트의 경우 spin_lock_bh() 함수로 스핀락을 잡아야 한다 (ksoftirqd에 의해 도는 softirq는 spin_lock()으로 잡는다.). spin_lock_bh()는 내부적으로 __local_bh_disable_ip()를 부르게 되고, 이 함수는 bottom half 처리를 비활성화한다.
즉, 인터럽트 핸들러에 의해 softirq가 껴들어서 스핀락을 잡는 데드락 상황을 피하기 위해 bottom half 처리를 비활성화하고 스핀락을 잡는 것이다.

아래 그림에서 위 내용에 대한 데드락 상황 및 solution을 표현하였다.


Bottom half context에서는 spin_lock() 함수나 spin_lock_irqsave() 함수(인터럽트 핸들러와 데이터 공유하는 경우, 인터럽트를 disable 하고 스핀락을 잡음)로 스핀락을 잡는다.
아래 그림에서 데드락 상황과 solution을 나타냈다.

추가적으로, 스핀락을 얻을 때 내부적으로 preemption을 disable 시켜 스핀락을 얻은 상태에서 다른 프로세스에 의해 선점되는 것을 막는다.

댓글