2008-10-06 3 views
6

즉, 시스템 호출시 EINTR과 같은 오류 조건을 어떻게 테스트 할 것인가?단위 테스트 오류 조건 - EINTR

나는 그 자체로 모든 경우 일 수있는 한 가지 구체적인 예는 (errno == EINTR)을 사용하여 EOF를 반환 할 때 fclose를 다시 호출해야하는지 여부입니다. 이 동작은 fclose의 구현에 따라 달라집니다.

// Given an open FILE *fp 
while (fclose(fp)==EOF && errno==EINTR) { 
    errno = 0; 
} 

EINTR이 발생할 때 fp가 해제되면이 호출은 안전하지 않을 수 있습니다. (errno == EINTR)에 대한 오류 처리를 테스트하려면 어떻게해야합니까?

답변

2

실제로 테스트 할 수있는 쉬운 방법이 없다고 생각합니다.

fclose 작업이 신호에 의해 중단되면 EINTR이 생성됩니다. 이것은 fclose가 close 요청을 처리 할 때 신호를 수신 한 백그라운드 스레드에 있음을 의미합니다.

행운을 빌어 그 상황을 재현하려고합니다.

3

시스템 기능을 추상화하기 위해 함수 포인터의 구조체를 사용하십시오. flcose (fp)에 대한 호출을 sys-> fclose (fp)와 같은 것으로 바꾸십시오. 유닛 테스트에서, 항상 EINTR을 리턴 한 다음 sys-> fclose를 해당 버전으로 설정하는 fclose 구현을 작성하십시오.

+0

본질적으로 당신은이 경우에해야 할 올바른 일인 시스템 호출을 조롱하는 것에 대해 이야기하고 있습니다. – tvanfosson

+0

불행히도, 테스트하고 싶은 고기를 조롱하고있을 것입니다. 질문은 : * 실제 * 시스템 호출이 닫히는 동안 인터럽트되었을 때 fp의 상태는 무엇입니까? – bmdhacks

4

C 표준은 호출이 실패하더라도 스트림이 파일에서 연결이 끊어 졌음을 나타내며 (불확정하게됩니다) fclose()를 다시 호출하는 것은 안전하지 않습니다.

3

리눅스 커널 소스 코드를 보면 파일 닫기시 EINTR을 반환하는 드라이버를 찾을 수 없습니다.

absosmurfly가이 케이스를 재현해야한다면 Linux에 자신의 드라이버를 작성하여 .release 메소드에서 -EINTR을 리턴 할 수 있습니다. O'Reilly의 Linux Device Drivers 책에서 example code을보십시오. scull 프로젝트는 가장 간단한 프로젝트 중 하나입니다. 이처럼되고 변경 것 :

int scull_release(struct inode *inode, struct file *filp) 
{ 
    return -EINTR; 
} 

은 다시하지만, 리눅스 소스 트리를 통해 grepping, 나는 가까이에 EINTR을 반환 어떤 드라이버를 찾을 수 없습니다.

편집 - 좋아요. 퓨즈처럼 보입니다 - 사용자 공간 파일 시스템이 가능할 수도 있습니다. 이것은 ssh와 같은 것에 사용됩니다. 그래도 여전히 최악의 경우.

1

Kris가 제안했듯이 "fclose()"에 대한 호출을 일시적으로 유닛 테스트 코드에 정의 된 구현으로 바꿉니다. fizzer가 지적한대로 동작이 정의되지대로 상태를 확인 귀찮게 필요가 없다, 그래서 당신은 다시 fclose()를 호출해서는 안,

int my_fclose(FILE *fp) 
{ 
    errno = EINTR; 
    return EOF; 
} 

그러나 : 귀하의 구현은 간단하게 뭔가를 할 수 있습니다.

다른 질문은 당신이 정말로 이것에 대해 걱정할 필요가 있는지 여부입니다. fclose() 동안 응용 프로그램 코드가 SIGKILL 및 SIGSTOP을 제외한 모든 가능한 신호를 차단했다면 EINTR을 얻지 못할 것이며 전혀 걱정할 필요가 없습니다.

1

fizzer가 우리에게 두 번 안전하지 않다고 전화했음을 상기시켜 주므로 테스트하기 위해 테스트하는 방법은 다음과 같습니다.

에 자신의 행동와 프로그램 에서fclose() (또는 libc의 다른 어떤 기능)을 다시 정의 할 수 있습니다. 유닉스 계열 시스템에서 링커는 불평하지 않는다. Windows에서는 시도하지 않았지만 cygwin에서는 시도하지 않았다. 물론 이것은 다른 테스트에서 실제 fclose()을 사용하지 못하게하므로 이러한 테스트는 별도의 테스트 실행 파일에 넣어야합니다.

다음은 minunit의 올인원 예입니다.

#include <errno.h> 
#include <stdio.h> 
#include <stdbool.h> 

/* from minunit.h : http://www.jera.com/techinfo/jtns/jtn002.html */ 
#define mu_assert(message, test) do { if (!(test)) return message; } while (0) 
#define mu_run_test(test) do { char *message = test(); tests_run++; \ 
           if (message) return message; } while (0) 

int tests_run = 0; 
bool fclose_shall_fail_on_EINTR = false; 

//--- our implemention of fclose() 
int fclose(FILE *fp) { 
    if (fclose_shall_fail_on_EINTR) { 
     errno = EINTR; 
     fclose_shall_fail_on_EINTR = false; //--- reset for next call 
     return EOF; 
    } else { return 0; } 
} 

//--- this is the "production" function to be tested 
void uninterruptible_close(FILE *fp) { 
    // Given an open FILE *fp 
    while (fclose(fp)==EOF && errno==EINTR) { 
     errno = 0; 
    } 
} 

char *test_non_interrupted_fclose(void) { 
    FILE *theHandle = NULL; //--- don't care here 
    uninterruptible_close(theHandle); 
    mu_assert("test fclose wo/ interruption", 0 == errno); 
    return 0; 
} 

char *test_interrupted_fclose(void) { 
    FILE *theHandle = NULL; //--- don't care here 
    fclose_shall_fail_on_EINTR = true; 

    uninterruptible_close(theHandle); 
    mu_assert("test fclose wo/ interruption", 0 == errno); 
    return 0; 
} 

char *test_suite(void) 
{ 
    mu_run_test(test_non_interrupted_fclose); 
    mu_run_test(test_interrupted_fclose); 
    return 0; 
} 

int main(int ac, char **av) 
{ 
    char *result = test_suite(); 

    printf("number of tests run: %d\n", tests_run); 
    if (result) { printf("FAIL: %s\n", result); } 

    return 0 != result; 
} 
1

음, 저는 여러분 모두가 꽤 중요한 것을 무시하고 있다고 생각합니다.

fclose()는 EINTR을 반환 할 수 없습니다. fopen(), fwrite(), fread() 또는 표준 C 입출력 함수도 사용할 수 없습니다.

open (2), write (2) 및 select (2)와 같은 저급 I/O 호출을 처리해야 EINTR을 처리 할 수 ​​있습니다.

는 [재미] 사람 페이지

+9

http://linux.die.net/man/3/fclose가 말하길 : "fclose() 함수도 실패하고 루틴 close (2), write (2) 또는 fflush에 대해 지정된 오류에 대해 errno를 설정할 수 있습니다 (삼)." close (2)는 EINTR을 반환 할 수 있습니다. – user9876

1

내가 신호를 동시에 처리 및 확인 오류 상태에 문제가있을 수 있다고 생각 읽기.