2011. 10. 13. 20:01
softirq 구현, 핸들러, 실행 OS이야기2011. 10. 13. 20:01
<linux/interrupt.h>에 정의된 softirq_action 구조체로 표현된다.
struct softirq_action
{
*즉, softirq_vec과 pending은 1:1로 매핑되어 있다. pending의 j번째 비트가 1이면 softirq_vec의 j번째 softirq_action을 수행하게 된다.(h->action(h))
1.지역변수인 pending의 값을 softirq_pending() 매크로의 리턴값으로 설정한다. 이것은 지연된 softirq의 32비트 마스크이다. 즉 n번째 비트가 1이면 n번째 softirq가 지연되어 있는 식이다.
2. 이제 지연된 softirq으 비트마스크를 다른 곳에 저장해두었으므로 원래 비트마스크를 초기화한다.
3. 포인터 h를 softirq_vec 배열의 첫번째 요소로 설정한다.
4. pending의 첫번째 비트가 1인 경우 h->action(h)를 호출한다.
5. 포인터 h를 하나만큼 증가시켜 softirq_vec 배열의 다음 요소를 가르키도록 한다.
6. 비트 마스크 pending을 1비트만큼 우츨으로 쉬프트한다. 그러면 첫번째 비트가 소실되고 다른 모든 비트가 우측으로 이동된다. 결과적으로 두 번째 비트가 첫번째의 위치에 갖게 되었으므로 이전 단계를 반복한다.
7. 이제 포인터 h는 배열의 두 번째 요소르르, 비트 마스크 pending은 두 번째 비트를 첫번째 위치에 갖게 되었으므로 이전 단계를 반복한다.
8. pending이 0이 될떄까지, 즉, 더이상 지연작업이 없을 떄까지 이 작업을 반복한다. 이렇게 비트 마스크 pending을 검사하는것이 포인터 h가 항상 softirq_vec배열의 유효한 요소를 가리킴을 보장하는데 충분함을 유의하자.
struct softirq_action
{
void (*action)(struct softirq_action *); //실행할 함수
void *data; //함수에 넘길 데이터
void *data; //함수에 넘길 데이터
}
kernel/softirq.c에 정의되어있다.
static struct softirq_action softirq_vec[32];
softirq의 실행
- 등록된 softirq는 실행도기 전에 반드시 표시되어야 한다.
- 이것은 softirq를 레이즈한다고 부른다.
- 일반적으로 인터럽트 핸들러는 리턴하기 직전 자신의 softirq를 실행할 것이라고 표시한다.
- 그러면 적당한 시간 뒤에 softirq가 실행된다.
- 실행하기 위한 지연된 softirq의 체크는 다음과 같은 경우 이뤄진다.
1. 하드웨어 인터럽트를 처리한 후
2. 커널 스레드 ksoftirqd에 의해
3. 네트워크 서브시트테멩서와 같이, 코드에서 직접 지연된 softirq를 검사하여 실행하는 경우
- 어떤 경우이든 softirq는 do_softirq() 안에서 실행된다. 이 함수는 매우 간단함. 지연된 softirq가 있을 경우 do_softirq() 루프를 돌면서 각 지연 softirq에 대한 핸들러를 호출한다. 다음에서 do_softirq()의 중요한 부분을 간략히 살펴보면
u32 pending = softirq_pending(cpu);
if(pending){
kernel/softirq.c에 정의되어있다.
static struct softirq_action softirq_vec[32];
softirq의 실행
- 등록된 softirq는 실행도기 전에 반드시 표시되어야 한다.
- 이것은 softirq를 레이즈한다고 부른다.
- 일반적으로 인터럽트 핸들러는 리턴하기 직전 자신의 softirq를 실행할 것이라고 표시한다.
- 그러면 적당한 시간 뒤에 softirq가 실행된다.
- 실행하기 위한 지연된 softirq의 체크는 다음과 같은 경우 이뤄진다.
1. 하드웨어 인터럽트를 처리한 후
2. 커널 스레드 ksoftirqd에 의해
3. 네트워크 서브시트테멩서와 같이, 코드에서 직접 지연된 softirq를 검사하여 실행하는 경우
- 어떤 경우이든 softirq는 do_softirq() 안에서 실행된다. 이 함수는 매우 간단함. 지연된 softirq가 있을 경우 do_softirq() 루프를 돌면서 각 지연 softirq에 대한 핸들러를 호출한다. 다음에서 do_softirq()의 중요한 부분을 간략히 살펴보면
u32 pending = softirq_pending(cpu);
if(pending){
struct softirq_action *h = softirq_vec;
softirq_pending(cpu) = 0;
do{
do{
if(pending & 1) //우측 첫번째 비트가 1이면
h->action(h); //softirq실행
h++; //다음 배열의 원소로 이동
pending >>= 1; //다음비트 검사하기 위해 우측으로 쉬프트
}while(pending);
}
h++; //다음 배열의 원소로 이동
pending >>= 1; //다음비트 검사하기 위해 우측으로 쉬프트
}while(pending);
}
*즉, softirq_vec과 pending은 1:1로 매핑되어 있다. pending의 j번째 비트가 1이면 softirq_vec의 j번째 softirq_action을 수행하게 된다.(h->action(h))
1.지역변수인 pending의 값을 softirq_pending() 매크로의 리턴값으로 설정한다. 이것은 지연된 softirq의 32비트 마스크이다. 즉 n번째 비트가 1이면 n번째 softirq가 지연되어 있는 식이다.
2. 이제 지연된 softirq으 비트마스크를 다른 곳에 저장해두었으므로 원래 비트마스크를 초기화한다.
3. 포인터 h를 softirq_vec 배열의 첫번째 요소로 설정한다.
4. pending의 첫번째 비트가 1인 경우 h->action(h)를 호출한다.
5. 포인터 h를 하나만큼 증가시켜 softirq_vec 배열의 다음 요소를 가르키도록 한다.
6. 비트 마스크 pending을 1비트만큼 우츨으로 쉬프트한다. 그러면 첫번째 비트가 소실되고 다른 모든 비트가 우측으로 이동된다. 결과적으로 두 번째 비트가 첫번째의 위치에 갖게 되었으므로 이전 단계를 반복한다.
7. 이제 포인터 h는 배열의 두 번째 요소르르, 비트 마스크 pending은 두 번째 비트를 첫번째 위치에 갖게 되었으므로 이전 단계를 반복한다.
8. pending이 0이 될떄까지, 즉, 더이상 지연작업이 없을 떄까지 이 작업을 반복한다. 이렇게 비트 마스크 pending을 검사하는것이 포인터 h가 항상 softirq_vec배열의 유효한 요소를 가리킴을 보장하는데 충분함을 유의하자.
'OS이야기' 카테고리의 다른 글
softirq 새 핸들러 등록 (0) | 2011.10.13 |
---|---|
softirq 사용 (0) | 2011.10.13 |
Bottom Half (0) | 2011.10.13 |
인터럽트 핸들링구현 (0) | 2011.10.13 |
인터럽트 컨텍스트 (0) | 2011.10.13 |