stdin、stdout、stderrは、プロセスに使用するI / Oチャネルを「認識」しているデータ構造にインデックスを付ける整数です。このデータ構造はすべてのプロセスに固有であることを理解しています。I / Oチャネルは、動的メモリ割り当てを備えたいくつかのデータ配列構造にすぎませんか?
stdin、stdout、stderrは、プロセスに使用するI / Oチャネルを「認識」しているデータ構造にインデックスを付ける整数です。このデータ構造はすべてのプロセスに固有であることを理解しています。I / Oチャネルは、動的メモリ割り当てを備えたいくつかのデータ配列構造にすぎませんか?
回答:
Unixライクなオペレーティングシステムでは、標準入力、出力およびエラーストリームは、ファイル記述子によって識別されます0
、1
、2
。Linuxでは、これらはのproc
ファイルシステムの下に表示されます/proc/[pid]/fs/{0,1,2}
。これらのファイルは、実際にはディレクトリ下の疑似端末デバイスへのシンボリックリンク/dev/pts
です。
疑似端末(PTY)は、仮想デバイスのペアである疑似端末マスター(PTM)と疑似端末スレーブ(PTS)(まとめて疑似端末ペアと呼ばれます)であり、IPCチャネルを提供します。端末デバイスに接続され、疑似端末を使用して入力を送信したり、前のプログラムから入力を受信したりするドライバプログラム。
重要な点は、疑似端末スレーブが通常の端末と同じように表示されることです。たとえば、非標準モードと標準モード(デフォルト)を切り替えることができます。このモードではSIGINT
、割り込み文字(通常は生成)時に信号 を生成するなど、特定の入力文字を解釈します。キーボードのCtrl+ Cを押すと)が疑似端末マスターに書き込まれるか、ファイルの終わり文字(通常は+ によって生成されます)が検出されると、nextはマスターread()
に戻り0
ます。端末がサポートするその他の操作には、エコーのオン/オフの切り替え、フォアグラウンドプロセスグループの設定などがあります。CtrlD
疑似端末にはいくつかの用途があります。
それらは、プログラムssh
がネットワークを介して接続された別のホストで端末指向プログラムを操作することを可能にします。端末指向プログラムは、対話型端末セッションで通常実行される任意のプログラムです。ソケットは前述の端末関連機能をサポートしていないため、このようなプログラムの標準入力、出力、およびエラーは直接ソケットに接続できません。
これらは、プログラムexpect
がスクリプトからインタラクティブな端末指向プログラムを駆動することを可能にします。
これらは、ターミナルxterm
関連の機能を提供するためなど、ターミナルエミュレータによって使用されます。
これらはscreen
、複数のプロセス間で単一の物理端末を多重化するなどのプログラムで使用されます。
これらはscript
、シェルセッション中に発生するすべての入力と出力を記録するようなプログラムで使用されます。
Linuxで使用されるUnix98スタイルのPTYは、次のように設定されます。
ドライバープログラムは、で疑似端末マスターマルチプレクサーを開き、そこでdev/ptmx
PTMのファイル記述子を受信し、PTSデバイスが/dev/pts
ディレクトリに作成されます。オープンによって取得される各ファイル記述子/dev/ptmx
は、独自のPTSが関連付けられた独立したPTMです。
ドライバープログラムはfork()
、子プロセスを作成するように呼び出します。子プロセスは、次の手順を実行します。
setsid()
子供は、子供がセッションリーダーである新しいセッションを開始するように要求します。これにより、子供は制御端末を失います。
子は、ドライバプログラムによって作成されたPTMに対応するPTSデバイスを開きます。子はセッションリーダーですが、制御端末がないため、PTSが子制御端末になります。
子はdup()
、スレーブデバイスのファイル記述子を標準入力、出力、およびエラーに複製するために使用します。
最後に、子はexec()
、疑似端末デバイスに接続される端末指向プログラムを起動するために呼び出します。
この時点で、ドライバープログラムがPTMに書き込むものはすべて、PTSの端末指向プログラムへの入力として表示されます。逆も同様です。
正規モードで動作している場合、PTSへの入力は行ごとにバッファリングされます。言い換えると、通常の端末と同様に、PTSから読み取るプログラムは、改行文字がPTMに書き込まれた場合にのみ入力行を受け取ります。バッファリングキャパシティが使い果たさwrite()
れると、入力の一部が消費されるまで、以降の呼び出しはブロックされます。
Linuxカーネルでは、ファイルに関連するシステムコールはopen()
、read()
、write()
stat()
などのユーザ空間のプログラムのための均一なファイルシステムインタフェースを提供する仮想ファイルシステム(VFS)層に実装されています。VFSを使用すると、カーネル内で異なるファイルシステムの実装を共存させることができます。ユーザースペースプログラムが前述のシステムコールを呼び出すと、VFSはその呼び出しを適切なファイルシステム実装にリダイレクトします。
下のPTSデバイスは、で定義さ/dev/pts
れているdevpts
ファイルシステムの実装によって管理され/fs/devpts/inode.c
、Unix98スタイルのptmx
デバイスを提供するTTYドライバは、で定義されていdrivers/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_num
により0
、バッファが「反転」しました1
。ときは、buf_num
変更、char_buf_ptr
およびflag_buf_ptr
によって識別されるバッファの先頭に設定したbuf_num
、とcount
に設定しました0
。
カーネルバージョン3.7以降、TTYフリップバッファはkmalloc()
、リングで編成されて割り当てられたオブジェクトに置き換えられました。通常の速度のIRQ駆動シリアルポートの通常の状況では、それらの動作は古いフリップバッファーの場合とほとんど同じです。2つのバッファが割り当てられ、カーネルは以前と同様にそれらの間を循環します。ただし、遅延がある場合や速度が向上する場合、バッファプールが少し大きくなる可能性があるため、新しいバッファの実装のパフォーマンスは向上します。
3つのいずれかのmanページから、答えを説明しています。
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>.
stdin
、stdout
およびstderr
Cライブラリの観点から説明していますが、問題はカーネルの実装に関するものです。私の回答では、カーネルの視点を説明しようとしました。