2008-10-06 10 views
6

Вкратце, как вы можете протестировать условие ошибки, такое как EINTR при системном вызове.Условия ошибки тестирования устройства - EINTR

Один конкретный пример, над которым я работаю, который сам по себе может быть случайным, заключается в необходимости повторного вызова fclose, когда он возвращает EOF с (errno == EINTR). Поведение зависит от реализации fclose:

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

Этот вызов может быть небезопасным, если fp освобождается при возникновении EINTR. Как я могу проверить обработку ошибок, когда (errno == EINTR)?

ответ

2

Я не думаю, что есть простой способ проверить это по своему усмотрению.

EINTR будет сгенерирован, если операция fclose прерывается сигналом. Это означает, что fclose был в фоновом потоке, который получил сигнал, когда он обрабатывал запрос на закрытие.

Удачи, пытаясь воспроизвести этот набор обстоятельств.

3

Используйте конструкцию указателей функций, чтобы абстрагировать системные функции. Замените вызов flcose (fp) на что-то вроде sys-> fclose (fp). В своем модульном тесте создайте реализацию fclose, которая всегда возвращает EINTR, затем установите sys-> fclose в эту версию.

+0

По сути, вы говорите о том, чтобы выкрикивать системные вызовы, которые в этом случае должны быть правильными. – tvanfosson 2008-10-07 01:12:08

+0

К сожалению, вы бы издевались над тем, что он хочет проверить. Возникает вопрос: каков статус fp, когда системный вызов * real * прерывается во время закрытия. – bmdhacks 2008-10-07 01:14:42

4

В этом конкретном случае небезопасно снова вызвать fclose(), поскольку стандарт C говорит, что поток отключен от файла (и становится неопределенным), даже если вызов завершается с ошибкой.

3

Если посмотреть на исходный код ядра Linux, я не могу найти драйверы, которые даже возвращают EINTR при закрытии файла.

Если вам нужно было воспроизвести этот случай, вы можете написать свой собственный драйвер в Linux, чтобы вернуть -EINTR по методу .release. Взгляните на example code из книги O'Reilly's Linux Device Drivers. Проект scull является одним из самых простых. Вы бы изменить его, чтобы быть похожим на это:

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

Снова, хотя, по оглавлению дерева исходных текстов Linux, я не могу найти драйвер, который будет возвращать EINTR на закрытии.

EDIT - ОК это похоже на предохранитель - возможно, файловая система пользовательского пространства. Это используется для таких вещей, как sshfs. Тем не менее, край.

1

Как предлагает Крис, временно заменить вызовы на «реальный» fclose() с вашей собственной реализацией, определенной в вашем тестовом коде устройства. Ваша реализация может сделать что-то просто:

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

Но, как Fizzer указывает, вы не должны вызывать fclose() снова поведение не определено, так что вам не нужно беспокоиться даже проверки состояния.

Другой вопрос, спросить, действительно ли вам нужно беспокоиться об этом; если ваш код приложения блокировал все возможные сигналы (кроме SIGKILL и SIGSTOP) во время вашего fclose(), тогда вы не получили бы EINTR и вообще не должны были волноваться.

1

Вот как бы я это испытал, просто для тестирования, так как физзатор напомнил нам, что вызов fclose() дважды небезопасен.

Можно переопределитьfclose() (или любую другую функцию LIBC) в вашей программе с вашим собственным поведением. В Unix-подобных системах компоновщик не жалуется - никогда не пробовал 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) и выберите (2), которые вам нужны для обработки EINTR.

Прочитайте [смешная] человек страница

1

Я думаю, что может быть проблемой с одновременной обработкой сигналов и подтверждающим наличием ошибок.

Смежные вопросы