인터럽트 시 시스템 호출을 처리하는 방법을 설명하는 교과서를 읽고 있습니다.
시스템 호출이 중단될 수 있습니다. 오랫동안 프로세스를 차단할 수 있는 읽기, 대기, 승인 등의 시스템 호출을 느린 시스템 호출이라고 합니다. 일부 이전 버전의 Unix에서는 핸들러가 신호를 포착하는 동안 중단된 느린 시스템 호출이 신호 핸들러가 반환될 때 재개되지 않고 오류 조건 및 errno가 EINTR로 설정된 사용자에게 즉시 반환됩니다. 이러한 시스템에서 프로그래머는 중단된 시스템 호출을 수동으로 다시 시작하는 코드를 포함해야 합니다.
하지만 시스템 호출을 다시 시작하는 것이 항상 안전한가요? 시스템 호출이 완료되기 전에 재설정되어야 하는 내부 데이터 구조를 시스템 호출이 유지한다고 가정합니다. 따라서 우리는 장기 실행 및 차단 시스템 호출을 시작하고 신호가 이를 중단하면 시스템 호출이 다시 시작되므로 첫 번째 시스템 호출에서는 데이터 구조를 재설정할 기회가 없습니다.
이전 호출의 데이터 구조가 재설정되지 않았으므로 두 번째 시스템 호출이 발생한 후 데이터 구조가 일치하지 않아 작업이 손상될 수 있습니다.
그렇다면 시스템 호출을 다시 시작하는 것이 안전한가요?
답변1
Linux에서는 그렇습니다. 반환 시스템 호출을 다시 시작하는 것은 항상 안전합니다 EINTR
. 반환 값은 유용한 진행이 이루어지기 전에 시스템 호출이 중단되었으므로 다시 시작해야 함을 의미합니다. 시스템 호출은 이를 염두에 두고 구현됩니다.
시스템 호출 인터럽트로 인한 시스템 상태 변경은 다르게 처리됩니다.read
중단되기 전에 일부 데이터를 검색하는 호출은 해당 데이터를 반환하여 성공을 나타냅니다.write
중단되기 전에 일부 데이터를 전송한 호출은 자신이 쓴 데이터의 양을 반환하며, 이는 또한 성공을 나타냅니다. (덧붙여서, 성공적인 호출이 요청한 작업을 모두 수행했다고 가정하기보다는 이러한 함수의 반환 값을 확인해야 하는 이유 중 하나입니다.)
SA_RESTART
적절한 신호에 플래그를 설정하면 많은 시스템 호출이 자동으로 다시 시작될 수 있습니다. GNU C 라이브러리는 재시작 코드 작성을 돕는 매크로를 제공합니다.TEMP_FAILURE_RETRY
존재하다unistd.h
( _GNU_SOURCE
이미 정의된 경우 정의).
EINTR
Linux에서는 신호 처리기가 없어도 시스템 호출이 반환될 수 있습니다.
"신호 처리기 인터럽트 시스템 호출 및 라이브러리 함수" 섹션man 7 signal
다양한 시나리오에서 영향을 받는 시스템 호출 목록을 포함하여 모든 세부 정보가 포함되어 있습니다.