MIT 소스를 읽고 있어요xv6 운영 체제. 클립은 다음의 시작 부분에 나타납니다 sh.c
.
// Ensure that three file descriptors are open.
while((fd = open("console", O_RDWR)) >= 0){
if(fd >= 3){
close(fd);
break;
}
}
나는 이것이 다음과 같은지 확인한다는 것을 안다.적어도새로 할당된 파일 설명자가 3보다 높은지(또는 동일한지) 확인하여 3개의 파일 설명자(아마도 stdin, stdout 및 stderr용)를 엽니다.
open
1) 동일한 프로세스에서 동일한 장치에 여러 번 액세스하고 다른 파일 설명자를 기대하는 것이 어떻게 가능합니까 ?
2) 이를 이해하기 위해 호스트 컴퓨터(x86_64 Linux 4.6.0.1)에서 유사한 코드 조각을 실행했습니다. 테스트 프로그램은 open
루프에서 텍스트 파일을 반복적으로 편집하여 다른 fd를 기대할 수 있는지 확인하지만 항상 동일한 파일 설명자를 생성합니다. 이것으로부터 나는 xv6의 코드 조각이 분명히 작동하기 때문에 open
실제 파일과 장치(예: )가 어떻게든 다르다는 결론을 내렸습니다(Qemu에서 테스트됨). /dev/console
차이점이 뭐야?
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
int main(void)
{
int fd;
int cnt = 0;
while ((fd = open("sample.txt", O_RDWR) > 0)) {
if (cnt != 10) {
cnt++;
printf("File descriptor opened: %d\n", fd);
} else {
break;
}
}
return 0;
}
실행 결과는 다음과 같습니다.
$ ./a.out
File descriptor opened: 1
File descriptor opened: 1
[snip]
File descriptor opened: 1
File descriptor opened: 1
편집하다답변 중 하나를 바탕으로 strace
실행 파일을 실행하여 찾았습니다.open
물론여러 파일 설명자가 반환되지만 어떤 이유로든 그 중 아무 것도 인쇄되지 않습니다. 왜 그럴까요?
3) 다소 관련이 없지만 fds 0-2에서 stdio 스트림을 사용하는 규칙이 바로 규칙이 아닙니까? 예를 들어 초기화 시퀀스가 입력/출력 파일 설명자를 다른 항목에 할당하는 경우 해당 하위 항목이 I/O를 수행하는 방식에 어떤 영향을 미칠까요?
답변1
이것은 실제로 3개의 질문입니다. 절차가 잘못되었으므로 즉시 주소 #2:
while ((fd = open("sample.txt", O_RDWR) > 0)) {
아마 당신 말은
while ((fd = open("sample.txt", O_RDWR)) > 0) {
부적절하게 배치된 괄호를 사용하면 0보다 큰지 테스트하는 것뿐입니다 fd
(파일 설명자 0, 1, 2가 열려 있으므로 이는 아마도 좋은 가정일 것입니다).
#1의 경우:open
호출(성공한 경우)은 다른 파일 설명자를 반환하도록 정의됩니다. 장치를 다시 켤 수 없는 경우 open
반환됩니다 -1
.
#3의 경우: 물론 그렇습니다.관습, 여전히POSIX기준. 다른 시스템은 각 프로그램에 대한 네 번째 공개 스트림을 포함하여 다른 규칙을 사용합니다.
추가 자료:Aegis 환경 작업(1988년 7월)
Apollo Domain/OS에 오류가 있음을 보여주는 6-9페이지를 참조하세요.입력하다그리고 **출력*
답변2
아니요, 코드는 그렇지 않습니다.확인하다설명자, 실제로 열립니다. 아직 설명이 제공되지 않았습니다. 각 열 때마다 새로운 파일 설명자(예: 0,1,2,3)가 제공됩니다. fd 3에 도달하면 코드가 중단되고 0에서 2까지는 열린 상태로 유지됩니다.
각 파일 설명자는 파일의 위치에 대한 포인터일 뿐입니다. 따라서 동일한 파일에 대해 여러 설명자를 사용하는 데 문제가 없습니다.
테스트 프로그램이 서로 다른 공개 호출에 대해 동일한 fd를 제공하는 경우 버그가 있는 것입니다. 코드를 보여주세요.
예, fd 0에서 2까지는 엄격한 규칙이 있습니다. 일부 코드가 stdout에 인쇄하려는 경우 실제로는 fd 1에 인쇄됩니다. stdout을 다른 것으로 "매핑"할 수 있는 방법은 없습니다.
답변3
1) 시스템이 동일한 파일을 동시에 여는 여러 프로세스를 지원하는 경우 왜 한 프로세스가 여러 번 열 수 없도록 허용합니까? 파일 설명자는 상속되므로 동일한 프로세스에서 동일한 파일을 두 번 사용하게 될 수 있습니다. 즉, 한 번 상속되고 프로세스 자체에서 한 번 열리는 경우입니다. 프로세스가 어떤 파일을 열었는지 확인하고 이전 파일에 대한 참조를 반환하는 것은 추가 작업입니다.
또한 프로세스의 여러 부분이 동시에 동일한 파일을 사용하고 있는지에 대한 의문이 있습니다. 기본 프로그램이 이를 사용하는 동안 라이브러리가 일부 구성 파일을 사용한다고 가정합니다. 파일 설명자는 액세스 모드 및 파일 포인터의 위치와 관련됩니다. 복사본이 하나만 있으면 이상한 일이 발생합니다. 또한 파일이 (동일한 fd에) 두 번 열리면 닫히면 어떻게 되나요? 시기를 결정하기 위해 또 다른 참조 카운팅 계층이 있을 수 있습니다.진짜파일을 닫아도 다른 문제에는 도움이 되지 않습니다.
2) 코드에 따라 다릅니다. C가 아닌 스마트 언어는 열린 파일을 보유하고 있는 변수를 다시 계산하고 다시 열기 전에 닫을 수 있습니다. 코드를 보지 않고는 말하기가 어렵습니다.
그러나 작은 테스트로서 Perl에서 동일한 변수로 동일한 파일을 두 번 열면 동일한 FD 번호가 생성됩니다.
perl -e 'open F, "test.txt"; printf "%d ", fileno(F); open F, "test.txt"; printf "%d\n", fileno(F)'
3 3
이를 실행하면 strace
파일이 다시 열리기 직전에 닫히는 것을 알 수 있습니다.
두 개의 서로 다른 변수를 통해 두 개의 FD 번호를 얻습니다.
perl -e 'open F, "test.txt"; printf "%d ", fileno(F); open G, "test.txt"; printf "%d\n", fileno(G)'
3 4
3) 기술적으로 표준 문서 번호 매기기는 관례라고 말할 수 있습니다. 성문화된 협약POSIX 및 ISO C 표준:
프로그램 시작 시 세 가지 스트림이 미리 정의되어야 하며 명시적으로 열 필요가 없습니다. 표준 입력(일반 입력 읽기용), 표준 출력(일반 출력 쓰기용) 및 표준 오류(진단 출력 쓰기용).
그러나 어쨌든 관례는 프로그램이 커널 관리 없이도 실행될 수 있다는 것입니다. 아니면 그렇지 않을 수도 있습니다. 호출 사양을 읽으면 exec
다음과 같은 것 같습니다.구현이 당신을 위해 무언가를 열도록 허용:
exec 함수 계열 중 하나를 성공적으로 호출한 후 파일 설명자 0, 1 또는 2가 닫히면 구현 시 새 프로세스 이미지에서 파일 설명자에 대해 지정되지 않은 파일을 열 수 있습니다.
(물론 프로그램 자체에서 끌 수도 있습니다.)
시작할 때 사용하지 않도록 설정하면 호환성이 제외됩니다.
표준 유틸리티 또는 규격 응용 프로그램이 읽기용으로 열리지 않은 파일 설명자 0 또는 쓰기용으로 열리지 않은 파일 설명자 1 또는 2로 실행되는 경우 유틸리티나 응용 프로그램이 실행되는 환경은 규격이 아닌 것으로 간주되므로 유틸리티나 응용 프로그램이 이 표준에 설명된 대로 동작하지 않습니다.
이것Linux 매뉴얼 페이지에는 매우 유용하게 나와 있습니다.:
일반적인 원칙에 따라, 권한이 있든 없든 모든 이식 가능한 프로그램은 execve() 중에 이 세 개의 파일 설명자가 닫힌 상태로 유지된다고 가정할 수 있습니다.