배경으로 잡담
EINTR
소위 인터럽트 가능한 시스템 호출에 의해 반환될 수 있는 오류입니다. 시스템 호출이 실행되는 동안 신호가 발생하면 해당 신호는 무시되지 않습니다. 신호 처리기가 정의되어 있지만 없는 경우SA_RESTART
설정되고 이 핸들러가 신호를 처리하면 시스템 호출이 EINTR
오류 코드를 반환합니다.
참고로 Python에서 사용할 때 이 오류가 자주 발생합니다 ncurses
.
질문
POSIX 표준에 지정된 이 동작 뒤에 어떤 이유가 있습니까? (커널 설계에 따라) 복구되지 않을 수도 있다는 것을 이해할 수 있지만 커널 수준에서 자동으로 다시 시작하지 않는 이유는 무엇입니까? 이는 레거시적인 이유입니까, 아니면 기술적인 이유입니까? 이것이 기술적인 이유였다면, 그 이유는 지금도 여전히 유효한가요? 이것이 유산상의 이유라면, 그 역사는 어떻게 됩니까?
답변1
프로그램의 나머지 부분은 알 수 없는 상태에 있기 때문에 신호 처리기에서 중요한 작업을 수행하기가 어렵습니다. 대부분의 신호 처리기는 나중에 프로그램의 다른 곳에서 확인하고 처리할 플래그를 설정합니다.
시스템 호출이 자동으로 다시 시작되지 않는 이유:
다음을 통해 소켓에서 데이터를 수신하는 애플리케이션을 상상해 보세요.차단하고 중단할 수 없음 recv()
시스템 호출. 우리 시나리오에서는 데이터 전송이 매우 느리고 프로그램이 오랫동안 이 시스템 호출에 상주합니다. 프로그램에는 SIGINT
플래그(다른 곳에서 평가됨)를 설정하고 SA_RESTART
자동으로 다시 시작하도록 시스템 호출을 설정하는 신호 처리기가 있습니다. 프로그램이 recv()
데이터를 기다리고 있다고 상상해 보세요. 하지만 데이터가 도착하지 않습니다. 시스템 호출 차단. 이제 프로그램은 사용자로부터 캡처합니다 ctrl. c시스템 호출이 중단되고 방금 플래그를 설정한 신호 처리기가 실행됩니다. 그런 다음 recv()
다시 시작하고 여전히 데이터를 기다리고 있습니다. recv()
플래그를 평가하고 프로그램을 정상적으로 종료할 기회 없이 이벤트 루프가 중단됩니다 .
설정되지 않은 경우 SA_RESTART
:
위의 시나리오에서 SA_RESTART
설정하지 않으면 다시 시작하는 대신 recv()
수신됩니다 . EINTR
계속할 수 있도록 시스템 호출이 종료됩니다. 물론 프로그램은 (가능한 한 빨리) 플래그(신호 처리기에 의해 설정된)를 확인하고 정리해야 합니다.
답변2
Richard Gabriel이 논문을 썼습니다.“나쁠수록 좋다”는 인식의 증가Unix의 디자인 선택에 대해 설명합니다.
MIT 출신과 버클리 출신(그러나 Unix에서 일하고 있음)이라는 두 명의 저명한 사람들이 한때 만나 운영 체제 문제를 논의했습니다. MIT 출신의 이 사람은 ITS(MIT Artificial Intelligence Laboratory Operating System)에 대해 많이 알고 있었고 Unix 소스 코드도 읽고 있었습니다. 그는 Unix가 PC 오류 문제를 어떻게 해결했는지에 관심이 있었습니다. PC 손실 문제는 사용자 프로그램이 중요한 상태(예: IO 버퍼)가 있을 수 있는 긴 작업을 수행하기 위해 시스템 루틴을 호출할 때 발생합니다. 작동 중 중단이 발생하면 사용자 프로그램의 상태를 저장해야 합니다. 시스템 루틴에 대한 호출은 일반적으로 단일 명령이기 때문에 사용자 프로그램의 PC는 프로세스 상태를 적절하게 캡처할 수 없습니다. 시스템 루틴은 종료되거나 진행되어야 합니다. 올바른 접근 방식은 시스템 루틴을 호출한 명령으로 사용자 프로그램 PC를 종료하고 복원하여 시스템 루틴에 다시 들어가는 등의 중단 후에 사용자 프로그램을 재개할 수 있도록 하는 것입니다.
PC loser-ing
PC가 강제로 실행되기 때문에 그렇게 불립니다loser mode
. 여기서 "패배자"는 "사용자"를 가리키는 MIT의 애정 용어입니다.MIT에 있는 사람은 이 사건을 처리하는 코드를 보지 못했고 뉴저지에 있는 사람에게 문제를 처리하는 방법을 물었습니다. 뉴저지 직원은 Unix 사람들이 문제를 알고 있지만 해결책은 시스템 루틴을 항상 완료하도록 하는 것이었지만 때로는 시스템 루틴이 작업을 완료하지 못했음을 나타내는 오류 코드를 반환하는 것이라고 말했습니다. 그런 다음 올바른 사용자 프로그램은 오류 코드를 확인하여 시스템 루틴을 다시 시도할지 여부를 결정해야 합니다. MIT 사람들은 이 솔루션이 옳지 않기 때문에 좋아하지 않았습니다.
뉴저지 사람들은 Unix 솔루션이 올바른 솔루션이라고 말합니다. 왜냐하면 Unix는 단순하도록 설계되었고 옳은 일은 너무 복잡하기 때문입니다. 또한 프로그래머는 이러한 추가 테스트와 루프를 쉽게 삽입할 수 있습니다. MIT 사람들은 구현이 간단하지만 기능에 대한 인터페이스가 복잡하다고 지적했습니다. 뉴저지 사람은 Unix에서는 올바른 절충안이 선택된다고 말합니다. 즉, 구현 단순성이 인터페이스 단순성보다 더 중요하다고 말했습니다.