7

つまり、システム コールで EINTR などのエラー状態をどのように単体テストしますか。

私が取り組んでいる特定の例の 1 つは、(errno==EINTR) で EOF を返すときに fclose を再度呼び出す必要があるかどうかです。動作は、fclose の実装によって異なります。

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

EINTR が発生したときに fp が解放された場合、この呼び出しは安全ではない可能性があります。when (errno==EINTR) のエラー処理をテストするにはどうすればよいですか?

4

8 に答える 8

4

この特定のケースでは、fclose() を再度呼び出すのは安全ではありません。C 標準では、呼び出しが失敗した場合でも、ストリームはファイルから切り離される (そして不確定になる) と言われているためです。

于 2008-10-07T00:27:08.257 に答える
3

Linux カーネルのソース コードを見ると、ファイルを閉じたときに EINTR を返すドライバーさえ見つかりません。

absosmurfly がこのケースを再現する必要がある場合は、.release メソッドで -EINTR を返す独自のドライバーを Linux で作成できます。O'Reilly の Linux Device Drivers book のサンプル コードを見てください。スカル プロジェクトは、最も単純なものの 1 つです。次のように変更します。

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

繰り返しになりますが、Linux ソース ツリーを調べてみると、終了時に EINTR を返すドライバーが見つかりません。

編集- ヒューズのように見えます - ユーザー空間のファイルシステムができるかもしれません。これは、sshfs などに使用されます。ただし、まだエッジケースです。

于 2008-10-07T00:38:03.973 に答える
3

関数ポインターの構造体を使用して、システム関数を抽象化します。flcose(fp) への呼び出しを sys->fclose(fp) のようなものに置き換えます。単体テストで、常に EINTR を返す fclose の実装を作成し、sys->fclose をそのバージョンに設定します。

于 2008-10-07T00:21:02.917 に答える
2

これを実際に自由にテストする簡単な方法はないと思います。

fclose 操作がシグナルによって中断されると、EINTR が生成されます。これは、fclose がクローズ要求を処理しているときにシグナルを受信したバックグラウンド スレッドにあったことを意味します。

その一連の状況を再現しようとして頑張ってください。

于 2008-10-07T00:06:53.320 に答える
1

フィザーがfclose()2回呼び出すのは安全ではないことを思い出させたので、テストのためだけに、これをテストする方法を次に示します。

独自の動作を使用して、プログラム内で (または libc のその他の関数を)再定義 することができます。Unix ライクなシステムでは、リンカは文句を言いません。Windows では試したことがありませんが、cygwin では試していません。もちろん、これにより他のテストが real を使用できなくなるため、そのようなテストは別のテスト実行可能ファイルに入れる必要があります。fclose()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;
}
于 2008-11-10T13:47:01.677 に答える
1

Kris が示唆するように、一時的に「本物」への呼び出しをfclose()単体テスト コードで定義された独自の実装に置き換えます。あなたの実装は、次のような単純なことを行うことができます:

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

ただし、fizzer が指摘しているfclose()ように、動作が未定義であるため、再度呼び出すべきではありません。そのため、状態を確認する必要さえありません。

もう 1 つの質問は、これについて本当に心配する必要があるかどうかです。もしあなたのアプリケーションコードが (SIGKILL と SIGSTOP を除く) すべての可能なシグナルをブロックしていればfclose()、EINTR を受け取ることはなく、まったく心配する必要はありません。

于 2008-10-07T02:20:38.900 に答える
1

信号の同時処理とエラー状態の確認に問題があるのではないかと思います。

于 2011-02-26T00:47:38.320 に答える
1

ええと、皆さんはかなり重要なことを無視していると思います。

fclose() は EINTR を返すことができません。fopen()、fwrite()、fread()、または標準の CI/O 関数のいずれもできません。

EINTR を処理する必要があるのは、open(2)、write(2)、select(2) などの低レベルの I/O 呼び出しに手を出すときだけです。

[面白い]マニュアルページを読む

于 2009-07-02T01:02:36.557 に答える