[완료] Bottomhalves...

prose2의 이미지

제가 리눅스 커널(2.6)공부를 하고있는데요,
Bottom halves쪽을 보고 있거든요.. 그런데 이해가 가지 않는게 있어서 질문을 드립니다.

처음에 인터럽트가 발생하면

1. CPU가 PC에 있는 값을 커널스택에 저장하고,
2. 벡터 테이블에서 ISR의 주소를 받아와서 처리를 하고,
3. 지연될 작업이 있으면 인터럽트 핸들러가 종료되기 전에 표시를 해서
4. Softirq 벡터 테이블에 등록을 해 주고
5. 거기에 대응된 핸들러 함수를 ksoftirqd라는 커널 스레드를 이용해서 처리를 하는것으로 알고 있는데요,

질문 1. 이 때 커널스레드에서 처리된다는 말은 데몬을 통해 백그라운드로 처리를 시켜준다는 이야기인가요?
질문 2. 이 때 softirq가 실행되는 시점은 어떻게 결정되나요?

wariua의 이미지

일단 적어주신 내용 가운데 5번 항목을 살짝 수정해야 할 것 같습니다. 모든 softirq가 ksoftirqd를 통해 처리되는 것은 아닙니다. 2.6.x 소스를 기준으로 간단하게 동작하는 걸 따라가 보자면 다음과 같습니다.

1. ~linux/arch/.../kernel/irq.c 파일에 do_IRQ() 함수가 있습니다. 네, top half쪽 인터럽트 핸들러입니다. 그 루틴 아래쪽에 보면 irq_exit()를 호출하게 되어 있습니다.

2. irq_exit() 함수는 ~linux/kernel/softirq.c에 정의되어 있습니다. 그 함수 내에선 invoke_softirq()를 호출하는데, 이는 결국 __do_softirq()를 호출하는 매크로입니다.

3. __do_softirq() 함수가 softirq 핸들러입니다. 함수 내용 가운데 h->action(h)가 특정 핸들러를 호출하는 라인이죠. 그런데 루틴을 보면 아시겠지만 핸들러 수행 직후에 다시 pending 상태의 작업이 있는 경우 앞의 동작을 반복하는데, 최대 MAX_SOFTIRQ_RESTART번까지만 반복하도록 되어 있습니다. 그만큼 반복한 후에도 pending 작업이 있으면 wakeup_softirqd()를 호출하도록 되어 있습니다.

4. wakeup_softirqd() 함수가 ksoftirqd 스레드를 활성화합니다. 함수의 주석에 나와 있듯이 ksoftirqd라는 별도의 스레드로 softirq 핸들러를 실행하는 이유는 "to avoid userspace starvation"입니다.

5. 그리하여 ksoftirqd 스레드가 하는 일은 처리가 지연된 softirq 작업을 처리하는 것입니다. 그 내용은 ksoftirqd() 함수를 보면 아시겠지만, 결국 __do_softirq()를 다시 호출하는 것입니다. 단, 우선순위가 가장 낮은 (nice == 19) 스레드로 동작하기 때문에 다른 태스크에게 실행 기회를 줄 수 있게 되지요.

왼편의 내용 검색에서 "softirq", "tasklet" 등으로 검색하면 흥미로운 내용들을 많이 찾으실 수 있을 겁니다 :-)
----
$PWD `date`

$PWD `date`

prose2의 이미지

ksoftirqd는 지연된 작업이 있을 경우 ,softirq가 자기 자신을 재활성화 해서 10개 이상 실행 하려 할 경우 기 이상의 작업들을 스타베이션을 피하기 위해 써주는거군요.(나이스 19값으로)
그렇다면 일반적인 softirq는 어떤녀석에 의해서 수행되나요?
1. 이녀석도 특별한 데몬으로 높은 우선순위의 나이스값으로 수행되는건가요? (책들을 참조하고 있지만 너무 애매해서요)
2. 그렇다면 지연되는 시점은 어떻게 결정되는건가요? (인터럽트 핸들러(top-half)가 종료되면서 지연된 작업이 있다면 바로 soft-irq를 interrupt context에서 수행해준다면 나누는 의미가 없지 않나요?)

wariua의 이미지

2번에서 말씀하신 것처럼 기본적으로 softirq 핸들러는 인터럽트 문맥에서 실행됩니다.

top half(hardirq handler) 종료 직후에 bottom half(softirq handler)가 실행된다고 해서 인터럽트 처리 루틴을 둘로 쪼갠 의미가 없지는 않습니다. hardirq handler가 실행중인 동안에는 일부 혹은 전체 인터럽트가 비활성화 되지만 softirq handler가 실행중인 동안에는 인터럽트를 막아두지 않으니까요. 아시다시피, 인터럽트를 막아두는 시간을 가능하면 줄이기 위해서 급하지 않은 처리 작업을 지연(defer)시키기 위한 것이 바로 bottom half 메커니즘입니다. 그런 의미에서 bottom half의 유형 중 하나인 softirq 핸들러는 그 목적에 충실한 셈입니다:-)
----
$PWD `date`

$PWD `date`

prose2의 이미지

얘기를 하면서도 이해가 가지 않는 부분이 몇군데 있네요..
softirq는 어떤 한 인터럽트에 관한 지연된 작업을 수행해 주는건데

어떻게 여러개의 softirq가 동시에 처리될 수 있죠?(그럴 필요가 있을까요?)
그리고 softirq_vec에 저장되어있는 softirq를 do_softirq에서 불러서 처리하는게 아닌가요? (그렇다면 softirq_vec는 32만큼의 크기 제한이 있고, 게다가 nr번째 위치에는 해당하는 종류의 softirq만 존재할텐데요..)
혹시 그럼 여러 인터럽트가 발생시킨 softirq를 주욱 모아뒀다가 동시에 동시에 실행시키는건가요? (이것도 말이 않되는데요..)
도무지 책을 봐도 이해가 가지 않고... 도와주십시오.ㅜ_ㅜ

wariua의 이미지

풀어 쓰자면, 인터럽트의 top half 처리 직후에 softirq가 실행된다면 처리해야 할 작업은 직전의 인터럽트에 의해 생긴 것 하나뿐일 텐데, 왜 __do_softirq() 함수에서는 최대 10번(MAX_SOFTIRQ_RESTART)까지 softirq 처리 루틴을 반복하도록 되어 있느냐는 말씀이신가요?

(말씀하신 걸 제대로 이해했는지 자신이 없군요. 일단 그럭저럭 이해했다고 가정하고 얘기를 진행해 나가겠습니다.)

이유인즉, softirq 처리 루틴이 실행되고 있는 도중에 인터럽트가 발생할 수 있기 때문입니다. softirq 처리 루틴이 실행중인 동안 인터럽트가 발생하면 CPU 제어는 다시 hardirq 핸들러로 넘어가고, 핸들러 실행이 완료되면 (이번에는 softirq 처리가 이뤄지지 않은 채) 좀 전에 중단되었던 softirq 처리 루틴으로 제어가 넘어와서 실행이 계속됩니다. 그러면 그 softirq 처리 루틴의 실행이 끝났을 때 또 다른 softirq 작업이 남아있을 겁니다. (즉, local_softirq_pending()의 리턴값이 0이 아닐 겁니다.) 그러면 다시 반복해서 그 softirq 작업을 처리합니다.

softirq 핸들러는 상당히 짧아서 금방 수행이 끝날 수도 있지만 경우에 따라서는 수백 us 동안이나 실행될 수도 있습니다. 그렇다면 실행 도중에 인터럽트가 여럿 발생할 수 있겠지요.

한편으로, 처리 과정에서 다른 인터럽트가 발생하지 않는다고 하더라도 softirq 처리 과정에서 새로운 softirq 작업이 추가되는 경우도 있습니다. 가령 네트워크 입력을 처리하는 softirq(NET_RX_SOFTIRQ) 핸들러가 그 패킷을 다른 네트워크 인터페이스로 내보내는 경우, softirq 작업이 끝나기 직전에 패킷 전송을 완료한 네트워크 장치가 인터럽트를 발생시켜서 연이어 NET_TX_SOFTIRQ 처리를 해야 할 수도 있습니다.

----

얘기가 좀 복잡해질 것 같으면 제게 이메일을 주셔도 됩니다. 제 아이디 클릭하신 다음에 연락처 탭을 누르시면 메일 보내기 양식이 표시됩니다. 보내기를 하시면 가입하실 때 입력하신 이메일 주소를 이용해서 제게 이메일이 발송됩니다.

----
$PWD `date`

$PWD `date`

익명사용자의 이미지

아.. 그런것이었군요... 감사합니다...
말씀 해 주신 부분까지는 정확히 이해 했습니다.
그렇다면 한가지 또 의문이 생기는데요,

위에 글을 보시면 지연된 작업을 수행하는 루틴이 do_irq에 의해 호출된다고 하셨잖아요? (종료되는 함수에 의해)

그렇다면..
제가 알고있기로 raise함수가 CPU별로 할당된 커널 스택에 현재 발생한 바텀하프를 등록해준다고 알고있는데요..
이 raise함수도 do_irq에서 종료되기 전에 호출되는것으로 알고있는데 정확한가요?

만약 그게 정확하다면 인터럽트 핸들러가 종료되기 전에
1. 바텀하프를 등록해주는 루틴을 수행해 주고,
2. 그 다음 종료되면서 바텀하프를 수행하라는 루틴을 수행해 주는건가요?

알고싶습니다..

wariua의 이미지

말씀하신 대로입니다. 사실 이 정도가 되면... 운영체제마다 구현 방식이 달라질 수 있습니다. 일단 리눅스를 기준으로 설명 드리겠습니다.

네트워크 장치로 패킷이 수신된 경우를 예로 들어 보겠습니다.

어이어이한 과정을 거쳐서 do_IRQ() 함수가 호출되고(~linux/arch/.../kernel/irq.c), 거기서 irq 핸들러를 호출합니다.

fastcall unsigned int do_IRQ(struct pt_regs *regs)
{
    ...
 
    desc->handle_irq(irq, desc);
 
    ...
}

많이 쓰는 네트워크 장치 중 하나인 rtl8139 시리즈의 경우 rtl8139_open() 함수를 통해(~linux/drivers/net/8139too.c) 인터럽트 핸들러를 등록해 둡니다. 인터럽트 핸들러인 rtl8139_interrupt() 함수에서는 처리 작업을 한 후, 이후의 패킷 수신 처리(softirq 핸들러가 하는 일)를 스케줄링합니다.

static irqreturn_t rtl8139too_interrupt (int irq, void *dev_instance)
{
    ...
 
    /* Receive packets are processed by poll routine.
       If not running start it now. */
    if (status & RxAckBits){
        if (netif_rx_schedule_prep(dev)) {
            RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
            __netif_rx_schedule (dev);
        }
    }
 
    ....
}

스케줄링을 하기 위해 호출하는 함수인 __netif_rx_schedule() 함수(~linux/net/core/dev.c)를 들여다보면 다음과 같습니다.

void __netif_rx_schedule(struct net_device *dev)
{
    ...
    __raise_softirq_irqoff(NET_RX_SOFTIRQ);
    ...
}

이런 식으로 인터럽트 핸들러 실행 과정에서 softirq 실행이 스케줄링 됩니다. 이제 다시 위로, 위로, ... do_IRQ()로 돌아가고, 거기서부터는 아시는 대로입니다.
----
$PWD `date`

$PWD `date`

prose2의 이미지

감사합니다. 와리우아(?)님 덕분에 softirq에 대한 이해가 되었습니다.
복 많이 받으실꺼에요..^^*

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.