Linuxカーネルでは、I / Oチャネルはどのように実装されていますか?

Linuxカーネルでは、I / Oチャネルはどのように実装されていますか?

stdin、stdout、stderrは、プロセスが使用するI / Oチャネルを「知っている」データ構造にインデックス付けされる整数です。私はこのデータ構造がプロセスごとに一意であることを知っています。 I / Oチャネルは、動的メモリ割り当てを含むいくつかのデータ配列構造ですか?

答え1

Unixファミリーオペレーティングシステムでは、標準の入力、出力、およびエラーストリームはファイルディスクリプタとして0識別1されます2。 Linuxでは、これらのファイルprocがあります/proc/[pid]/fs/{0,1,2}。このファイルは実際には以下を指します。擬似端末ディレクトリ内のデバイス/dev/pts

PTY(Pseudo Terminal)は一対の仮想デバイスです。擬似端末ホスト(PTM)と擬似端子スレーブ(PTS)(総称してASAと呼ばれる)偽の端末ペア) は、プログラムに接続するプログラム間の双方向パイプに似た IPC チャネルを提供します。端末機器、擬似端末を使用して以前のプログラムと入力を送受信するドライバです。

重要なのは、疑似ターミナルスレーブが通常のターミナルのように見えることです。非標準および標準パターン(既定値)、SIGINT次のような特定の入力文字を解釈します。邪魔する文字(通常+を押してCtrl生成C)は疑似ターミナルホストに書き込まれるか、またはファイルの終わりの文字(通常+で生成)が見つかると次の戻りを生成しますread()。端末でサポートされているその他のタスクには、エコーのオン/オフ、フォアグラウンドプロセスグループの設定などがあります。0CtrlD

擬似端末は様々な用途に使用されます。

  • これにより、プログラムは、sshネットワークを介して接続された他のホスト上でターミナル指向プログラムを実行することができます。ターミナル指向プログラムは、一般に、対話型ターミナルセッションで実行される任意のプログラムであり得る。これらのプログラムの標準入力、出力、およびエラーは、ソケットが上記の端末関連機能をサポートしていないため、ソケットに直接接続することはできません。

  • これにより、プログラムはexpectスクリプト内の対話型端末指向プログラムを駆動できます。

  • xtermたとえば、端末関連機能を提供するために端末エミュレータで使用されます。

  • screenたとえば、複数のプロセス間で単一の物理端末を再利用するためにプログラムで使用されます。

  • これは、scriptシェルセッション中に発生したすべての入出力を記録するなどのプログラムで使用されます。

Unix98スタイルPTY、Linuxで使用される場合、設定は次のようになります。

  • ドライバはマスターマルチプレクサで擬似端末を開き、dev/ptmxPTM のファイル記述子を受け取り、/dev/ptsディレクトリに PTS デバイスを作成します。開いた各ファイル記述子は、/dev/ptmx独自の関連PTSを持つ独立したPTMです。

  • ドライバ呼び出しは、fork()次の手順を順番に実行する子プロセスを生成します。

    • 新しいセッションを開始するために子供が呼び出すsetsid()子供はセッションリーダーです。これにより子供も負けた。制御端子

    • 子プロセスは、ドライバによって生成されたPTMに対応するPTSデバイスを開きます。子プロセスはセッションリーダーですが、制御端末がないため、PTSは子プロセスの制御端末になります。

    • 子は、dup()標準入力、出力、およびエラーのスレーブデバイスのファイル記述子をコピーするために使用されます。

    • 最後に、子プロセス呼び出しは、擬似exec()端末装置に接続するために端末指向プログラムを開始する。

この時点で、ドライバがPTMに書き込むすべての内容は、PTSのターミナル指向プログラムへの入力として表示され、その逆も同様です。

正式モードで実行すると、PTSへの入力は1行ずつバッファされます。つまり、通常の端末と同様に、PTSから読み取られるプログラムは、改行文字がPTMに書き込まれたときにのみ入力行を受け取ります。バッファ容量がなくなると、write()入力の一部が消費されるまで追加のブロック呼び出しが実行されます。

Linuxカーネルでは、ファイル関連のシステムコールは、ユーザー空間プログラム用の統合ファイルシステムインターフェースを提供する仮想ファイルシステム(VFS)層で実装されていますopen()。 VFSを使用すると、さまざまなファイルシステム実装がカーネルに共存できます。ユーザー空間プログラムが上記のシステムコールを呼び出すと、VFS はその呼び出しを適切なファイルシステム実装にリダイレクトします。read()write() stat()

次のPTSデバイスは、/dev/ptsで定義されているファイルシステムの実装によって管理され、Unix98スタイルのデバイスを提供するTTYドライバはで定義されています。devpts/fs/devpts/inode.cptmxdrivers/tty/pty.c

TTYデバイスとTTY間のバッファリング産業規律擬似端末などは、次に定義される各 tty デバイスに対して維持されるバッファ構造を提供します。include/linux/tty.h

カーネルバージョン3.7以前では、バッファフリップバッファ:

#define TTY_FLIPBUF_SIZE 512

struct tty_flip_buffer {
        struct tq_struct tqueue;
        struct semaphore pty_sem;
        char             *char_buf_ptr;
        unsigned char    *flag_buf_ptr;
        int              count;
        int              buf_num;
        unsigned char    char_buf[2*TTY_FLIPBUF_SIZE];
        char             flag_buf[2*TTY_FLIPBUF_SIZE];
        unsigned char    slop[4];
};

構造には、2つの同じサイズのバッファーに分割されたストレージスペースが含まれています。バッファには番号が付けられています0(前半char_buf/flag_buf)と1(後半)。ドライバは、によって識別されるバッファにデータを格納しますbuf_num。別のバッファをラインフィールドにフラッシュすることができます。

buf_num0との間を切り替えてバッファを「反転」します1。変更後はbuf_num、 と識別されるバッファの先頭に設定され、 に設定さchar_buf_ptrれます。flag_buf_ptrbuf_numcount0

カーネルバージョン3.7から開始kmalloc()TTYロールオーバーバッファーは、リング構成によって割り当てられたオブジェクトに置き換えられました。。通常の状況では、IRQベースのシリアルポートは通常の速度で前のフリップバッファとほぼ同じように動作します。両方のバッファは最終的に割り当てられ、カーネルは以前と同様に循環します。ただし、レイテンシが発生したり速度が増加したりすると、バッファプールがわずかに大きくなる可能性があるため、新しいバッファ実装はより良いパフォーマンスを発揮します。

答え2

これら3つのうちの1つのマニュアルページで答えを説明します。

   Under  normal circumstances every UNIX program has three streams opened
   for it when it starts up, one for input, one for output,  and  one  for
   printing diagnostic or error messages.  These are typically attached to
   the user's terminal but might instead  refer  to  files  or
   other  devices,  depending  on what the parent process chose to set up.

   The input stream is referred to as "standard input"; the output  stream
   is  referred  to as "standard output"; and the error stream is referred
   to as "standard error".  These terms are abbreviated to form  the  sym-
   bols used to refer to these files, namely stdin, stdout, and stderr.

   Each  of these symbols is a stdio(3) macro of type pointer to FILE, and
   can be used with functions like fprintf(3) or fread(3).

   Since FILEs are a buffering wrapper around UNIX file  descriptors,  the
   same  underlying  files  may  also  be accessed using the raw UNIX file
   interface, that is, the functions like read(2) and lseek(2).

   On program startup, the integer file descriptors  associated  with  the
   streams  stdin,  stdout, and stderr are 0, 1, and 2, respectively.  The
   preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are
   defined  with  these values in <unistd.h>.

関連情報