OS X (10.8.2)에서 이상한 동작을 추적하려고합니다. 기본적으로 필자는 파이프를 열어서 쓰기가 불가능해질 때까지 데이터로 채 웁니다. 그러나 내가 쓰려고 시도한 청크의 크기에 따라 select() 파이프가 여전히 쓰기 가능하다고 주장하더라도 write() 호출에서 EAGAIN을 얻을 것입니다. 여기비 차단 fd에 write()를 할 수 있습니까? select를 쓸 때 쓸 수 있습니까?
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/select.h>
#define START 1
#define END 16
int is_writeable(int fd) {
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
fd_set ws;
FD_ZERO(&ws);
FD_SET(fd, &ws);
if(select(fd+1, NULL, &ws, NULL, &timeout) < 0) {
return -1;
}
if(FD_ISSET(fd, &ws))
return 1;
else
return 0;
}
int main(int argc, char *argv[]) {
int pipes[2];
int rp, wp, i, errval, fails, tmp;
char testbuf[END];
char destbuf[128000];
for(i = START; i < END; i++) {
int byte_count = 0;
printf("%i: ", i);
fails = 0;
pipes[0] = 0;
pipes[1] = 0;
if(pipe(pipes) < 0) {
printf("PIPE FAIL\n");
break;
}
rp = pipes[0];
wp = pipes[1];
int flags = fcntl(wp, F_GETFL, 0);
if(fcntl(wp, F_SETFL, flags | O_NONBLOCK) == -1) {
fails = 4;
}
if(is_writeable(wp) != 1) {
fails = 1;
}
while(!fails) {
// printf(".");
if(is_writeable(wp) < 1) {
break;
}
tmp = write(wp, testbuf, i);
//No bytes written, fail
if(tmp < 0) {
if(errno == EAGAIN) {
if(is_writeable(wp) == 1) {
fails = 3;
break;
}
} else {
fails = 2;
perror("During write");
break;
}
} else {
byte_count += tmp;
}
//Errno is eagain, fail
}
printf("byte count %i, ", byte_count);
if(fails)
printf("FAIL, %i\n", fails);
else
printf("PASS\n");
if(close(wp) != 0)
printf("WP CLOSE FAIL\n");
if(close(rp) != 0)
printf("RP CLOSE FAIL\n");
}
}
출력됩니다 : 여기에 몇 가지 테스트 코드는 실패 케이스 (3)은 쓰기()가 호출이 -1 반환하지만 선택 경우 여전히 파일 핸들이 쓰기 가능한 것으로보고
1: byte count 16384, PASS
2: byte count 16384, PASS
3: byte count 65535, FAIL 3
4: byte count 16384, PASS
5: byte count 65535, FAIL 3
6: byte count 65532, FAIL 3
7: byte count 65534, FAIL 3
8: byte count 16384, PASS
9: byte count 65529, FAIL 3
10: byte count 65530, FAIL 3
11: byte count 65527, FAIL 3
12: byte count 65532, FAIL 3
13: byte count 65533, FAIL 3
14: byte count 65534, FAIL 3
15: byte count 65535, FAIL 3
하는 것으로 .
(1..10).each do |i|
passes = true
begin
(rp, wp) = IO.pipe
wp.write_nonblock ("F" * i) while(select [], [wp], [], 0)
rescue Errno::EAGAIN
puts "#{i}: FAIL"
passes = false
ensure
rp.close
wp.close
end
puts "#{i}: PASS" if passes
end
이 버그 사양의 오해 인 경우 내가 확실히 말할 수 없다 :
여기에 같은 실패를 보여줍니다 루비의 짧은 예이다. 생각?
Mac OS X 10.7.5에서 나는 도움이되는지 잘 모르겠다. (미안하지만 주석이 있어야하고 형식이 형편 없다) :'1 : byte count 15873 바이트 카운트 15,873이 통과 4 : 바이트 수 15,876이 통과 5 바이트 카운트 15,875이 통과 6 바이트 카운트 15,876이 통과 7 : 바이트 수 15,876, PASS 3 패스 바이트 15,874 카운트 : 2 PASS (14)을 통과 할 바이트 수 15,873 : (13)을 통과 할 바이트 수 15,876 : (12)을 통과 할 바이트 수 15,873 : (11)을 통과 할 바이트 수 15,880 : (10)을 통과 할 바이트 수 15,876 : 바이트 수 15,880는 9 합격 : 바이트 c ount 15876, PASS 15 : 바이트 수 15885, 패스 '. –
'select()'의 POSIX 스펙은 "O_NONBLOCK clear 함수를 사용하여 출력 함수를 호출하면 함수가 데이터를 성공적으로 전송하는지 여부에 관계없이 쓰기가 준비된 것으로 간주됩니다" 'select()'가 얼마나 많은 바이트가 출력 요청인지 알 수 없으므로 그 결정을 어떻게 내릴 수 있는지 모르겠습니다. 스펙에서는 "O_NONBLOCK 클리어로 1 바이트를 전송하는 출력 함수에 대한 호출이 차단되지 않을 것입니다 ..."라고 말할 것입니다. –
10.8.2에서 오류가 발생했기 때문에 Mountain Lion에 도입 된 오류라고 생각합니다. ML은 또한 64kB로 파이프를 확장하는 "특징"을 가지고 있는데, 이는 모든 실패들 사이에서 공통적 인 것처럼 보입니다. –