운영체제 기본/장치 제어와 입출력: 두 판 사이의 차이
출처를 이름 있는 MediaWiki 각주와 문서 말미 참고 문헌으로 정리 |
인터럽트를 비동기 사건 통지 중심으로 재구성; 타이머 선점은 활용 사례로 배치 |
||
| 1번째 줄: | 1번째 줄: | ||
[[운영체제 기본/보호|이전: 보호와 시스템 호출]] · [[운영체제 기본|목차]] · [[운영체제 기본/프로세스와 스레드|다음: 프로세스와 스레드]] | [[운영체제 기본/보호|이전: 보호와 시스템 호출]] · [[운영체제 기본|목차]] · [[운영체제 기본/프로세스와 스레드|다음: 프로세스와 스레드]] | ||
== 실행 | == 실행 흐름과 독립적인 사건의 통지 == | ||
키보드 입력, 네트워크 패킷 도착, 저장장치의 입출력 완료는 프로그램이 다음 명령을 실행하는 순서에 맞춰 발생하지 않는다. CPU가 계산을 진행하는 동안에도 이런 사건은 일어난다. '''하드웨어 인터럽트는 사건의 발생을 CPU에 알리고, 운영체제가 이를 처리할 기회를 만드는 통지 수단'''이다. | |||
인터럽트가 없다면 프로그램이나 운영체제가 장치의 상태를 반복해서 확인하는 폴링을 사용할 수 있다. 자주 확인하면 응답 지연은 줄지만 확인할 일이 없어도 CPU 시간을 쓴다. 확인 간격을 늘리면 그만큼 처리가 늦어진다. 인터럽트는 사건이 발생했을 때 처리를 요청하므로 이 반복 확인을 줄일 수 있다. 반대로 사건이 아주 빈번하면 잦은 진입·복귀의 비용이 커져 폴링이나 묶음 처리와 조합하는 편이 유리할 수 있다.<ref name="interrupt-polling">[https://docs.kernel.org/networking/napi.html Linux 커널 문서: NAPI], 인터럽트와 폴링의 결합.</ref> | |||
< | |||
인터럽트의 원인에 따라 할 일은 다르다. 키보드 입력은 도착한 데이터를 읽어 입력 계층에 넘기고, 네트워크 수신은 도착한 패킷의 처리를 진행하며, 저장장치 완료는 요청 결과를 확인한다. 타이머 만료는 시간 경과를 알린다. '''스케줄링과 선점은 이 통지를 활용하는 기능 중 하나'''이며, 모든 인터럽트가 CPU 양보나 프로세스 교체를 목적으로 발생하는 것은 아니다. | |||
== 인터럽트와 동기적 예외 == | == 인터럽트와 동기적 예외 == | ||
| 27번째 줄: | 21번째 줄: | ||
처리를 마친 뒤 원래 실행을 재개한다면 저장한 상태를 복원하고 인터럽트 복귀 절차를 거친다. 처리기가 잠깐 실행되었다는 사실과 다른 스레드로 '''문맥 교환'''했다는 사실은 다르다. 문맥 교환은 스케줄러가 실행 대상을 바꾸기로 결정했을 때 기존 실행 문맥을 보존하고 다른 문맥을 복원하는 별도 단계다. 진입만으로 실행 대상이 바뀌지는 않는다.<ref name="xv6-switch">Cox 외, [https://pdos.csail.mit.edu/6.1810/2025/xv6/book-riscv-rev5.pdf xv6], 8.1절과 8.2절.</ref> | 처리를 마친 뒤 원래 실행을 재개한다면 저장한 상태를 복원하고 인터럽트 복귀 절차를 거친다. 처리기가 잠깐 실행되었다는 사실과 다른 스레드로 '''문맥 교환'''했다는 사실은 다르다. 문맥 교환은 스케줄러가 실행 대상을 바꾸기로 결정했을 때 기존 실행 문맥을 보존하고 다른 문맥을 복원하는 별도 단계다. 진입만으로 실행 대상이 바뀌지는 않는다.<ref name="xv6-switch">Cox 외, [https://pdos.csail.mit.edu/6.1810/2025/xv6/book-riscv-rev5.pdf xv6], 8.1절과 8.2절.</ref> | ||
== 입출력 완료와 깨우기 == | |||
장치에서 데이터가 오기를 기다리는 스레드는 CPU를 받아도 해당 작업을 진행할 수 없다. 운영체제는 이 스레드를 대기 상태로 두고 다른 실행 가능 작업에 CPU를 준다. 장치가 완료 인터럽트를 보내면 드라이버가 완료 상태를 확인하고 기다리던 작업을 깨운다. 깨우기는 대기 상태를 실행 가능 상태로 바꾸는 일이며, 준비된 작업은 실행 대기열에서 스케줄러의 선택을 기다린다.<ref name="xv6-io">Cox 외, [https://pdos.csail.mit.edu/6.1810/2025/xv6/book-riscv-rev5.pdf xv6], 6.1절 및 9.1절.</ref> | |||
<pre> | |||
입출력 대기 -> 장치 완료 인터럽트 -> 드라이버의 완료 확인과 깨우기 | |||
-> 실행 가능 상태와 실행 대기열 -> 스케줄러 선택 -> 실행 재개 | |||
</pre> | |||
장치 인터럽트는 다른 프로세스가 실행 중일 때도 도착한다. 따라서 인터럽트에서 복귀하는 대상과 방금 깨어난 스레드가 같다고 볼 수 없다. 타이머가 CPU를 회수할 기회를 만든다면, 장치 인터럽트는 기다리던 조건이 충족되었음을 알리는 역할을 한다. | |||
인터럽트 대신 장치 상태를 반복 확인하는 폴링도 가능하다. 폴링은 사건이 드물면 CPU 시간을 낭비하지만, 사건이 빈번하면 여러 결과를 연속 처리하여 잦은 인터럽트 진입 비용을 줄일 수 있다. 인터럽트로 처리를 시작하고 폴링으로 묶어서 처리하는 조합도 사용한다.<ref name="napi">Linux kernel documentation, [https://docs.kernel.org/networking/napi.html NAPI], Datapath API 및 Scheduling and IRQ masking.</ref> | |||
== 타이머 인터럽트와 선점 == | == 타이머 인터럽트와 선점 == | ||
시스템 호출이 일어날 때마다 커널이 실행 중인 작업을 양보시킨다고 가정하자. 파일을 읽거나 출력하는 프로그램에서는 이 방법으로 실행 기회를 나눌 수 있다. 그러나 사용자 코드가 다음 C 반복문에 들어가면 시스템 호출 자체가 발생하지 않는다. | |||
<pre> | |||
while (1) { | |||
} | |||
</pre> | |||
시스템 호출을 유일한 양보 지점으로 삼았다면, 커널은 이 반복문에서 다음 양보 지점을 기다려도 제어권을 돌려받지 못한다. 해당 논리 CPU에서 실행을 기다리는 다른 작업은 차례를 얻지 못한다. '''시스템 호출마다 양보하도록 만드는 것과, 시스템 호출을 하지 않는 프로그램에서도 CPU를 회수할 수 있는 것은 다른 문제'''다. | |||
협력형 스케줄링은 프로그램의 자발적인 양보에 의존한다. 일반적인 선점형 시분할에서는 타이머 통지를 이용해 그 협조 없이 실행 기회를 나눈다. | |||
커널은 타이머에 다음 통지 시점을 설정한다. 시간의 진행과 만료 통지는 사용자 프로그램의 반복문과 독립적으로 이루어지므로, 프로그램이 시스템 호출을 전혀 하지 않아도 CPU는 타이머 인터럽트를 받아 커널로 진입할 수 있다. 사용자 프로그램이 이 타이머나 인터럽트 허용 상태를 마음대로 바꿀 수 없어야 이 장치가 제어권 회수 수단으로 기능한다.<ref name="riscv-timer">RISC-V International, [https://docs.riscv.org/reference/isa/v20260120/priv/machine.html The RISC-V Instruction Set Manual, Volume II: Machine-Level ISA], Machine Timer Registers 및 Machine Interrupt Registers.</ref> | 커널은 타이머에 다음 통지 시점을 설정한다. 시간의 진행과 만료 통지는 사용자 프로그램의 반복문과 독립적으로 이루어지므로, 프로그램이 시스템 호출을 전혀 하지 않아도 CPU는 타이머 인터럽트를 받아 커널로 진입할 수 있다. 사용자 프로그램이 이 타이머나 인터럽트 허용 상태를 마음대로 바꿀 수 없어야 이 장치가 제어권 회수 수단으로 기능한다.<ref name="riscv-timer">RISC-V International, [https://docs.riscv.org/reference/isa/v20260120/priv/machine.html The RISC-V Instruction Set Manual, Volume II: Machine-Level ISA], Machine Timer Registers 및 Machine Interrupt Registers.</ref> | ||
| 42번째 줄: | 60번째 줄: | ||
타이머 통지가 곧바로 선점 완료를 보장하지도 않는다. 커널은 공유 상태를 갱신하는 짧은 구간에서 해당 CPU의 마스킹 가능한 인터럽트를 막거나, 인터럽트는 허용하면서 스레드 선점을 미룰 수 있다. 두 제약은 서로 다르다. 전자는 처리기 진입을 늦추고 후자는 실행 대상 변경을 늦춘다. 선점 요청이 생겨도 보호 구간을 벗어날 때까지 기다릴 수 있으므로, 이런 구간의 길이가 응답 지연에 영향을 준다.<ref name="preempt-safe">Linux kernel documentation, [https://docs.kernel.org/locking/preempt-locking.html Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe].</ref> | 타이머 통지가 곧바로 선점 완료를 보장하지도 않는다. 커널은 공유 상태를 갱신하는 짧은 구간에서 해당 CPU의 마스킹 가능한 인터럽트를 막거나, 인터럽트는 허용하면서 스레드 선점을 미룰 수 있다. 두 제약은 서로 다르다. 전자는 처리기 진입을 늦추고 후자는 실행 대상 변경을 늦춘다. 선점 요청이 생겨도 보호 구간을 벗어날 때까지 기다릴 수 있으므로, 이런 구간의 길이가 응답 지연에 영향을 준다.<ref name="preempt-safe">Linux kernel documentation, [https://docs.kernel.org/locking/preempt-locking.html Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe].</ref> | ||
== | == 통지 빈도와 처리 비용 == | ||
장치가 사건마다 통지하면 개별 사건에 빠르게 반응할 수 있지만, 처리할 때마다 진입·복귀 비용이 든다. 여러 사건을 모아 통지하거나 한 번 진입한 뒤 묶어서 처리하면 처리량을 높일 수 있는 대신, 먼저 도착한 사건이 기다리는 시간이 생긴다. 네트워크의 인터럽트와 폴링 결합도 이 절충을 이용한다.<ref name="interrupt-polling" /> | |||
라운드 로빈처럼 시간 할당량을 두는 정책에서는 할당량이 짧을수록 다른 실행 가능 작업이 CPU를 받을 기회가 자주 온다. 대신 상태 저장과 복원, 스케줄러 실행 비용을 더 자주 지불한다. 작업이 바뀌면 이전 작업에 유리했던 캐시 내용이 다음 작업에는 유용하지 않을 수도 있다. 할당량을 길게 잡으면 이 비용을 줄이기 쉽지만 실행을 기다리는 다른 작업의 응답은 늦어진다. 타이머 자체가 공정성을 만드는 것은 아니며, 공정성은 시간 계산과 선택 정책이 함께 결정한다.<ref name="switch-cache">Jeffrey C. Mogul, Anita Borg, [https://decdoc.itsx.net/WRL/WRL-TN-16.pdf The Effect of Context Switches on Cache Performance], DEC WRL Technical Note TN-16, 1990.</ref> | 라운드 로빈처럼 시간 할당량을 두는 정책에서는 할당량이 짧을수록 다른 실행 가능 작업이 CPU를 받을 기회가 자주 온다. 대신 상태 저장과 복원, 스케줄러 실행 비용을 더 자주 지불한다. 작업이 바뀌면 이전 작업에 유리했던 캐시 내용이 다음 작업에는 유용하지 않을 수도 있다. 할당량을 길게 잡으면 이 비용을 줄이기 쉽지만 실행을 기다리는 다른 작업의 응답은 늦어진다. 타이머 자체가 공정성을 만드는 것은 아니며, 공정성은 시간 계산과 선택 정책이 함께 결정한다.<ref name="switch-cache">Jeffrey C. Mogul, Anita Borg, [https://decdoc.itsx.net/WRL/WRL-TN-16.pdf The Effect of Context Switches on Cache Performance], DEC WRL Technical Note TN-16, 1990.</ref> | ||
고정 간격의 주기적 틱만 가능한 것은 아니다. 다음 필요한 시각에 한 번 울리는 원샷 타이머를 재설정할 수도 있다. 틱리스 설계는 유휴 상태나 실행 가능한 작업이 하나인 상황에서 불필요한 주기적 통지를 줄인다. 이는 선점을 포기한다는 뜻이 아니라, 제어권 회수나 시간 처리가 필요한 시점에 맞춰 통지를 구성한다는 뜻이다.<ref name="dynamic-ticks">Linux kernel documentation, [https://docs.kernel.org/timers/highres.html High resolution timers and dynamic ticks design notes], [https://docs.kernel.org/timers/no_hz.html NO_HZ: Reducing Scheduling-Clock Ticks].</ref> | 고정 간격의 주기적 틱만 가능한 것은 아니다. 다음 필요한 시각에 한 번 울리는 원샷 타이머를 재설정할 수도 있다. 틱리스 설계는 유휴 상태나 실행 가능한 작업이 하나인 상황에서 불필요한 주기적 통지를 줄인다. 이는 선점을 포기한다는 뜻이 아니라, 제어권 회수나 시간 처리가 필요한 시점에 맞춰 통지를 구성한다는 뜻이다.<ref name="dynamic-ticks">Linux kernel documentation, [https://docs.kernel.org/timers/highres.html High resolution timers and dynamic ticks design notes], [https://docs.kernel.org/timers/no_hz.html NO_HZ: Reducing Scheduling-Clock Ticks].</ref> | ||
== 관련 각론 == | == 관련 각론 == | ||
2026년 10월 31일 (토) 07:24 판
이전: 보호와 시스템 호출 · 목차 · 다음: 프로세스와 스레드
실행 흐름과 독립적인 사건의 통지
키보드 입력, 네트워크 패킷 도착, 저장장치의 입출력 완료는 프로그램이 다음 명령을 실행하는 순서에 맞춰 발생하지 않는다. CPU가 계산을 진행하는 동안에도 이런 사건은 일어난다. 하드웨어 인터럽트는 사건의 발생을 CPU에 알리고, 운영체제가 이를 처리할 기회를 만드는 통지 수단이다.
인터럽트가 없다면 프로그램이나 운영체제가 장치의 상태를 반복해서 확인하는 폴링을 사용할 수 있다. 자주 확인하면 응답 지연은 줄지만 확인할 일이 없어도 CPU 시간을 쓴다. 확인 간격을 늘리면 그만큼 처리가 늦어진다. 인터럽트는 사건이 발생했을 때 처리를 요청하므로 이 반복 확인을 줄일 수 있다. 반대로 사건이 아주 빈번하면 잦은 진입·복귀의 비용이 커져 폴링이나 묶음 처리와 조합하는 편이 유리할 수 있다.[1]
인터럽트의 원인에 따라 할 일은 다르다. 키보드 입력은 도착한 데이터를 읽어 입력 계층에 넘기고, 네트워크 수신은 도착한 패킷의 처리를 진행하며, 저장장치 완료는 요청 결과를 확인한다. 타이머 만료는 시간 경과를 알린다. 스케줄링과 선점은 이 통지를 활용하는 기능 중 하나이며, 모든 인터럽트가 CPU 양보나 프로세스 교체를 목적으로 발생하는 것은 아니다.
인터럽트와 동기적 예외
하드웨어 인터럽트는 현재 실행하는 명령의 의미와 독립적으로 발생하는 비동기적 사건을 CPU에 알린다. 타이머 만료와 장치의 입출력 완료가 대표적이다. 반면 잘못된 메모리 접근이나 허용되지 않은 명령 실행으로 발생하는 예외는 해당 명령과 연결된 동기적 사건이다. 시스템 호출도 프로그램이 정해진 진입 명령을 실행하여 요청하므로, 장치가 비동기적으로 알리는 인터럽트와 구분해야 한다.
트랩이라는 용어의 범위는 아키텍처와 문헌마다 다르다. RISC-V에서는 예외나 인터럽트로 처리기에 제어가 넘어가는 일을 모두 트랩이라고 부른다. 따라서 “시스템 호출도 트랩이다”라는 설명에서 “시스템 호출도 비동기 하드웨어 인터럽트다”라는 결론을 내리면 안 된다.[2]
진입, 상태 보존, 복귀
CPU는 인터럽트를 받아들일 때 복귀 위치와 이전 실행 권한 등 필요한 최소 상태를 아키텍처가 정한 방식으로 보존하고, 미리 설정된 처리기 진입점으로 이동한다. 사용자 코드 실행 중이었다면 커널 처리를 위한 권한 전환도 이루어진다. 단순히 권한만 높여 사용자 코드를 계속 실행시키는 것이 아니다. 진입점과 권한 전환을 함께 통제해야 보호 경계를 유지할 수 있다.
하드웨어가 모든 레지스터를 저장하는 것은 아니다. 진입 코드가 나머지 필요한 레지스터를 보존하고, 커널 스택이나 전용 인터럽트 스택 등 처리기에 적합한 실행 환경을 마련한다. 하드웨어가 담당하는 범위는 아키텍처마다 다르다. 예를 들어 RISC-V에서는 일반 레지스터 저장과 커널 스택 선택을 소프트웨어가 수행한다.[3]
처리를 마친 뒤 원래 실행을 재개한다면 저장한 상태를 복원하고 인터럽트 복귀 절차를 거친다. 처리기가 잠깐 실행되었다는 사실과 다른 스레드로 문맥 교환했다는 사실은 다르다. 문맥 교환은 스케줄러가 실행 대상을 바꾸기로 결정했을 때 기존 실행 문맥을 보존하고 다른 문맥을 복원하는 별도 단계다. 진입만으로 실행 대상이 바뀌지는 않는다.[4]
입출력 완료와 깨우기
장치에서 데이터가 오기를 기다리는 스레드는 CPU를 받아도 해당 작업을 진행할 수 없다. 운영체제는 이 스레드를 대기 상태로 두고 다른 실행 가능 작업에 CPU를 준다. 장치가 완료 인터럽트를 보내면 드라이버가 완료 상태를 확인하고 기다리던 작업을 깨운다. 깨우기는 대기 상태를 실행 가능 상태로 바꾸는 일이며, 준비된 작업은 실행 대기열에서 스케줄러의 선택을 기다린다.[5]
입출력 대기 -> 장치 완료 인터럽트 -> 드라이버의 완료 확인과 깨우기
-> 실행 가능 상태와 실행 대기열 -> 스케줄러 선택 -> 실행 재개
장치 인터럽트는 다른 프로세스가 실행 중일 때도 도착한다. 따라서 인터럽트에서 복귀하는 대상과 방금 깨어난 스레드가 같다고 볼 수 없다. 타이머가 CPU를 회수할 기회를 만든다면, 장치 인터럽트는 기다리던 조건이 충족되었음을 알리는 역할을 한다.
인터럽트 대신 장치 상태를 반복 확인하는 폴링도 가능하다. 폴링은 사건이 드물면 CPU 시간을 낭비하지만, 사건이 빈번하면 여러 결과를 연속 처리하여 잦은 인터럽트 진입 비용을 줄일 수 있다. 인터럽트로 처리를 시작하고 폴링으로 묶어서 처리하는 조합도 사용한다.[6]
타이머 인터럽트와 선점
시스템 호출이 일어날 때마다 커널이 실행 중인 작업을 양보시킨다고 가정하자. 파일을 읽거나 출력하는 프로그램에서는 이 방법으로 실행 기회를 나눌 수 있다. 그러나 사용자 코드가 다음 C 반복문에 들어가면 시스템 호출 자체가 발생하지 않는다.
while (1) {
}
시스템 호출을 유일한 양보 지점으로 삼았다면, 커널은 이 반복문에서 다음 양보 지점을 기다려도 제어권을 돌려받지 못한다. 해당 논리 CPU에서 실행을 기다리는 다른 작업은 차례를 얻지 못한다. 시스템 호출마다 양보하도록 만드는 것과, 시스템 호출을 하지 않는 프로그램에서도 CPU를 회수할 수 있는 것은 다른 문제다.
협력형 스케줄링은 프로그램의 자발적인 양보에 의존한다. 일반적인 선점형 시분할에서는 타이머 통지를 이용해 그 협조 없이 실행 기회를 나눈다.
커널은 타이머에 다음 통지 시점을 설정한다. 시간의 진행과 만료 통지는 사용자 프로그램의 반복문과 독립적으로 이루어지므로, 프로그램이 시스템 호출을 전혀 하지 않아도 CPU는 타이머 인터럽트를 받아 커널로 진입할 수 있다. 사용자 프로그램이 이 타이머나 인터럽트 허용 상태를 마음대로 바꿀 수 없어야 이 장치가 제어권 회수 수단으로 기능한다.[7]
사용자 코드 실행 -> 타이머 만료 -> 인터럽트 진입과 상태 보존
-> 시간 계산과 재스케줄 필요 판단
-> 기존 실행 재개 또는 다른 실행 문맥 선택
타이머 사건은 CPU 사용 시간을 반영하고 선점 필요성을 판단할 기회를 제공한다. 실행 가능한 다른 작업이 없거나 현재 작업이 계속 실행되어야 한다면 그대로 복귀할 수 있다. 반대로 다른 작업을 실행해야 한다면, 안전한 시점에서 스케줄러가 문맥 교환을 수행한다. 따라서 “타이머 인터럽트마다 반드시 다른 프로세스로 교체한다”는 설명은 일반적인 규칙이 아니다.
타이머 통지가 곧바로 선점 완료를 보장하지도 않는다. 커널은 공유 상태를 갱신하는 짧은 구간에서 해당 CPU의 마스킹 가능한 인터럽트를 막거나, 인터럽트는 허용하면서 스레드 선점을 미룰 수 있다. 두 제약은 서로 다르다. 전자는 처리기 진입을 늦추고 후자는 실행 대상 변경을 늦춘다. 선점 요청이 생겨도 보호 구간을 벗어날 때까지 기다릴 수 있으므로, 이런 구간의 길이가 응답 지연에 영향을 준다.[8]
통지 빈도와 처리 비용
장치가 사건마다 통지하면 개별 사건에 빠르게 반응할 수 있지만, 처리할 때마다 진입·복귀 비용이 든다. 여러 사건을 모아 통지하거나 한 번 진입한 뒤 묶어서 처리하면 처리량을 높일 수 있는 대신, 먼저 도착한 사건이 기다리는 시간이 생긴다. 네트워크의 인터럽트와 폴링 결합도 이 절충을 이용한다.[1]
라운드 로빈처럼 시간 할당량을 두는 정책에서는 할당량이 짧을수록 다른 실행 가능 작업이 CPU를 받을 기회가 자주 온다. 대신 상태 저장과 복원, 스케줄러 실행 비용을 더 자주 지불한다. 작업이 바뀌면 이전 작업에 유리했던 캐시 내용이 다음 작업에는 유용하지 않을 수도 있다. 할당량을 길게 잡으면 이 비용을 줄이기 쉽지만 실행을 기다리는 다른 작업의 응답은 늦어진다. 타이머 자체가 공정성을 만드는 것은 아니며, 공정성은 시간 계산과 선택 정책이 함께 결정한다.[9]
고정 간격의 주기적 틱만 가능한 것은 아니다. 다음 필요한 시각에 한 번 울리는 원샷 타이머를 재설정할 수도 있다. 틱리스 설계는 유휴 상태나 실행 가능한 작업이 하나인 상황에서 불필요한 주기적 통지를 줄인다. 이는 선점을 포기한다는 뜻이 아니라, 제어권 회수나 시간 처리가 필요한 시점에 맞춰 통지를 구성한다는 뜻이다.[10]
관련 각론
- 운영체제 기본/Linux의 키보드 입력: i8042 키보드의 IRQ에서 입력 이벤트와 프로세스 깨우기까지.
참고 문헌
- ↑ 1.0 1.1 Linux 커널 문서: NAPI, 인터럽트와 폴링의 결합.
- ↑ RISC-V International, The RISC-V Instruction Set Manual, Volume I: Exceptions, Traps, and Interrupts.
- ↑ Russ Cox, Frans Kaashoek, Robert Morris, xv6: a simple, Unix-like teaching operating system, 2025, 4.1절과 4.2절.
- ↑ Cox 외, xv6, 8.1절과 8.2절.
- ↑ Cox 외, xv6, 6.1절 및 9.1절.
- ↑ Linux kernel documentation, NAPI, Datapath API 및 Scheduling and IRQ masking.
- ↑ RISC-V International, The RISC-V Instruction Set Manual, Volume II: Machine-Level ISA, Machine Timer Registers 및 Machine Interrupt Registers.
- ↑ Linux kernel documentation, Proper Locking Under a Preemptible Kernel: Keeping Kernel Code Preempt-Safe.
- ↑ Jeffrey C. Mogul, Anita Borg, The Effect of Context Switches on Cache Performance, DEC WRL Technical Note TN-16, 1990.
- ↑ Linux kernel documentation, High resolution timers and dynamic ticks design notes, NO_HZ: Reducing Scheduling-Clock Ticks.