Linux

2.2. Bottom Half

aucd29 2013. 9. 26. 20:55
2.2. Bottom Half
Bottom half란 interrupt의 결과로 불려지는 커널내의 함수(routine)들의 집합이다. 프로세
스의 상태에 의존하지 않으며, sleep()과 같은 함수를 불러서 진행을 블록킹(blocking) 할
수 없다. 참고로 top half란 시스템 콜이나 트랩(trap) 1 의 결과로 생기며, 동기적
(synchronous)으로 호출되는 커널내의 함수(routine)들 이다. 프로세스와 상태에 의존적이
며, sleep()함수를 부름으로써 블록킹 할 수 있다.
인터럽트의 발생시 이를 처리하는 모든 함수들이 불려질 필요는 없다. 즉, 바쁘고 중요한
일을 처리한 다음 나중에 덜 바쁜 일을 처리해 주도록 만들어줄 수 있다. 이와 같은 대표적
인 경우로 네트워크(network)에서 발생하는 패킷(packet) 의 처리를 나중으로 미루어 둘 수
도 있을 것이다. 되도록 이면 많은 패킷을 놓치지 않고 빨리 받아서 큐에 넣어둔 다음 네트
워크 인터페이스 인터럽트를 처리했다고 알리고, 나중에 이 패킷들에 대한 처리를 다시 조
금 한가한 시간에 해주게 된다. 이럴 때 사용할 수 있는 것이 바로 bottom half이다. 따라서,
상대적으로 처리시간이 긴 것들은 이것을 이용해서 나중에 시스템에서 처리해 준다.
커널 버전(version) 2.4에서는bottom half에 대한 처리가 많이 변경되었다. 즉, 소프트웨어
IRQ의 일환으로 처리된다. Bottom half의 초기화는 ~/kernel/softirq.c의 softirq_init()에서
bh_base 배열(array)에 init_bh()함수가 bottom half 핸들러 함수를 등록시켜주는 곳에서 일
어나며, bh_acton()함수에서 bottom half에 대한 처리를 해준다. 제거는 remove_bh() 함수
가 처리한다. 모든 시스템 콜이 복귀하기 전에 softirq와 mask를 가지고 softirq가 활성
(active)인지를 확인하게 되며, 만약 그럴 경우에는 do_softirq() 함수를 불러서 softirq를
처리한다.
do_softirq() 함수는 소프트웨어 인터럽트를 처리하기 위한 함수이다.
asmlinkage void do_softirq()
{
int cpu = smp_processor_id();
__u32 active, mask;
if (in_interrupt())
return;
local_bh_disable();
local_irq_disable();
1 시스템에 오류(fault)가 발생할 때 발생한다.
mask = softirq_mask(cpu);
active = softirq_active(cpu) & mask;
먼저 현재 CPU의 ID 값을 가져오고, 인터럽트가 진행 중인지를 확인한다. 만약 진행 중이라
면 곧바로 복귀하며, 그렇지 않을 경우에는 bottom half및 인터럽트를 일어나지 못하게 만
든다. 그리고 나서 softirq의 mask와 현재 CPU에서 활성화되어있는 softirq를 가져온다.
if (active) {
struct softirq_action *h;
restart:
/* Reset active bitmask before enabling irqs */
softirq_active(cpu) &= ~active;
local_irq_enable();
h = softirq_vec;
mask &= ~active;
do {
if (active & 1)
h->action(h);
h++;
active >>= 1;
} while (active);
local_irq_disable();
active = softirq_active(cpu);
if ((active &= mask) != 0)
goto retry;
}
만약 활성화된 softirq가 있다면, 이것이 처리가 되었다는 것을 나타내주고( &~active), 현
재의 CPU에서 IRQ 가 다시 발생할 수 있도록 만들어준다. do ~ while 을 돌면서 설정된 함
수들을 하나하나 처리해나가고, 처리가 끝나면 다시 IRQ 가 발행하지 못하도록 만들어준다.
다시 처리하는 동안에 발생하였을지 모를 인터럽트에 대한 부가적인 softirq들이 활성화 되
었는지를 확인한 다음, 만약 더 있다면 다시 이것을 위한 처리 절차를 밟게 된다.
local_bh_enable();
return;
retry:
goto restart;
}
다시 bottom half를 가능(enable)하도록 만들고 복귀한다. 이때 무한 반복을 막기위해서 국
지적인(local) 하드웨어 인터럽트를 불가(disable)로 놓고 복귀함에 유의하자.
Bottom half를 위한 우선 순위는 아래와 같다. 즉, TIMER_BH가 가장 높은 우선순위를 가
지고, 이어서 TQUEUE_BH가 오게 된다. 유념해서 봐야 할 부분은 TIMER_BH,
TQUEUE_BH, IMMEDIATE_BH정도가 될 것이다.
enum {
TIMER_BH = 0,
TQUEUE_BH,
DIGI_BH,
SERIAL_BH,
RISCOM8_BH,
SPECIALIX_BH,
AURORA_BH,
ESP_BH,
SCSI_BH,
IMMEDIATE_BH,
CYCLADES_BH,
CM206_BH,
JS_BH,
MACSERIAL_BH,
ISICOM_BH
};
?? TIMER_BH는 시스템에 주기적으로 발생하는 타이머 인터럽트가 발생할 때마다 활
성화된다. (mark_bh() 함수를 이용해서)
?? TQUEUE_BH는 시스템에 주기적으로 발생하는 타이머 인터럽트에서, 테스크 큐인
tq_timer에 어떤 값이 들어있을 경우에만 do_timer()루틴에서 활성화된다.
(mark_bh() 함수를 이용해서)
?? IMMEDIATE_BH는 Immediate 큐(queue)에 들어있는 작업들을 처리하기 위한
bottom half핸들러 들을 보관한다.
나중에 이러한 값들은 Bottom half핸들러를 설치할 때 사용하게 되므로 기억하고 있는 것
이 중요하다. 이전 커널 버전인 2.2.X에 있던 CONSOLE_BH와 NET_BH가 없어졌다. 또한
do_bottom_half()같은 함수도 더 이상 보이지 않는다.