본문 바로가기

나름컴공이라공/Linux Kernel

Linux Kernal Internal > Ch3 태스크 관리(3)

☆★☆2016.01.07 작성☆★☆

☆★☆참고책 _리눅스 커널 내부구조(저자_백승재, 최종무)☆★☆

 

7. 런 큐와 스케줄링

- 스케줄링을 위한 수행 가능 상태의 태스크를 자료구조를 통해 관리

* 런 큐(run queue) : 리눅스에서의 스케줄링을 위한 자료구조

운영체제에 따라 1개, 여러개(CPU별 1개의 런 큐 유지)

* 태스크 생성

- init_task 라는 헤더를 가진 이중 연결 리스트에 삽입

- 다중 CPU의 경우, 자식 태스크는 부모 태스크의 런 큐에 삽입(캐시 친화력↑)

​ - 대기 상태에서 깨어난 태스크는 대기 전의 런 큐에 삽입(캐시 친화력↑)

+ 캐시 친화력? 호출했던 것을 다시 호출할 확률 ↑(시간/공간 캐시)

 

* 스케줄링

① 실시간 태스크 스케줄링

- FIFO, RR

: 우선 순위 설정을 위해 rt_priority(realtime prioirty) 필드 사용(0~99까지의 우선순위)

태스크가 수행을 종료하거나, 스스로 중지하거나, 자신의 슬라이스를 다 사용할 때까지 CPU 사용

고정 우선순위

항상 우선순위가 높은 태스크가 먼저 수행되는 것 보장

- DAEDLINE

: deadline이 가까운 태스크를 우선순위로 두고 스케줄링 대상으로 선정(우선순위의 기준이 다름)

② 일반 태스크 스케줄링(CFS : Completely Fair Scheduler)

- 완벽하게 공평한 스케줄링 추구

- 정해진 시간 단위 내에 존재하는 태스크에 공평한 CPU 시간 할당

- vruntime(virtual runtime) : 각 태스크가 가진 값

CPU를 사용하는 경우 사용 시간과 우선순위를 고려하여 증가

부모의 우선순위와 동일

사용자 수준에서 -20~19 / 커널 수준에 (사용자 수준 우선순위 + 120) -> 100~139

실시간 태스크의 우선순위(0~99) 보다 항상 낮은 우선순위를 가짐(100~139)

runtime = runtime * ( weight(0) / weight(curr) )

- 우선순위가 0인 태스크의 weight 값을 현재 태스크의 weight 값으로 나누어 runtime에 곱함

- 우선순위가 높은 태스크의 경우 CPU를 좀더 오래 사용할 수 있도록 시간이 느리게 흐르는 것처럼 관리

우선순위가 낮은 태스크의 경우 CPU를 조금만 사용하도록 시간이 빠르게 흐르는 것처럼 관리

 

* 스케줄링 대상인 태스크 선택 문제

① 가장 작은 vruntime 값의 태스크를 스케줄링 대상으로 선정 :

- 새롭게 생성된 태스크의 빠른 수행 시도

- RBtree 자료구조 이용(가작 좌측에 있는 vruntime이 최소 값)

Red Black tree 예

 

② 타임슬라이스 지정

- 시간 단위를 태스크의 우선순위에 기반하여 태스크에 분배

 

* 스케줄러 호출

- 호출 방법 : schedule() 함수 호출, 태스크의 thread_info구조체 내부의 need_resched 필드 설정

- 호출하는 경우

: need_resched 필드를 보고 스케줄러의 필요가 있을 때

현재 수행 태스크의 타임 슬라이스를 모두 사용 or 이벤트 대기할 때

새로운 태스크 생성, 대기 상태의 태스크가 깨어날 때

현재 태스크가 스케줄링 관련 시스템 콜을 호출할 때

 

8. 문맥 교환

* 문맥 교환(Context switch) : 수행 중 태스크의 동작을 정지하고 다른 태스크로 전환하는 과정

* 문맥 저장(Context save) : 문맥 교환되는 시점에서 수행 정도라든지, 현재 CPU의 레지스터 값이 얼마인지 등의 정보를 저장

* 문맥(CPU register)는 task_structure의 thread에 struc_thread_struct 형태로 저장

 

9. 태스크와 시그널

* 시그널 : 태스크에게 비동기적인 사건의 발생을 알리는 매커니즘

* 태스크의 원할한 시그널 처리

- 다른 태스크에게 시그널 송신 : sys_kill() 함수

- 시그널 수신 : signal, pending 변수(task_structure)

- 시그널 처리 : sys_signal() 함수, sighand 변수(task_structure)

 

* 시그널 매커니즘 : 시그널 번호를 구조체로 정의, 큐에 등록하는 구조

- 특정 pid 태스크 종료시, pid(tgid의 개념)가 동일한 태스크들(쓰레드를 공유한)에 시그널을 공유(task_structure의 signal 필드)

- 특정 태스크에만 전달 : 공유하지 않는 시그널 pending 필드에 저장

 

* 시그널을 보내는 과정

① 해당 태스크의 task_structure 구조체를 찾기

② 보내려는 시그널 번호를 통해 siginfo 자료구조를 초기화

③ 시그널의 성격에 따라 task_structure의 signal, pending 필드를 선택하여 세팅

④ blocked 필드를 검사해서 받지 않도록 설정된 시그널인지 검색하여 시그널 송신