8장 후반부 처리와 지연된 작업. [165] DATE

Download Report

Transcript 8장 후반부 처리와 지연된 작업. [165] DATE

8장 후반부 처리와 지연된 작업
Sang-bok, Heo
인터럽트
전반부 처리
• 실행 시간에 민감한 작업
• 하드웨어와 관련된 작업
• 다른 인터럽트가 방해해서는 안 되는 작업
후반부 처리
• 인터럽트 핸들러가 처리하지 않은 모든 관련 처리 수행
• 거의 모든 일을 후반부 처리에서 하는 것이 이상적
- 전반부 처리 – 하드웨어의 데이터를 메모리로 복사
- 후반부 처리 – 데이터를 처리 하는 것
2
왜 후반부 처리를 하는가?
왜 뒤로 미루는가?
• 인터럽트 라인을 모든 프로세서에 대해 비활성화 시킴
- 인터럽트 핸들러에서 처리할 작업의 양을 제한할 필요
• 인터럽트 비활성화 시간 최소화는 시스템 반응속도 및 성능에
영향을 미침
미루는 시기가 언제인가?
• 네트워크 트래픽 수신을 처리하는 동안에도 키 입력처리를 해야함
- 일부 작업을 ‘나중’으로 지연
• ‘나중’ : 지금이 아닌 시점
- 시스템이 덜 바쁜, 인터럽트가 활성화된 미래의 어떤 순간으로 미룸
3
후반부 처리기
BH
•
•
•
•
bottom half – 일반적인 후반부 처리를 나타내는 용어
정적으로 만들어진 32개의 후반부 처리기
전반부 처리에서 32비트 정수의 각 비트를 후반부처리기 지정
BH는 전역으로 동기화
- 서로 다른 프로세스에서도 동시에 BH 실행 불가
• 구조는 간단, 병목현상이 발생
태스트 큐(task queue)
• 커널에 몇 개의 큐를 만듦
- 큐에는 실행할 함수가 연결 리스트 형태로 저장
• 각 큐별로 정해진 특정 시간에 대기 중인 함수를 실행
• BH 인터페이스를 대체하기에 유연성 부족
• 덩치가 너무 큼
- 네트워크처럼 성능이 중요한 서브시스템에서
4
후반부 처리기
softirq
• 모든 프로세서에서 동시에 실행할 수 있는 정적으로 정의된 후반부
처리기의 모음
• 네트워크처럼 성능이 아주 중요한 경우에 유용
• 커널 컴파일 시에 정적으로 등록
태스트릿
• softirq 기반, 동적으로 생성 가능한 유연한 후반부 처리기
- 다른/같은 유형의 태스크릿 프로세서에서 동시에 실행 가능/불가
• 커널 컴파일시 동적으로 등록
워크 큐
• 프로세스 컨텍스트에서 나중에 처리할 작업을 관리하는 방법
• 간단, 유용
5
softirq
<linux/interrupt.h>
softirq 구현
• 컴파일 시에 정적으로 할당(동적으로 등록 및 제거 불가)
• softirq에 따라서 NR_SOFTIRQS 개수만큼 등록 가능
softirq 실행
• 하드웨어 인터럽트 코드가 반환되는 경우
• ksoftirqd 커널 스레드 내에서
• 네트워크 서브시스템처럼 명시적으로 코드에서 지연 상태인
softirq를 확인하고 실행하는 경우
6
softirq
softirq 사용
• 시스템에서 가장 실행시간에 민감하고 중요한 후반부 처리
- 네트워크와 블록 장치
• 태스크릿 – softirq기반으로 만듦
• 자체적으로 효율적인 락 관리 가능
인덱스 할당
태스크릿
우선순위
softirq 설명
HI_SOFTIRQ
0
높은 우선순위 태스크릿
TIMER_SOFTIRQ
1
타이머
NET_TX_SOFTIRQ
2
네트워크 패킷 송신
NET_RX_SOFTIRQ
3
네트워크 패킷 수신
BLOCK_SOFTIRQ
4
블록 장치
TASKLET_SOFTIRQ
5
일반 우선순위 태스크릿
SCHED_SOFTIRQ
6
스케줄러
HRTIMER_SOFTIRQ
7
고해상도 타이머
RCU_SOFTIRQ
8
RCU 락
7
softirq
핸들러 등록
• sofrirq 인덱스와 핸들러 함수
softirq 올림
• 인터럽트를 비활성-> softirq 올림 -> 인터럽트 상태를 복원
최적화
• 인터럽트가 이미 비활성상태라면 약간의 최적화 가능
인터럽트 핸들러 – 하드웨어 작업 수행 - softirq 올리고 종료
– do_softirq() 함수 호출 – softirq 실행
8
태스크릿
구현
• softirq 기반으로 만들어짐
- HI_SOFTIRQ, TASKLET_SOFTIRQ 두 가지 softirq 사용
태스크릿 구조체
• softirq 기반으로 만들어짐
• 핸들러 함수 : data 인자를 하나 받음
• state : 0, TASKLET_STATE_SCHED, TASKLET_STATE_RUN
- SCHED : 태스크릿이 실행을 기다리는 중
- RUN : 태스크릿 실행 중
· 최적화를 위해 다중 프로세서 시스템에서만 사용
• count : 태스크릿 참조 횟수
- 값이 0이 아니면 태스크릿은 비활성, 실행되지 않음
- 값이 0이면 활성화 상태, 실행 대기 표시가 있으면 실행
9
태스크릿
태스크릿 스케줄링
• sofrirq 올림과 같은 개념
핸들러 함수
• tasklet_action(), tasklet_hi_action()
10
태스크릿
태스크릿 사용
• 후반부 처리는 태스크릿을 이용해 구현하는 편이 좋음
• 동적/정적으로 생성 가능
• 사용하기 편하고 빠름
태스크릿 선언
• 직접 참조
- DECLARE_TASKLET(name, func, data)
· count 값이 0인 활성화 상태의 태스크릿 생성
- DECLARE_TASKLET_DISABLED(name, func, data)
· count 값이 1인 비활성화 상태의 태스크릿 생성
• 간접 참조
- tasklet_struct 구조체 t
· 초기화 : tasklet_init() 함수 이용
11
태스크릿
Ksoftirq
• softirq/태스크릿 처리는 프로세서 별로 존재하는 커널 스레드의
도움을 받음
- 너무 많은 sofrirq가 쏟아지는 경우 처리를 도와줌
• sofrirq의 문제
- 재등록된 sofrirq를 적절한 시기에 처리하지 못하는 것
- 프로세서 시간을 얻지 못하는 일이 발생
· softirq 발생 빈도, softirq 스스로 다시 등록할 수 있다는 점
• 해결
- 재등록된 softirq 즉시 처리하지 않는 방법
- 커널 스레드를 작동(낮은 우선 순위)
· softirq 너무 많아지면
12
워크 큐
워크 큐
• 지연 작업을 커널 스레드 형태로 처리
• 프로세스 컨텍스트에서 실행
• 스케줄링이 가능하며, 휴면 상태로 전환 될 수 있음
- 많은 양의 메모리 할당, 세마포어 할당 작업의 필요한 경유 유용
• 지연되는 작업이 휴면 상태 전환이 필요한 경우 워크 큐 사용
• 커널 스레드가 필요하지 않은 경우 태스크릿 사용 검토
13
워크 큐
구현
• 최상위 계층에 작업 스레드가 있음
- 여러 유형의 작업 스레드
- 특정 유형의 스레드는 프로세스당 하나씩
작업 스레드
cpu_workqueue_struct
프로세서 당 하나씩
workqueue_struct 구조체
work_struc
work_struc
work_struc
t 구조체
t 구조체
t 구조체
…
…
…
…
…
…
…
…
…
작업 스레드
유형마다 하나씩
지연 작업
함수마다 하나씩
14
워크 큐
워크 큐 사용
• 작업 생성
- DECLARE_WORK(name, void (*func)(void *), void *data)
- INIT_WORK(struct work_struct *work, void (*func)(void *), void *data)
• 워크 큐 핸들러
- void work_handler(void *data)
• 작업 스케줄링
- scedule_work(&work)
- schedule_delayed_work(&work, delay)
• 작업 비우기
- int cancel_delayed_work(struct work_struct *work)
• 새로운 워크 큐 만들기
- struct workqueue_struct *create_workqueue(const char *name)
15
후반부 처리
후반부 처리 작업 사이의 락
• 태스크릿
- 내부의 동시성과 관련된 문제를 신경 쓰지 않아도 됨
- 외부의 동시성 문제를 해결하려면 적절한 락 필요
• sofrirq
- 모든 공유 데이터에 대해 적절한 락 필요
후반부 처리 비활성화
• 공유 데이터를 안전하게 보호 하려면 비활성화 + 락 함께
- 핵심 커널 코드를 작성하는 경우-후반부 처리만 비활성화 시킬수 있음
• 후반부 처리 작업 활성화 – local_bh_disable()
• 후반부 처리 작업 비활성화 – local_bh_enable()
16