내가 이해하는 바에 따르면, 커널은 프로세스가 아니라 다른 프로세스의 런타임에서 호출할 수 있는 핸들러 세트입니다(또는 타이머 또는 유사한 것을 통해 커널 자체에 의해).
프로그램이 다시 실행되기 전에 장기 실행 동기화가 필요한 일부 예외 처리기가 발생하는 경우(예: 디스크 읽기가 필요한 페이지 오류 발생) 커널은 컨텍스트를 전환해야 한다는 것을 어떻게 인식합니까? 이를 달성하려면 다른 프로세스가 실행되어야 하는 것 같나요?
커널이 이 상태의 프로세스를 간헐적으로 확인하여 이를 처리하는 프로세스를 생성합니까? 장기 실행 동기화 핸들러를 호출하는 프로세스는 핸들러가 완료될 때까지(예: 디스크 읽기 완료) 컨텍스트를 전환해야 함을 커널에 알립니까?
답변1
"커널은 프로세스가 아니다."
이것은 순수한 용어입니다. (용어가 중요합니다.) 프로세스는 정의에 따라 사용자 공간에 존재하므로 커널은 프로세스가 아닙니다. 하지만 커널에는실.
"프로그램이 다시 실행되기 전에 장기 실행 동기화가 필요한 일부 예외 처리기가 발생하는 경우(예: 디스크 읽기가 필요한 페이지 오류 발생)".
사용자 공간 프로세스가 매핑되지 않은 메모리 페이지를 참조하는 기계 명령어를 실행하는 경우:
프로세서는 트랩을 생성하고 다음으로 전환합니다.링 0/관리자 모드. (이것은 하드웨어에서 발생합니다.)
트랩 핸들러는 커널의 일부입니다. 메모리 페이지를 디스크에서 가져와야 한다고 가정하면 프로세스를 중단할 수 없는 절전 상태로 전환합니다. 즉, 프로세스 테이블에 프로세스 CPU 상태를 저장하고 프로세스 테이블의 프로세스 항목에 있는 상태 필드를 수정합니다. 피해자 메모리 페이지가 발견되고, 요청된 페이지 내의 피해자와 페이지를 페이지 아웃하기 위해 I/O가 시작되며, 스케줄러(커널의 또 다른 부분)가 호출되어 사용자 영역 컨텍스트를 실행할 준비가 된 다른 프로세스로 전환합니다.
결국 I/O가 완료됩니다. 그러면 인터럽트가 발생합니다. 인터럽트에 대한 응답으로 프로세서는 핸들러를 호출하고 링 0/감독자 모드로 전환합니다. (이것은 하드웨어에서 발생합니다.)
인터럽트 핸들러는 커널의 일부입니다. 메모리 페이지를 기다리고 있는 프로세스의 I/O 대기 상태를 지우고 실행할 준비가 된 것으로 표시합니다. 그런 다음 스케줄러를 호출하여 사용자 모드 컨텍스트를 실행할 준비가 된 프로세스로 전환합니다.
일반적으로 커널은 다음과 같이 실행됩니다.
하드웨어 트랩이나 인터럽트에 응답합니다. 여기에는 타이머 인터럽트가 포함됩니다.
사용자 프로세스의 명시적 시스템 호출에 응답합니다.
대부분의 경우 프로세서는 링 3/사용자 모드에 있으며 일부 사용자 모드 프로세스의 명령을 실행합니다. 사용자 공간 프로세스가 시스템 호출을 할 때(예: 입출력 작업을 수행하려고 하기 때문에) 또는 하드웨어가 트랩(잘못된 메모리 액세스, 0으로 나누기 등)을 생성하거나 인터럽트 요청을 받을 때 하드웨어(I/O 완료, 타이머 인터럽트, 마우스 이동, 네트워크 인터페이스에 패킷 도착 등)
제목의 질문에 답하자면,"커널 스케줄러가 프로세스를 선점하는 방법을 아는 방법": 커널은 타이머 인터럽트를 처리합니다. 타이머 인터럽트가 도착했을 때 스케줄러는 현재 실행 중인 사용자 모드 프로세스가 리소스를 모두 소모했음을 알게 됩니다.양자그런 다음 프로세스는 실행 대기열의 끝에 배치되고 다른 프로세스가 재개됩니다. (일반적으로 스케줄러는 실행할 준비가 된 모든 사용자 모드 프로세스가 공정한 프로세서 시간 공유를 받도록 주의를 기울입니다.)
답변2
프로그램이 다시 실행되기 전에 장기 실행 동기화가 필요한 일부 예외 처리기가 발생하는 경우(예: 디스크 읽기가 필요한 페이지 오류 발생) 커널은 컨텍스트를 전환해야 한다는 것을 어떻게 인식합니까? 이를 달성하려면 다른 프로세스가 실행되어야 하는 것 같나요?
페이지 오류로 인해 디스크 읽기가 필요한 경우 커널 페이지 오류 처리기는 커널 스케줄러를 호출합니다.
https://elixir.bootlin.com/linux/v4.17/source/mm/filemap.c#L2470
filemap_fault()
wait_on_page_locked() - usually via __lock_page_or_retry()
wait_on_page_bit()
wait_on_page_bit_common()
io_schedule()
schedule()
나는 이 질문이 무엇을 의미하는지 잘 이해하지 못했지만 두 번째 질문에 대한 대답은 "아니요, 그럴 필요는 없습니다"라고 생각합니다.
최적화를 무시하면 커널은 항상 읽기 대기열에 넣은 직후에 컨텍스트를 전환합니다. (즉, filemap_fault()
호출 전에 발생합니다 __lock_page_or_retry()
. 논리가 약간 복잡하지만 문제 없이 실행할 수 있습니다.)
실행할 다른 프로세스가 없으면 커널은 CPU를 유휴 작업으로 전환합니다. (리눅스 커널은 CPU당유휴 스레드. 그러나 예를 들어 Windows "시스템 유휴 프로세스"와는 달리 이를 볼 수 없습니다 top
.