내가 읽고 있어요아푸에그리고시스템 호출 인터럽트챕터가 나를 혼란스럽게 합니다.
책을 바탕으로 제가 이해한 내용을 적고 싶은데 정정해 주세요.
초기 UNIX 시스템의 특징은 "느린" 시스템 호출에서 프로세스가 차단된 동안 신호가 포착되면 시스템 호출이 중단된다는 것입니다. 시스템 호출은 오류를 반환하고
errno
로 설정 됩니다EINTR
. 여기에서는 신호가 발생하고 프로세스가 이를 포착했으므로 차단된 시스템 호출을 깨워야 하는 일이 발생할 가능성이 높다고 가정합니다.그래서 그것이 말하는 것은더 일찍UNIX 시스템의 특징이 있습니다. 내 프로그램이 시스템 호출을 사용하는 경우 프로그램이 언제든지 신호를 포착하면 중단/중지됩니다. (기본 핸들러는 캡처로 간주됩니까?)
예를 들어, 10GB의 데이터를 읽는 시스템 호출이 있는 경우 읽는 동안 신호(예: )
read
를 보내면 실패하고 반환됩니다.kill -SIGUSR1 pid
read
응용 프로그램이 중단된 시스템 호출을 처리하지 못하도록 하기 위해 4.2BSD에서는 중단된 특정 시스템 호출을 자동으로 다시 시작하는 기능을 도입했습니다. 자동 재시작을 위한 시스템 호출은
ioctl
,read
,readv
,write
,writev
및wait
입니다waitpid
. 앞서 언급한 것처럼 이러한 기능 중 처음 5개는 느린 장치의 신호에 의해서만 중단됩니다. 신호가 잡히면 항상 중단됩니다wait
.waitpid
이는 중단 시 작업이 다시 시작되는 것을 원하지 않는 일부 응용 프로그램에 문제를 일으킬 수 있으므로 4.3BSD에서는 프로세스가 신호별로 이 기능을 비활성화할 수 있도록 허용합니다.
그래서 전에자동 재시작소개받은 후 중단된 시스템 호출을 직접 처리해야 했습니다. 다음과 같은 코드를 작성해야 합니다.
시스템 호출을 중단할 때의 문제는 이제 오류 반환을 명시적으로 처리해야 한다는 것입니다. 일반적인 코드 시퀀스(읽기 작업을 가정하고 중단된 경우에도 읽기를 다시 시작한다고 가정)는 다음과 같습니다.
again:
if ((n = read(fd, buf, BUFFSIZE)) < 0) {
if (errno == EINTR)
goto again; /* just an interrupted system call */
/* handle other errors */
}
하지만 이제는 이런 종류의 코드를 작성할 필요가 없습니다.자동 재시작기구.
그렇다면 내 이해가 모두 정확하다면 지금 중단된 시스템 호출에 대해 무엇/왜 신경써야 할까요..? 시스템/운영 체제가 자동으로 처리하는 것 같습니다.
답변1
신호 처리기에 의한 시스템 호출 중단은 다양한 차단 시스템 호출의 경우에만 발생하며, 프로그래머가 명시적으로 설정한 신호 처리기에 의해 시스템 호출이 중단되는 경우에 발생합니다.
추가적으로 자동 시스템 호출 재시작은임의로 선택할 수 있는특징. SA_RESTART
신호 처리기를 구축할 때 플래그를 지정하여 시스템 호출을 자동으로 다시 시작하도록 선택할 수 있습니다 . (예를 들어) Linux에 명시된 바와 같이신호(7)매뉴얼 페이지:
If a signal handler is invoked while a system call or library
function call is blocked, then either:
* the call is automatically restarted after the signal handler
returns; or
* the call fails with the error EINTR.
Which of these two behaviors occurs depends on the interface and
whether or not the signal handler was established using the
SA_RESTART flag (see sigaction(2)).
위 인용문의 마지막 문장에서 알 수 있듯이 이 기능을 사용하기로 선택하더라도 모든 시스템 호출에 적용되는 것은 아니며 적용되는 시스템 호출 세트는 UNIX 구현마다 다릅니다. Linux signal(7)
매뉴얼 페이지에서는 이 플래그를 사용할 때 자동으로 다시 시작되는 여러 시스템 호출을 지적 SA_RESTART
하지만 다음을 포함하여 핸들러를 빌드할 때 이 플래그를 지정하더라도 다시 시작되지 않는 다양한 시스템 호출도 지적합니다.
* "Input" socket interfaces, when a timeout (SO_RCVTIMEO) has been
set on the socket using setsockopt(2): accept(2), recv(2),
recvfrom(2), recvmmsg(2) (also with a non-NULL timeout argu‐
ment), and recvmsg(2).
* "Output" socket interfaces, when a timeout (SO_RCVTIMEO) has
been set on the socket using setsockopt(2): connect(2), send(2),
sendto(2), and sendmsg(2).
* File descriptor multiplexing interfaces: epoll_wait(2),
epoll_pwait(2), poll(2), ppoll(2), select(2), and pselect(2).
* System V IPC interfaces: msgrcv(2), msgsnd(2), semop(2), and
semtimedop(2).
이러한 시스템 호출의 경우 APUE에 설명된 형식의 루프를 사용하여 수동으로 다시 시작하는 것이 중요합니다. 예:
while ((ret = some_syscall(...)) == -1 && errno == EINTR)
continue;
if (ret == -1)
/* Handle error */ ;
답변2
[APUE 내용은 읽지 않았지만 인용하신 내용은 별로인 것 같습니다.]
내 프로그램이 시스템 호출을 사용하는 경우 프로그램이 언제든지 신호를 포착하면 중단/중지됩니다.
시스템 호출이 아닙니다. 오직일부시스템 호출은 중단될 수 있습니다.
(기본 핸들러는 캡처로 간주됩니까?)
아니요.
예를 들어, 읽기 syscall이 있고 10GB의 데이터를 읽는 동안 읽는 동안 두 신호 중 하나(예: kill -SIGUSR1 pid)를 보내면 읽기가 실패하고 반환됩니다.
10GB read()는 읽기 전에 중단된 경우에만 EINTR을 반환합니다.1바이트라도; 그렇지 않으면 읽은 데이터의 양을 반환합니다(짧은 읽기 = 성공, errno는 관련 없음).
[연결된 속임수에서는 설명되지 않습니다.]
그렇다면 내 이해가 모두 정확하다면 지금 중단된 시스템 호출에 대해 무엇/왜 신경써야 할까요..? 시스템/운영 체제가 자동으로 처리하는 것 같습니다.
왜냐하면 당신이 원할 수도 있기 때문입니다무엇신호가 수신되면 신호 처리기로 많은 작업을 수행할 수 없습니다. malloc() 또는 stdio(또는 심지어 printf())를 사용하는 모든 작업은 불가능합니다. 따라서 프로그램의 메인 루프에서 인터럽트를 처리해야 하며, 그렇게 하려면 어떻게든 차단 read()에서 인터럽트해야 합니다(read()는 poll()이 fd 읽기 준비를 반환한 후에도 차단될 수 있습니다).
[이것예전에는링크기만에서도 설명됨]