shell/initはどのようにstdioストリームを生成しますか?

shell/initはどのようにstdioストリームを生成しますか?

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用)を開きます。

open1)同じプロセスで同じデバイスに複数回アクセスし、異なるファイル記述子を期待することはどのように可能ですか?

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

編集する答えの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基準。他のシステムは、各プログラムの第4の公開ストリームを含む異なる規則を使用する。

追加資料: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)システムが同じファイルを同時に開く複数のプロセスをサポートしている場合、なぜ1つのプロセスが複数回開くことができないのですか?ファイル記述子は継承されるため、同じプロセスで同じファイルを2回使用することができます。つまり、一度継承され、プロセス自体で一度開かれる場合です。プロセスがどのファイルを開いたかを確認し、古いファイルへの参照を返すことは追加の作業です。

また、プロセスの複数の部分が同時に同じファイルを使用しているかどうか疑問があります。基本プログラムがそれを使用している間、ライブラリーはいくつかの構成ファイルを使用しているとします。ファイル記述子は、アクセスモードおよびファイルポインタの位置に関連する。コピーが1つしかないと、奇妙なことが起こります。また、ファイルが(同じfdで)2回開かれたときに閉じるとどうなりますか?タイミングを決定するために別の参照カウント層がある場合があります。本物ファイルを閉じても他の問題には役立ちません。


2)コードによって異なります。 C以外のスマート言語は、開かれたファイルを保持している変数を再計算して再開する前に閉じることができます。コードを見ないと話すのは難しいです。

しかし、小さなテストとして、Perlで同じ変数で同じファイルを2回開くと、同じFD番号が生成されます。

perl -e 'open F, "test.txt"; printf "%d ", fileno(F); open F, "test.txt"; printf "%d\n", fileno(F)'
3 3

これを実行すると、straceファイルが再度開く直前に閉じられることがわかります。

2つの異なる変数を介して2つの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規格:

プログラムの開始時に3つのストリームを事前定義する必要があり、明示的に開く必要はありません。標準入力(標準入力読み取り用)、標準出力(標準出力書き込み用)、標準エラー(診断出力書き込み用)。

しかし、とにかく慣例は、プログラムがカーネル管理なしで実行できることです。それともそうではないかもしれません。呼び出し仕様を読めば、exec次のようになります。実装があなたのために何かを開くことを許可する:

exec関数ファミリの1つを正常に呼び出した後にファイルディスクリプタ0、1、または2が閉じられると、実装は新しいプロセスイメージでファイルディスクリプタに指定されていないファイルを開くことができます。

(もちろんプログラム自体からドラッグすることもできます。)

起動時に無効にすると、互換性は除外されます。

標準ユーティリティまたは仕様アプリケーションが読み取り用に開かれていないファイルディスクリプタ0または書き込み用に開かれていないファイルディスクリプタ1または2で実行されている場合、ユーティリティまたはアプリケーションが実行されている環境は規格ではないと見なされるため、ユーティリティまたはアプリケーションこの規格で説明されているように動作しません。

これLinuxのマニュアルページには非常に便利です。:

一般的な原則によれば、権限があるかどうかにかかわらず、すべての移植可能なプログラムは、execve()中にこれら3つのファイル記述子が閉じられたままであると仮定できます。

関連情報