<!--Chapter 5 Interprocess Communication Mechanisms-->
<sect>プロセス間通信の仕組み<label id="chapter_ipc">
<p>
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
Processes communicate with each other and with the kernel to coordinate their
activities. Linux supports a number of Inter-Process Communication (IPC)
mechanisms. Signals and pipes are two of them but Linux also supports the
System V IPC mechanisms named after the Unix TM release in which they first
appeared. 
-->
<p>プロセスは、他のプロセスやカーネルと相互に通信することで、自らの作業の調整
を図っている。Linux では、いくつかのプロセス間通信(Inter-Process 
Communication, IPC)のメカニズムがサポートされている。シグナルとパイプは
その典型であるが、Linux は System V IPC メカニズムもサポートしている。System V
 IPC という名称は、Unix の当該リリースで初めて登場したことからその名が付けられ
ている。

<!--5.1  Signals-->
<sect1>シグナル<label id="chapter_ipc_sect1">

<!--
Signals are one of the oldest inter-process communication methods used by Unix
TM systems. They are used to signal asynchronous events to one or more
processes. A signal could be generated by a keyboard interrupt or an error
condition such as the process attempting to access a non-existent location in 
its virtual memory. Signals are also used by the shells to signal job control
commands to their child processes. 
-->
<p>シグナルは、Unix システムで使用される最も古いプロセス間通信の方法である。
シグナルは、ひとつ以上のプロセスに対して非同期イベント(asynchronous events)を
伝達するために使用される。シグナルが生成されるのは、キーボード割り込みがあっ
たり、プロセスが仮想メモリ内に存在しない場所にアクセスしようとしてエラーが起
きたときなどである。シグナルは、シェルが子プロセスに対してジョブ制御の信号を
伝達するときにも利用される。

<!--
There are a set of defined signals that the kernel can generate or that can be
generated by other processes in the system, provided that they have the correct
privileges. You can list a system's set of signals using the kill command 
(kill -l), on my Intel Linux box this gives: 
-->
<p>一連の定義済みシグナルがあり、それらはカーネルによって生成されるが、正しい
権限を与えられているなら、システム上のカーネル以外のプロセスでも生成が可能で
ある。<tt>kill</tt> コマンド (<tt>kill -l</tt>) を使用すれば、システム上で
利用可能なシグナルのリストを得ることができる。わたしの Intel の Linux ボック
スでは次のような結果が表示された。

<verb>
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
 5) SIGTRAP      6) SIGIOT       7) SIGBUS       8) SIGFPE
 9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     17) SIGCHLD
18) SIGCONT     19) SIGSTOP     20) SIGTSTP     21) SIGTTIN
22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO
30) SIGPWR      
</verb>

<!--
The numbers are different for an Alpha AXP Linux box. Processes can choose to
ignore most of the signals that are generated, with two notable exceptions:
neither the SIGSTOP signal which causes a process to halt its execution nor the
SIGKILL signal which causes a process to exit can be ignored. Otherwise
though, a process can choose just how it wants to handle the various signals.
Processes can block the signals and, if they do not block them, they can either
choose to handle them themselves or allow the kernel to handle them. If the
kernel handles the signals, it will do the default actions required for this 
signal. For example, the default action when a process receives the SIGFPE 
(floating point exception) signal is to core dump and then exit. Signals have 
no inherent relative priorities. If two signals are generated for a process at
the same time then they may be presented to the process or handled in any 
order. Also there is no mechanism for handling multiple signals of the same 
kind. There is no way that a process can tell if it received 1 or 42 SIGCONT 
signals. 
-->
<p>シグナルの番号は、Alpha AXP の Linux ボックスでは異なったものになる。プロセ
スは、生成されたシグナルの大部分を無視することもできるが、ふたつだけ有名な
例外がある。プロセスの実行を停止させる SIGSTOP シグナルと、プロセスを終了させ
る SIGKILL シグナルであり、これらは無視できない。それ以外については、プロセス
が様々なシグナルをどう処理するかを自分で選択できる。プロセスはシグナルを
ブロックすることができるが、ブロックしない場合は、自分自身で処理するか、
あるいはカーネルに処理してもらうこともできる。
カーネルがシグナルを処理する場合、そのシグナル
が要求するデフォルトの行為が実行される。たとえば、プロセスが SIGFPE (floatin 
point exception)シグナルを受け取った際のデフォルトの行為は、core dump を行って
終了することである。シグナルには、内在的な相対的優先順位といったものはない。
ひとつのプロセスに対してふたつのシグナルが同時に生成された場合、それらがプロ
セスに渡される順番も、プロセスが処理すべき順番も決まっていない。また、同じ
種類の重複したシグナルを処理するメカニズムというのも存在しない。プロセスは、
SIGCOUNT をひとつだけ受け取ったのか、それともそれを 42 個受け取ったのかと
いうことを伝えるべき方法を持たない。

<!--
Linux implements signals using information stored in the task_struct for the
process. The number of supported signals is limited to the word size of the
processor. Processes with a word size of 32 bits can have 32 signals whereas 64
bit processors like the Alpha AXP may have up to 64 signals. The currently
pending signals are kept in the signal field with a mask of blocked signals 
held in blocked. With the exception of SIGSTOP and SIGKILL, all signals can be
blocked. If a blocked signal is generated, it remains pending until it is 
unblocked. Linux also holds information about how each process handles every 
possible signal and this is held in an array of sigaction data structures 
pointed at by the task_struct for each process. Amongst other things it 
contains either the address of a routine that will handle the signal or a flag
which tells Linux that the process either wishes to ignore this signal or let 
the kernel handle the signal for it. The process modifies the default signal 
handling by making system calls and these calls alter the sigaction for the 
appropriate signal as well as the blocked mask. 
-->
<p>Linux のシグナルの実装では、プロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> 構造体に保存された情報が利用される。
サポートされるシグナルの数は、プロセッサのワード(<ref id="chapter_g_word" 
name="word">)サイズに制限されている。
32 ビットのワードサイズを持つプロセッサは、32 個のシグナルを持つことが出来る
が、Alpha AXP のような 64 ビットプロセッサでは 64 個までである。
まだ処理の済んでいないシグナルは、<tt>task_struct</tt> の <tt><ref 
id="task_struct" name="signal"></tt> フィールドに保存され、<tt><ref 
id="task_struct" name="blockd"></tt> フィールドにブロックされたシグナルの
シグナルマスク(<ref id="signal_mask" name="signal mask">)が保持される。
SIGSTOP と SIGKILL を除いて、すべてのシグナルはブロックすることができる。
ブロックされたシグナルが生成されると、それはブロックを解除されるまで未処理
状態に留まる。また、Linux は、個々のプロセスが受け取るかもしれないあらゆる
シグナルをどう処理するのかに関する情報を保持しているのだが、その情報は <tt>
<ref id="sigaction" name="sigaction"></tt> データ構造体の配列に保存され、個々
のプロセスの <tt>task_struct</tt> データ構造体によってポイントされている。
それ以外にも、<tt>task_struct
</tt> には、シグナルを処理するルーチンのアドレスか、もしくはフラグのいずれか
が含まれている。フラグを使う場合、プロセスは、当該シグナルを無視するか、
そのシグナルの処理をカーネルに代行させるかをそのフラグによって Linux に伝える。
プロセスは、システムコールを使ってシグナルに対するデフォルト処理を変更すること
ができ、そのシステムコールによって適切なシグナルに関する <tt>sigaction</tt> 
構造体を変更したり、<tt>blockd</tt> マスクを変化させたりする。

<!--
Not every process in the system can send signals to every other process, the
kernel can and super users can. Normal processes can only send signals to
processes with the same uid and gid or to processes in the same process group1.
Signals are generated by setting the appropriate bit in the task_struct's
signal field. If the process has not blocked the signal and is waiting but
interruptible (in state Interruptible) then it is woken up by changing its 
state to Running and making sure that it is in the run queue. That way the 
scheduler will consider it a candidate for running when the system next 
schedules. If the default handling is needed, then Linux can optimize the 
handling of the signal. For example if the signal SIGWINCH (the X window 
changed focus) and the default handler is being used then there is nothing to 
be done. 
-->
<p>システム上の全プロセスが他のどのプロセスにもシグナルを送れるというわけでは
ないが、カーネルとスーパーユーザにはそれが可能である。通常のプロセスは、
同じ <tt>uid</tt> や <tt>gid</tt> を持つプロセスか、同じプロセスグループに
属するプロセスにのみシグナルを送れる。<ref id="chapter_ipc_fn" name="(脚注1)">
シグナルの生成は、<tt><ref id="task_struct" 
name="task_struct"></tt> の <tt>signal</tt> フィールドにある適切なビットを
セットすることにより為される。プロセスがシグナルをブロック
しておらず、待機中だが割り込み可能な(INTERRUPTIBLE な)状態にある場合、そのプロ
セスは、目を覚まして実行中(RUNNING)状態に置かれ、実行キューへ登録されて、その
登録を確認される。それによって、スケジューラは、システムの次のスケジュールに
おいて、そのプロセスを実行の候補者と見なす。デフォルトの処理が必要な場合、
Linux はそのシグナルの処理を最適化できる。たとえば、シグナル SIGWINCH 
(X Window のフォーカス変更)が生成され、それに対してデフォルトのハンドラが使用
される場合は、そのハンドラによって適切な処理がなされるので、それ以外の特別な
処理はなされない。

<!--
Signals are not presented to the process immediately they are generated., they
must wait until the process is running again. Every time a process exits from a
system call its signal and blocked fields are checked and, if there are any
unblocked signals, they can now be delivered. This might seem a very unreliable
method but every process in the system is making system calls, for example to
write a character to the terminal, all of the time. Processes can elect to 
wait for signals if they wish, they are suspended in state Interruptible until
a signal is presented. The Linux signal processing code looks at the sigaction
structure for each of the current unblocked signals. 
-->
<p>シグナルは生成されてすぐにプロセスに渡されるわけではない。それらはプロセスが
再び実行されるまで待たなければならない。プロセスがシステムコールによって終了
するときはいつでも、<tt><ref id="task_struct" name="signal"></tt> と <tt>
<ref id="task_struct" name="blocked"></tt> フィールドがチェック
され、もしプロセスが予めブロックしていないシグナルが存在する場合は、その時点で
ようやくプロセスにシグナルを渡すことができる。これは非常に信頼性の低い方法に
思われるかもしれないが、システム内のすべてのプロセスは、始終システムコールを
発して、たとえば、端末に文字を書き込んだりしているので、こうした仕組みはやむを
得ないものである。しかし、プロセスは、自分が望む場合は、自らシグナル待ちの
状態になることもできる。その場合、シグナルが送られるまで、割り込み可能な
サスペンド状態となる。その際、Linux のシグナル処理のコードは、現在ブロック
されていないシグナルを受け取るたびに、<tt><ref id="sigaction" 
name="sigaction"></tt> 構造体を調べる。

<!--
If a signal's handler is set to the default action then the kernel will handle
it. The SIGSTOP signal's default handler will change the current process's 
state to Stopped and then run the scheduler to select a new process to run. 
The default action for the SIGFPE signal will core dump the process and then 
cause it to exit. Alternatively, the process may have specfied its own signal 
handler. This is a routine which will be called whenever the signal is 
generated and the sigaction structure holds the address of this routine. The 
kernel must call the process's signal handling routine and how this happens is
processor specific but all CPUs must cope with the fact that the current 
process is running in kernel mode and is just about to return to the process 
that called the kernel or system routine in user mode. The problem is solved 
by manipulating the stack and registers of the process. The process's program 
counter is set to the address of its signal handling routine and the 
parameters to the routine are added to the call frame or passed in registers. 
When the process resumes operation it appears as if the signal handling 
routine were called normally. 
-->
<p>プロセスのシグナルハンドラがデフォルトにセットされている場合、カーネルが
そのシグナルを処理する。SIGSTOP シグナルのデフォルトのハンドラは、現在のプロ
セスの状態を停止状態(STOPPED)とし、スケジューラを起動して新しいプロセスを実行
する。SIGFPE シグナルのデフォルトの処理は、そのプロセスに core dump させ、
それを終了させる。反対に、プロセスが自分自身のシグナルハンドラを指定すること
もできる。これは、そのシグナルが生成されると必ず呼び出されるルーチンとな
り、<tt><ref id="sigaction" name="sigaction"></tt> 構造体がそのルーチンのアド
レスを保持する。その場合、カーネルはプロセスのシグナル処理ルーチンを呼び出
さなければならず、その呼び出し方法はプロセッサに固有のものであるが、
すべての CPU が対処しなければならない事実として、カーネルモードで実行されて
いるカレントプロセスは、カーネルやシステムルーチンを呼び出した時のユーザモー
ドのプロセスへと戻ろうとしているということである。
この問題を解決するために、プロセスのスタックとレジスタが操作される。プロセスの
プログラムカウンタには、そのシグナル処理ルーチンのアドレスが設定され、
そのルーチンへのパラメータがコールフレームに付加されるか、レジスタに渡される。
プロセスが再び実行を開始するとき、シグナル処理ルーチンは通常通り呼び出された
かのように見える。

<!--
Linux is POSIX compatible and so the process can specify which signals are
blocked when a particular signal handling routine is called. This means 
changing the blocked mask during the call to the processes signal handler. The
blocked mask must be returned to its original value when the signal handling 
routine has finished. Therefore Linux adds a call to a tidy up routine which 
will restore the original blocked mask onto the call stack of the signalled 
process. Linux also optimizes the case where several signal handling routines 
need to be called by stacking them so that each time one handling routine 
exits, the next one is called until the tidy up routine is called. 
-->
<p>Linux は POSIX に準拠しているので、プロセスは、特定のシグナル処理ルーチン
が呼び出されたとき、そのシグナルをブロックするかどうか指定ができる。
これは、プロセスのシグナル処理ルーチンの呼び出しがなされている間にブロック
マスクを変更することを意味する。シグナル処理ルーチンが終了したら、そのブロック
マスクの値は元に戻されなければならない。したがって、Linux は、片づけ用のルー
チン(tidy up routine)へのコールを追加して、そのルーチンがシグナルを受け取った
プロセスのコールスタック上のブロックマスクを元に戻す。
また、Linux は、複数のシグナル処理ルーチンの呼び出しが必要な場合、それらを
スタックに積んでおいて、ひとつの処理ルーチンが終了したら次のルーチンを呼び出す
操作を繰り返して、最後に片づけルーチンを呼び出すという方法でそうした処理を最適
化している。

<!--5.2  Pipes-->
<sect1>パイプ<label id="chapter_ipc_sect2">

<!--
The common Linux shells all allow redirection. For example 
-->
<p>一般的な Linux シェルは、すべてリダイレクション(redirection)をサポートして
いる。たとえば、次のようなリダイレクションがある。

<tscreen><verb>
$ ls | pr | lpr
</verb></tscreen>

<!--
pipes the output from the ls command listing the directory's files into the
standard input of the pr command which paginates them. Finally the standard
output from the pr command is piped into the standard input of the lpr command
which prints the results on the default printer. Pipes then are unidirectional
byte streams which connect the standard output from one process into the 
standard input of another process. Neither process is aware of this 
redirection and behaves just as it would normally. It is the shell which sets 
up these temporary pipes between the processes. 
-->
<p>上記の例では、ディレクトリ内のファイルを表示する <tt>ls</tt> コマンドの
出力をパイプ処理して、<tt>pr</tt> コマンドの標準入力に振り向けて、<tt>pr</tt> 
にページ処理をさせる。そうして、そのコマンド出力をパイプ処理して、<tt>lpr</tt> 
コマンドの標準入力に振り向けて、デフォルトプリンタ上でその結果をプリントさせ
ている。すなわち、パイプとは、あるプロセスの標準出力を別のプロセスの標準入力
へと繋ぐ、片方向性をもったバイトストリームである。その場合、どちらのプロセス
もリダイレクションを意識せず、通常通りに振る舞う。プロセス間にそれらの一時的
なパイプを設定するのはシェルの役目である。

<label id="figure5-1">
<!--                        Figure 5.1: Pipes-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-1.gif">
</figure>
</#if>
<#unless output="html">
<verb>
 プロセス 1                             プロセス 2

    file                                  file
+-----------+                         +-----------+
| f_mode    |                         | f_mode    |
|-----------|                         |-----------|
| f_pos     |                         | f_pos     |
|-----------|                         |-----------|
| f_flags   |                         | f_flags   |
|-----------|                         |-----------|
| f_count   |                         | f_count   |
|-----------|                         |-----------|
| f_owner   |      +---------------+  | f_owner   |
|-----------|      |               |  |-----------|
| f_inode   |---+  |    inode      |  | f_inode   |-----+
|-----------|   |  |  +---------+  |  |-----------|     |
| f_op      |-+ |  +->|         |  |  | f_op      |--+  |
|-----------| | +---->|         |  |  |-----------|  |  |
| f_version | |       |         |  |  | f_version |  |  |
+-----------+ |       |         |  |  +-----------+  |  |
              |       |         |  |                 |  |
              |/      +---------+  +-----------------+--+
              *               |                      |
            パイプ            |       データページ   |
            書き込み          |       +-----------+  |
            操作ルーチン      |       |           |  |/
                              +------>|           |  *
                                      |           | パイプ
                                      |           | 読み出し
                                      |           | 操作ルーチン
                                      |           |
                                      |           |
                                      |           |
                                      +-----------+
</verb>
</#if>
<p>図表(5.1) パイプ

<!--
In Linux, a pipe is implemented using two file data structures which both point
at the same temporary VFS inode which itself points at a physical page within
memory. Figure  5.1 shows that each file data structure contains pointers to
different file operation routine vectors; one for writing to the pipe, the 
other for reading from the pipe. 
This hides the underlying differences from the generic system calls which read
and write to ordinary files. As the writing process writes to the pipe, bytes 
are copied into the shared data page and when the reading process reads from 
the pipe, bytes are copied from the shared data page. Linux must synchronize 
access to the pipe. It must make sure that the reader and the writer of the 
pipe are in step and to do this it uses locks, wait queues and signals. 
-->
<p>Linux において、パイプの実装には、ふたつの <tt><ref id="file" name="file">
</tt> データ構造体が使用される。メモリ内のある物理ページをポイントする VFS 
inode を一時的に作成して、それをふたつの構造体で同時にポイントするのである。
図表(5.1)では、それぞれの <tt>file</tt> データ構造体が、ファイル操作ルーチン
の配列の異なる要素をポイントしている様子が示されている。ひとつは、パイプへ
の書き込みであり、もうひとつは、パイプからの読み出しである。
<newline>[see: include/linux/inode_fs_i.h](ママ)
(訳注: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/pipe_fs_i.h" 
name="pipe_fs_i.h"> ？)<newline>
この方法では、通常ファイルへの書き込み処理と読み出し処理をする汎用システム
コール間にある基礎的な違いは隠蔽される。書き込みプロセスがパイプに書き込むと
き、バイト列は共有データページにコピーされ、読み出しプロセスがパイプから読み
出すときは、バイト列がその共有データページからコピーされる。Linux は、その
パイプへのアクセスを同期させなければならない。Linux は、パイプからの読み出し
と、そこへの書き込みとが確実に歩調を合わせるようにしなければならず、そのため
に Linux は、ロック(<ref id="chapter_km_sect5" name="lock">)や待ち行列(<ref 
id="chapter_km_sect4" name="wait queue">)やシグナル(signal)といった仕組
みを利用している。

<!--
When the writer wants to write to the pipe it uses the standard write library
functions. These all pass file descriptors that are indices into the process's
set of file data structures, each one representing an open file or, as in this
case, an open pipe. The Linux system call uses the write routine pointed at by
the file data structure describing this pipe. That write routine uses 
information held in the VFS inode representing the pipe to manage the write 
request. 
If there is enough room to write all of the bytes into the pipe and, so long 
as the pipe is not locked by its reader, Linux locks it for the writer and 
copies the bytes to be written from the process's address space into the 
shared data page. If the pipe is locked by the reader or if there is not 
enough room for the data then the current process is made to sleep on the pipe
inode's wait queue and the scheduler is called so that another process can 
run. It is interruptible, so it can receive signals and it will be woken by 
the reader when there is enough room for the write data or when the pipe is 
unlocked. When the data has been written, the pipe's VFS inode is unlocked and
any waiting readers sleeping on the inode's wait queue will themselves be 
woken up. 
-->
<p>書き込みプロセスがパイプに書き込もうとするときは、標準の書き込みライブラリ
関数を使用する。
それらの間でやり取りされるファイルディスクリプタはすべて、書き込みプロセ
スが持つ一連の <tt><ref id="file" name="file"></tt> データ構造体へのインデッ
クスとなっていて、それら個々の構造体がオープンされたファイル、この場合には
オープンされたパイプを表している。
Linux のシステムコールが使用する書き込みルーチンは、そのパイプを記述する 
<tt>file</tt> データ構造体によってポイントされたルーチンである。書き込み
ルーチンが書き込み要求を処理する際に利用する情報は、そのパイプを表す VFS <tt>
<ref id="inode" name="inode"></tt> に保持された情報である。
<newline>[see: pipe_write(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/pipe.c" 
name="fs/pipe.c">]<newline>
パイプへ書き込もうとする全バイト量を保持するだけの空きが共有ページ上に存在し、
パイプが読み出しプロセスによってロックされていない場合、Linux は書き込み
プロセスのためにそのパイプをロックして、書き込まれるべきバイト列を書き込み
プロセスのアドレス空間から共有データページにコピーする。
パイプが読み出しプロセスによってロックされているか、データを保持する充分な空
きスペースが存在しない場合は、現在のプロセスがパイプの <tt>inode</tt> の待ち
行列上でスリープ状態にされ、スケジューラが呼び出されて、他のプロセスが実行
される。
書き込みプロセスは割り込み可能であるので、シグナルの受信が可能である。
書き込みプロセスは、データ書き込みのための充分なスペースが確保されるか
パイプのロックが解除されたときに、読み込みプロセスによってスリープ状態から
起こされる。
データが書き込まれるとき、パイプの VFS inode のロックは解除され、
その inode の待ち行列上でスリープ状態になっている読み出しプロセスがあれば、
読み出しプロセスもそれによって目を覚ます。

<!--
Reading data from the pipe is a very similar process to writing to it. 
Processes are allowed to do non-blocking reads (it depends on the mode in
which they opened the file or pipe) and, in this case, if there is no data to 
be read or if the pipe is locked, an error will be returned. This means that 
the process can continue to run. The alternative is to wait on the pipe 
inode's wait queue until the write process has finished. When both processes 
have finished with the pipe, the pipe inode is discarded along with the shared
data page. 
-->
<p>パイプからのデータの読み出しは、書き込みプロセスと非常によく似ている。
<newline>[see: pipe_read(), in <htmlurl 
url="./The-Linux-Kernel-images/linux/fs/pipe.c" 
name="fs/pipe.c">]<newline>
プロセスは、ブロッキングしない読み出し(non-blocking read)をすることも
許される。(それは、プロセスがファイルやパイプをオープンするときのモードに
依存する。)そして、その場合、読み出すべきデータがないか、パイプがロックされて
いる場合は、エラーが返される。これは、そのプロセスが実行を継続できることを
意味する。それ以外の方法として、パイプの inode の待ち行列上で休止して、書き込み
プロセスの終了を待つことも可能である。両方のプロセスがパイプ処理を終了する
と、パイプの inode とその共有データページとは破棄される。

<!--
Linux also supports named pipes, also known as FIFOs because pipes operate on
a First In, First Out principle. The first data written into the pipe is the 
first data read from the pipe. Unlike pipes, FIFOs are not temporary objects, 
they are entities in the file system and can be created using the mkfifo 
command. Processes are free to use a FIFO so long as they have appropriate 
access rights to it. The way that FIFOs are opened is a little different from 
pipes. A pipe (its two file data structures, its VFS inode and the shared data
page) is created in one go whereas a FIFO already exists and is opened and 
closed by its users. Linux must handle readers opening the FIFO before writers
open it as well as readers reading before any writers have written to it. That
aside, FIFOs are handled almost exactly the same way as pipes and they use the
same data structures and operations. 
-->
<p>Linux は、名前付きパイプもサポートしている。パイプは先入れ先出し(First In,
 First Out)の原理で処理を行うので、名前付きパイプは FIFO とも呼ばれる。
パイプに書き込まれた最初のデータは、パイプから読み出される最初のデータとな
る。通常のパイプとは異なり、FIFO は一時的なオブジェクトではなく、ファイルシス
テム内の実体であり、<tt>mkfifo</tt> コマンドによって作成が可能である。
プロセスは、それに対する適切なアクセス権限を持つ限り、自由に FIFO を利用する
ことができる。FIFO をオープンする方法は、通常のパイプのそれとは少し異なる。
通常のパイプ(ふたつの <tt>file</tt> データ構造体、VFS inode とその共有データ
ページのセット)は必要に応じて一時的に作成されるだけだが、FIFO はすでに
存在する実体であり、ユーザによってオープンされ、クローズされる。Linux は、
書き込みプロセスが FIFO をオープンする前に読み出しプロセスにそれをオープンさ
せ、書き込みプロセスがそれに書き込んでしまう前に読み出しプロセスがそれを読める
状態にするよう、それらを操作しなければならない。しかし、そうした
ことを除くと、FIFO の処理は、通常のパイプの処理方法とほとんど全く同一であり、
両者は同じデータ構造と処理メカニズムを使っている。


<!--5.3  Sockets-->
<sect1>ソケット<label id="chapter_ipc_sect3">
<p>
REVIEW NOTE: Add when networking chapter written. 


<!--5.3.1  System V IPC Mechanisms-->
<sect2>System V IPC のメカニズム<label id="chapter_ipc_sect3-1">

<!--
Linux supports three types of interprocess communication mechanisms that first
appeared in Unix TM System V (1983). These are message queues, semaphores
and shared memory. These System V IPC mechanisms all share common
authentication methods. Processes may access these resources only by passing
a unique reference identifier to the kernel via system calls. Access to these
System V IPC objects is checked using access permissions, much like accesses
to files are checked. The access rights to the System V IPC object is set by 
the creator of the object via system calls. The object's reference identifier 
is used by each mechanism as an index into a table of resources. It is not a 
straight forward index but requires some manipulation to generate the index. 
-->
<p>Linux は、Unix System V (1983) で初めて登場したプロセス間通信(IPC)の仕組み
を 3 種類サポートしている。それらは、メッセージキュー(message queue)、セマフォ
(semaphore)、そして共有メモリ(shared memory)である。これらの System V IPC の
仕組みはすべて共通の認証方法を利用している。プロセスが共有リソースに
アクセスできるのは、システムコール経由でカーネルに対してユニークな参照識別子
(reference identifier)を渡した場合だけである。
これらの System V IPC オブジェクトへのアクセスをチェックする
場合には、アクセスパーミッションが使用されるが、それはファイルへのアクセス
チェックに類似したものである。System V IPC オブジェクトへのアクセス権限は、
そのオブジェクトの作成者によってシステムコール経由で設定される。個々の IPC 
メカニズムは、オブジェクトの参照識別子を、リソーステーブルへのインデックスと
して利用している。しかし、それは単純なインデックスではなく、そのインデックス
作成には多少の操作を必要とする。

<!--
All Linux data structures representing System V IPC objects in the system
include an ipc_perm structure which contains the owner and creator process's 
user and group identifiers. The access mode for this object (owner, group and 
other) and the 
IPC object's key. The key is used as a way of locating the System V IPC 
object's reference identifier. Two sets of keys are supported: public and 
private. If the key is public then any process in the system, subject to 
rights checking, can find the reference identifier for the System V IPC 
object. System V IPC objects can never be referenced with a key, only by their
reference identifier. 
-->
<p>Linux システム上で System V IPC オブジェクトを表すすべてのデータ構造には、
<tt><ref id="ipc_perm" name="ipc_perm"></tt> 構造体が含まれている。そして、
その構造体には、そのオブジェクトの所有プロセスおよび作成プロセスのユーザ ID 
とグループ ID とが含まれる。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/ipc.h" 
name="include/linux/ipc.h">]<newline>
また、<tt>ipc_perm</tt> には、そのオブジェクトへのアクセスモード(所有者、
グループ、その他)と IPC オブジェクトキー(<tt><ref id="ipc_perm" name="key">
</tt>)も含まれている。
キーは、System V IPC オブジェクトの参照識別子を探す手段として使用される。
サポートされているキーには、プライベート(private)とパブリック(public)の二種類
がある。キーがパブリックの場合、どのようなプロセスでも、アクセス権をチェック
された後、その System V IPC オブジェクトの参照識別子を見つけることができる。
System V IPC オブジェクトは、キーでは参照できないようになっていて、その参照
識別子でのみ参照が可能となっている。

<!--5.3.2  Message Queues-->
<sect2>メッセージキュー<label id="chapter_ipc_sect3-2">

<!--
Message queues allow one or more processes to write messages, which will be
read by one or more reading processes. Linux maintains a list of message
queues, the msgque vector; each element of which points to a msqid_ds data
structure that fully describes the message queue. When message queues are
created a new msqid_ds data structure is allocated from system memory and
inserted into the vector. 
-->
<p>メッセージキュー(message queue)とは、ひとつ以上のプロセスがメッセージを書
き込んで、それをひとつ以上の読み出しプロセスによって読み出すことを可能にする
仕組みである。Linux は、メッセージキューのリストを <tt><ref id="msqid_ds" 
name="msque" ></tt> 配列によって管理している。この配列の個々の要素は、
<tt><ref id="msqid_ds" name="msqid_ds"></tt> データ構造体をポイントしてい
て、その構造体が個々のメッセージキューを完全に記述している。メッセージキューが
作成されるとき、新しい <tt>msqid_ds</tt> データ構造体がシステムメモリから割り
当てられ、配列のなかに挿入される。
<newline>[see: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/msg.h" 
name="include/linux/msg.h">]<newline>

<!--              Figure 5.2: System V IPC Message Queues-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-2.gif">
</figure>
</#if>
<#unless output="html">
<verb>
   msqid_ds
+--------------+
|              |
|  ipc         |
|              |
|--------------|
|              |
|--------------|
|  *msg_last   |                msg                      msg
|--------------|            +------------+            +-----------+
|  *msg_first  |----------->| *msg_next  |----------->| *msg_next |
|--------------|            |------------|            |-----------|
|              |            | msg_type   |            | msg_type  |
|  times       |            |------------|            |-----------|
|              |            | *msg_spot  |            | *msg_spot |
|--------------|            |------------|            |-----------|
|  *wwait      |            | msg_stime  |            | msg_stime |
|--------------|            |------------|            |-----------|
|  *rwait      |            | msg_ts     |            | msg_ts    |
|--------------|       *    |------------|       *    |-----------|
|              |      /|    |            |      /|    |           |
|--------------|       |    |            |       |    |           |
|  msg_qnum    |       |    |            |       |    |           |
|--------------|     msg_ts |  message   |     msg_ts |  message  |
|              |       |    |            |       |    |           |
+--------------+       |    |            |       |    |           |
                       |/   |            |       |/   |           |
                       *    +------------+       *    +-----------+

                            <---------------- msg_qnum ----------->
</verb>
</#if>
<p>図表(5.2)System V IPC メッセージキュー


<!--
Each msqid_ds 
data structure contains an ipc_perm data structure and pointers to the
messages entered onto this queue. In addition, Linux keeps queue modification
times such as the last time that this queue was written to and so on. The
msqid_ds also contains two wait queues; one for the writers to the queue and
one for the readers of the message queue. 
-->
<p>個々の <tt><ref id="msqid_ds" name="msqid_ds"></tt> 構造体には、<tt>
<ref id="ipc_perm" name="ipc_perm"></tt> データ構造体とそのキューに入れられた
メッセージへのポインタが含まれている。さらに、Linux は、キューの変更時間を記録
しており、たとえばそのキューに書き込みがなされた最後の時間といった情報を保持
している。<tt>msqid_ds</tt> には、ふたつの待ち行列が含まれていて、それぞれ
メッセージキューへの書き込みプロセスに対するものと読み出しプロセスに対する
ものとなっている。

<!--
Each time a process attempts to write a message to the write queue its 
effective user and group identifiers are compared with the mode in this 
queue's ipc_perm data structure. If the process can write to the queue then 
the message may be copied from the process's address space into a msg 
data structure and put at the end of this message queue. Each message is tagged
with an application specific type, agreed between the cooperating processes.
However, there may be no room for the message as Linux restricts the number
and length of messages that can be written. In this case the process will be
added to this message queue's write wait queue and the scheduler will be called
to select a new process to run. It will be woken up when one or more messages
have been read from this message queue. 
-->
<p>プロセスが書き込みキューにメッセージを書き込もうとするときはいつも、その
実効ユーザ ID と実効グループ ID とが、そのキューの <tt>ipc_perm</tt> データ
構造体にあるモードと比較される。
プロセスがそのキューに書き込み可能な場合、メッセージは、そのプロセスのアドレ
ス空間から <tt><ref id="msg" name="msg"></tt> データ構造体へとコピーされ、そ
のメッセージキューの最後に置かれる。個々のメッセージには、協調するプロセス間で
合意されたアプリケーション固有のタイプ(type)がタグ付けされる。しかし、Linux 
は、書き込み可能なメッセージの数と長さを制限しているので、メッセージの書き込み
の際に容量が足りない場合が生じ得る。その場合、そのプロセスが当該メッセージ
キューの書き込みキューに加えられ、スケジューラが呼び出されて、新しいプロセス
が実行される。そして、いくつかのメッセージがそのメッセージキューから読み出さ
れたときに、先ほどのプロセスが起こされる。

<!--
Reading from the queue is a similar process. Again, the processes access rights
to the write queue are checked. A reading process may choose to either get the
first message in the queue regardless of its type or select messages with
particular types. If no messages match this criteria the reading process will 
be added to the message queue's read wait queue and the scheduler run. When a
new message is written to the queue this process will be woken up and run 
again.
-->
<p>キューからの読み出しも同様の過程を辿る。再度、書き込みキューに対するプロセ
スのアクセス権がチェックされる。読み出しプロセスは、メッセージのタイプに関係
なくキューの最初のメッセージを取得するか、特定のタイプのメッセージを選択する
かのいずれかを選択することができる。選択基準に合致するメッセージがない場合、
読み出しプロセスはメッセージキューの読み出し待ち行列に加えられて、スケジュー
ラが実行される。新しいメッセージがキューに書き込まれると、そのプロセスは起こ
されて再び実行される。

<!--5.3.3  Semaphores-->
<sect2>セマフォ<label id="chapter_ipc_sect3-3">

<!--
In its simplest form a semaphore is a location in memory whose value can be
tested and set by more than one process. The test and set operation is, so far
as each process is concerned, uninterruptible or atomic; once started nothing 
can stop it. The result of the test and set operation is the addition of the 
current value of the semaphore and the set value, which can be positive or 
negative. Depending on the result of the test and set operation one process 
may have to sleep until the semphore's value is changed by another process. 
Semaphores can be used to implement critical regions, areas of critical code 
that only one process at a time should be executing. 
-->
<p>最も単純な形式で考えると、セマフォとは、複数のプロセスにより、ある値をテスト
(test)したりセット(set)したりすることが可能な、メモリ上の場所である。
テストとセットの操作は、個々のプロセスに関する限り、割り込みができない、もし
くは他のプロセスから干渉を受けない(atomic)操作である。すなわち、いったんプロ
セスが操作を始めると他のプロセスがそれを止めることはできない。テストとセット
の操作の結果は、そのセマフォの現在の値とセットした値との和となる。セットされ
る値は、正の場合も負の場合もある。テストとセットの操作の結果によっては、ある
プロセスが、他のプロセスによってセマフォの値が変更されるまで、休止しなければ
ならない場合が起こる。セマフォは、非常に重要なメモリ領域を作成したいときに
利用することができ、一度に単一のプロセスだけが実行すべき非常に重要なコードの
領域を作り出すことができる。

<!--
Say you had many cooperating processes reading records from and writing
records to a single data file. You would want that file access to be strictly
coordinated. You could use a semaphore with an initial value of 1 and, around 
the file operating code, put two semaphore operations, the first to test and 
decrement the semaphore's value and the second to test and increment it. The 
first process to access the file would try to decrement the semaphore's value 
and it would succeed, the semaphore's value now being 0. This process can now 
go ahead and use the data file but if another process wishing to use it now 
tries to decrement the semaphore's value it would fail as the result would 
be -1. That process will be suspended until the first process has finished 
with the data file. When the first process has finished with the data file it 
will increment the semaphore's value, making it 1 again. Now the waiting 
process can be woken and this time its attempt to increment the semaphore will
succeed. 
-->
<p>たとえば、協調して働く多くのプロセスがあり、それらは単一のファイルを読み込
んだり、それに書き込んだりしているとする。そして、そのファイルへのアクセスを
厳しく調整したいと思っているとする。その場合、セマフォを使い、初期値を 1 に
設定し、ファイル操作コードの中に、ふたつのセマフォ操作コードを加える。ひとつ
は、セマフォの値をテストして、その値から 1 を引くもの、もうひとつは、セマフォ
値をテストして値に 1 を足すものである。
ファイルにアクセスする最初のプロセスは、セマフォの値から 1 を引こうとし、それに
成功すればセマフォの値は 0 になる。このプロセスは処理を続けて、データファイル
を使用するが、もし次のプロセスがそれを使いたいと思ってセマフォの値から 1 を引こ
うとしても、その結果が -1 になってしまうので失敗する。
そのプロセスは、最初のプロセスがデータファイルの使用を終えるまで、停止状態に
なる。最初のプロセスがデータファイルの使用を終えたら、セマフォの値に 1 を足
して、1 に戻す。この時点で、待機していたプロセスが起こされて、今回はセマフォ値
に 1 を足す(訳注: -1 か？)ことに成功する。


<!--                Figure 5.3: System V IPC Semaphores-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-3.gif">
</figure>
</#if>
<#unless output="html">
<verb>
                                 +-------+
                        +------->|       |  セマフォ配列
                        |        |-------|
     semid_ds           |        |       |
+------------------+    |        |-------|
|                  |    |        |       |
| ipc              |    |        |-------|
|                  |    |        |       |
|------------------|    |        |-------|
|                  |    |        |       |
| times            |    |        |-------|
|                  |    |        |       |
|------------------|    |        +-------+
| sem_base         |----+                       sem_queue
|------------------|                           +---------+
| sem_pending      |-------------------------->| next    |
|------------------|                           |---------|
| sem_pending_last |     sem_undo              | prev    |
|------------------|  +-----------+            |---------|
| undo             |->| proc_next |            | sleeper |
|------------------|  |-----------|            |---------|
| sem_nsems        |  | id_next   |            | undo    |
+------------------+  |-----------|            |---------|
                      | semid     |            | pid     |
                      |-----------|  +------+  |---------|
                      | semadj    |->|      |  | status  |
                      +-----------+  |      |  |---------|
                                     |      |  | sma     |
                                     |      |  |---------|  +------+
                                     |      |  | sops    |->|      |
                                     |      |  |---------|  |      |
                                     |      |  | nsops   |  |      |
                                     +------+  +---------+  |      |
                                                            |      |
                                                            |      |
                                                            |      |
                                                            +------+
</verb>
</#if>
<p>図表(5.3)System V IPC セマフォ


<!--
System V IPC semaphore objects each describe a semaphore array and Linux
uses the semid_ds data structure to represent this. 
All of the semid_ds data structures in the
system are pointed at by the semary, a vector of pointers. There are
sem_nsems in each semaphore array, each one described by a sem data
structure pointed at by sem_base. All of the processes that are allowed to
manipulate the semaphore array of a System V IPC semaphore object may make
system calls that perform operations on them. The system call can specify many
operations and each operation is described by three inputs; the semaphore 
index, the operation value and a set of flags. The semaphore index is an index
into the semaphore array and the operation value is a numerical value that 
will be added to the current value of the semaphore. First Linux tests whether
or not all of the operations would succeed. An operation will succeed if the 
operation value added to the semaphore's current value would be greater than 
zero or if both the operation value and the semaphore's current value are 
zero. If any of the semaphore operations would fail Linux may suspend the 
process but only if the operation flags have not requested that the system 
call is non-blocking. If the process is to be suspended then Linux must save 
the state of the semaphore operations to be performed and put the current 
process onto a wait queue. It does this by building a sem_queue data structure
on the stack and filling it out. The new sem_queue data structure is put at 
the end of this semaphore object's wait queue (using the sem_pending and 
sem_pending_last pointers). The current process is put on the wait queue in 
the sem_queue data structure (sleeper) and the scheduler called to choose 
another process to run. 
-->
<p>System V IPC セマフォオブジェクトは、それぞれがセマフォ配列を記述しており、
Linux は、<tt><ref id="semid_ds" name="semid_ds"></tt> データ構造体を使用して
これを表現する。
<newline>[see <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/sem.h" 
name="include/linux/sem.h">]<newline>
システム上のすべての <tt>semid_ds</tt> データ構造体は、 <tt><ref id="semid_ds" 
name="semary"></tt> というポインタの配列によってポイントされている。
個々のセマフォ配列には、<tt><ref id="semid_ds" name="sem_nsems"></tt> 個の
要素があり、各々のセマフォ配列の要素は、<tt><ref id="sem" name="sem"></tt> 
データ構造体により記述されていて、<tt>sem</tt> 構造体は <tt><ref id="semid_ds" 
name="sem_base"></tt> によってポイントされている。
System V IPC セマフォオブジェクトから成るセマフォ配列の操作を許されているすべて
のプロセスは、システムコールを生成して、それらを操作する。
システムコールは多くの操作を指定することができるが、個々の操作は、セマフォ
インデックス(semaphore index)、オペレーション値(operation value)、および一連の
フラグ(a set of flag)という 3 つの入力項目によって記述される。
セマフォインデックスとは、セマフォ配列へのインデックスであり、オペレーション
値とは、セマフォの現在の値に加えるべき数値である。
Linux はまず、すべての操作が成功したかどうかをテストする。操作が成功するのは、
セマフォの現在の値にオペレーション値を加えた値がゼロより大きいか、もしくは
オペレーション値とセマフォの現在の値の両方がゼロの場合のいずれかである。
セマフォ操作がひとつでも失敗した場合で、他のプロセスをブロックしない
(non-blocking)システムコールをオペレーションフラグが要求しない場合、Linux は、
プロセスをサスペンドする。
プロセスがサスペンド状態になると、Linux は実行されるべきセマフォ操作の状態
(state)を保存して、現在のプロセスを待ち行列(wait queue)上に置かなければなら
ない。
その処理は、スタックに <tt><ref id="sem_queue" name="sem_queue"></tt> データ
構造体を作成して、必要な情報を書き込むことによってなされる。新しい <tt>
sem_queue</tt> データ構造体は、そのセマフォオブジェクトの待ち行列の最後に置か
れる。(その際は、<tt><ref id="semid_ds" name="sem_pending"</tt> と 
<tt><ref id="semid_ds" name="sem_pending_last"></tt> ポインタが使用される。)
現在のプロセスは、<tt>sem_queue</tt> データ構造体の待ち行列上に(休止状態で)置
かれ、スケジューラが呼び出されて、次のプロセスが実行される。

<!--
If all of the semaphore operations would have succeeded and the current process
does not need to be suspended, Linux goes ahead and applies the operations to
the appropriate members of the semaphore array. Now Linux must check that any
waiting, suspended, processes may now apply their semaphore operations. It
looks at each member of the operations pending queue (sem_pending) in turn,
testing to see if the semphore operations will succeed this time. If they will
then it removes the sem_queue data structure from the operations pending list 
and applies the semaphore operations to the semaphore array. It wakes up the
sleeping process making it available to be restarted the next time the 
scheduler runs. Linux keeps looking through the pending list from the start 
until there is a pass where no semaphore operations can be applied and so no 
more processes can be woken. 
-->
<p>もしセマフォ操作がすべて成功し、現在のプロセスを停止させる必要がなければ、
Linux は処理を継続し、セマフォ配列の適切なメンバーにその操作を適用する。
この時点で、Linux は、待ち状態や停止状態にあるプロセスがそれぞれのセマフォ
操作を適用できるかどうかをチェックする。Linux は、操作ルーチンのペンディング
キュー(pending queue)(<tt><ref id="semid_ds" name="sem_pending"></tt>)のメン
バーそれぞれを順番に見て、今回はそのセマフォ操作が成功するかどうかをテスト
する。
成功した場合、Linux は、ペンディングリストからその <tt>sem_queue</tt> データ
構造体を削除して、セマフォ配列にそのセマフォ操作を適用する。
Linux は、休眠中のプロセスを起こして、次にスケジューラが実行されるときに再始動
されるようにする。Linux は、ペンディングリストを最初から順に調べていって、
適用できるセマフォ操作が無くなり、それ以上プロセスを起こせなくなるまで
それを続ける。

<!--
There is a problem with semaphores, deadlocks. These occur when one process
has altered the semaphores value as it enters a critical region but then fails
to leave the critical region because it crashed or was killed. Linux protects 
against this by maintaining lists of adjustments to the semaphore arrays. The 
idea is that when these adjustments are applied, the semaphores will be put 
back to the state that they were in before the a process's set of semaphore 
operations were applied. These adjustments are kept in sem_undo data 
structures queued both on the semid_ds data structure and on the task_struct 
data structure for the processes using these semaphore arrays. 
-->
<p>セマフォには、デッドロックという問題がある。それが起こるのは、あるプロセス
が、重要なメモリ領域に入ったときのに、クラッシュするか kill されるかしてそこ
から出られなくなり、セマフォ値が変更されたままになる場合である。Linux はこれを
防止するために、セマフォ配列に対する調整(adjustment)リストを管理している。
そのアイデアは、セマフォ配列に調整が適用されると、セマフォが、問題を起こした
プロセスの操作が適用される前の状態(state)に戻されるということである。
これらの調整は、<tt><ref id="sem_undo" name="sem_undo"></tt> データ構造体に
保存されていて、それは <tt><ref id="semid_ds" name="semid_ds"></tt> データ
構造体上のキューとそれらのセマフォ配列を使うプロセスの <tt><ref 
id="task_struct" name="task_struct"></tt> データ構造体上のキューとに置かれる。

<!--
Each individual semaphore operation may request that an adjustment be
maintained. Linux will maintain at most one sem_undo data structure per
process for each semaphore array. If the requesting process does not have one,
then one is created when it is needed. The new sem_undo data structure is
queued both onto this process's task_struct data structure and onto the
semaphore array's semid_ds data structure. As operations are applied to the
semphores in the semaphore array the negation of the operation value is added 
to this semphore's entry in the adjustment array of this process's sem_undo 
data structure. So, if the operation value is 2, then -2 is added to the 
adjustment entry for this semaphore. 
-->
<p>個々のセマフォ操作は、調整のためのデータ管理がなされるされることを個別に要求
する場合がある。Linux は、個々のセマフォ配列について、プロセスあたり最大ひと
つの <tt><ref id="sem_undo" name="sem_undo"></tt> データ構造体しか管理しない。
調整を要求するプロセスがそれをひとつも持っていない場合は、必要なときにひとつの
データ構造体が作成される。新しい <tt><ref id="sem_undo" 
name="sem_undo"></tt> データ構造体は、そのプロセスの <tt><ref id="task_struct"
 name="task_struct"></tt> データ構造体上のキューと、セマフォ配列の <tt>
<ref id="semid_ds" name="semid_ds"></tt> データ構造体上のキューとに入れられる。
セマフォ操作がセマフォ配列のセマフォに対して適用されるとき、オペレーション値
を正負逆にした値が、そのプロセスの <tt>sem_undo</tt> データ構造の調整
(adjustment)配列の中にあるセマフォエントリーに加えられる。
それゆえ、オペレーション値が 2 の場合、-2 がそのセマフォの調整エントリに加え
られる。

<!--
When processes are deleted, as they exit Linux works through their set of
sem_undo data structures applying the adjustments to the semaphore arrays. If
a semaphore set is deleted, the sem_undo data structures are left queued on the
process's task_struct but the semaphore array identifier is made invalid. In
this case the semaphore clean up code simply discards the sem_undo data
structure. 
-->
<p>プロセスが終了して削除されるとき、Linux は、そのプロセスの <tt>
<ref id="sem_undo" name="sem_undo"></tt> データ構造体のセットを調査して、
セマフォ配列に対する調整を適用する。セマフォセットが削除された場合、<tt>
sem_undo</tt> データ構造体は、プロセスの <tt><ref id="task_struct" 
name="task_struct"></tt> のキューに残ったままになるが、セマフォ配列の識別子は
無効になる。その場合、セマフォを片づける(clean up)コードが、単にその <tt>
sem_undo</tt> 構造体を破棄する。


<!--5.3.4  Shared Memory-->
<sect2>共有メモリ<label id="chapter_ipc_sect3-4">

<!--
Shared memory allows one or more processes to communicate via memory that
appears in all of their virtual address spaces. The pages of the virtual 
memory is referenced by page table entries in each of the sharing processes' 
page tables. It does not have to be at the same address in all of the 
processes' virtual memory. As with all System V IPC objects, access to shared 
memory areas is controlled via keys and access rights checking. Once the 
memory is being shared, there are no checks on how the processes are using it.
They must rely on other mechanisms, for example System V semaphores, to 
synchronize access to the memory. 
-->
<p>共有メモリ(shared memory)は、プロセスの仮想アドレス空間の任意の場所を経由
して、複数のプロセスが通信することを可能にする仕組みである。共有される仮想メ
モリのページは、個々の共有プロセスのページテーブル内にあるページテーブルエン
トリによって参照される。
共有されるページは、すべてのプロセスの仮想メモリ内の同一アドレスになくてもよ
い。System V IPC のオブジェクトを使う場合はすべて、共有メモリエリアへのアクセ
スは、キーとアクセス権限のチェックによって制御されている。(正当なアクセスに
より)いったんメモリが共有されたなら、プロセスがそれを使用する方法はチェック
されない。メモリへのアクセスの同期を取るといったことは、他の仕組み、たとえば、
System V のセマフォなどの仕組みに依存しなければならない。


<!--               Figure 5.4: System V IPC Shared Memory-->
<#if output="html">
<figure><ph vspace="1"><img src="./The-Linux-Kernel-images/figure5-4.gif">
</figure>
</#if>
<#unless output="html">
<verb>
  shmid_ds
+------------+
|            |
| ipc        |
|            |
|------------|
| shm_segsz  |    +------+
|------------| +->| pte  |
|            | |  |------+
|            | |  | pte  |
| times      | |  |------|
|            | |  |      |
|            | |  |      |
|------------| |  |      |
| shm_npages | |  |------|
|------------| |  | pte  |
| shm_pages  |-+  +------+   vm_area_struct         vm_area_struct
|------------|             +----------------+     +----------------+
| attaches   |------------>|                | +-->|                |
+------------+             |                | |   |                |
                           |                | |   |                |
                           |----------------| |   |----------------|
                           | vm_next_shared |-+   | vm_next_shared |
                           |----------------|     |----------------|
                           |                |     |                |
                           |                |     |                |
                           |                |     |                |
                           +----------------+     +----------------+
</verb>
</#if>
<p>図表(5.4) System V IPC 共有メモリ

<!--
Each newly created shared memory area is represented by a shmid_ds data
structure. These are kept in the shm_segs vector. 
The shmid_ds data structure decribes how big the area of shared memory is,
how many processes are using it and information about how that shared memory
is mapped into their address spaces. It is the creator of the shared memory 
that controls the access permissions to that memory and whether its key is 
public or private. If it has enough access rights it may also lock the shared 
memory into physical memory. 
-->
<p>新しく作成された個々の共有メモリエリアは、<tt><ref id="shmid_ds" 
name="shmid_ds"></tt> データ構造体によって表される。
それらは、<tt><ref id="shmid_ds" name="shm_segs"></tt> 配列に保存される。
<newline>[see: include/linux/sem.h](訳注: <htmlurl 
url="./The-Linux-Kernel-images/linux/include/linux/shm.h" 
name="include/linux/shm.h">？)<newline>
<tt>shmid_ds</tt> データ構造体は、その共有メモリのエリアの大きさ、それを使用
するプロセスの数、およびその共有メモリがプロセスのアドレス空間にマップされて
いる様子に関する情報を記述している。そのメモリへのアクセス権限や、
キーがパブリックキーかプライベートキーかを管理するのは、その共有メモリの作成者
である。プロセスが適切なアクセス権を持っているなら、共有メモリを物理メモリに
<ref id="chapter_mm_lock" name="ロック">することもできる。

<!--
Each process that wishes to share the memory must attach to that virtual
memory via a system call. This creates a new vm_area_struct data structure
describing the shared memory for this process. The process can choose where in
its virtual address space the shared memory goes or it can let Linux choose a
free area large enough. The new vm_area_struct structure is put into the list
of vm_area_struct pointed at by the shmid_ds. The vm_next_shared and
vm_prev_shared pointers are used to link them together. The virtual memory is
not actually created during the attach; it happens when the first process 
attempts to access it. 
-->
<p>メモリを共有しようとする個々のプロセスが、自己の仮想メモリに共有領域を張り
付ける(attach)場合は、システムコールを利用しなければならない。そして、そのシ
ステムコールによって <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
データ構造体が作成され、それがプロセスの共有メモリを記述する。
プロセスは、共有メモリが自分の仮想アドレス空間内のどこに置かれるかを選択する
ことができるが、充分な広さの空領域の確保を Linux に任せることもできる。
新しい <tt>vm_area_struct</tt> 構造体は、<tt>vm_area_struct</tt> のリストに
挿入され、<tt><ref id="shmid_ds" name="shmid_ds"></tt> によってポイントされ
る。 <tt><ref id="vm_area_struct" name="vm_next_shared"></tt> と <tt><ref 
id="vm_area_struct" name="vm_prev_shared"></tt> ポインタが、それらをリンクす
るために使用される。共有メモリ領域は、仮想メモリに張り付けられた(attach)だけ
で実際に物理メモリ上に作成されるわけではない。プロセスが最初にそこにアクセス
しようとしたとき、初めて作成される。

<!--
The first time that a process accesses one of the pages of the shared virtual
memory, a page fault will occur. When Linux fixes up that page fault it finds 
the vm_area_struct data structure describing it. This contains pointers to 
handler routines for this type of shared virtual memory. The shared memory 
page fault handling code looks in the list of page table entries for this 
shmid_ds to see if one exists for this page of the shared virtual memory. If 
it does not exist, it will allocate a physical page and create a page table 
entry for it. As well as going into the current process's page tables, this 
entry is saved in the shmid_ds. This means that when the next process that 
attempts to access this memory gets a page fault, the shared memory fault 
handling code will use this newly created physical page for that process too. 
So, the first process that accesses a page of the shared memory causes it to 
be created and thereafter access by the other processes cause that page to be 
added into their virtual address spaces. 
-->
<p>初めてプロセスが共有メモリのページのひとつにアクセスしたときは、ページ
フォルトが発生する。Linux がそのページフォルトを解消したとき、プロセスは、
共有メモリを記述する <tt><ref id="vm_area_struct" name="vm_area_struct"></tt> 
データ構造体を発見する。その構造体には、その共有メモリのタイプに合わせた処理
ルーチンへのポインタが含まれている。共有メモリページフォルト処理コードは、
その <tt><ref id="shmid_ds" name="shmid_ds"></tt> に対するページテーブルエン
トリのリストを探して、共有仮想メモリの該当ページに関するエントリがあるか
どうかを確認する。もし存在しないなら、物理ページを割り当てて、そのための
ページテーブルエントリを作成する。カレントプロセスのページテーブルにそのエン
トリが付け加わると同時に、<tt>shmid_ds</tt> にもそれが保存される。すなわち、
そうしておけば、このメモリにアクセスしようとする次のプロセスがページフォルト
を起こしたとき、共有メモリ処理コードはこの新しく作成された物理ページをそのプ
ロセスのために使用できるわけである。それゆえ、共有メモリにアクセスした最初の
プロセスが物理メモリ上にそれを割り当てたことで、他のプロセスによるそれ以後の
アクセスは、その物理ページをそれらのプロセスの仮想アドレス空間に付加するだけ
で済むようになる。

<!--
When processes no longer wish to share the virtual memory, they detach from it.
So long as other processes are still using the memory the detach only affects 
the current process. Its vm_area_struct is removed from the shmid_ds data
structure and deallocated. The current process's page tables are updated to
invalidate the area of virtual memory that it used to share. When the last 
process sharing the memory detaches from it, the pages of the shared memory 
current in physical memory are freed, as is the shmid_ds data structure for 
this shared memory. 
-->
<p>プロセスがもはや仮想メモリの共有を必要としなくなったとき、プロセスは自己の
仮想メモリからその領域を外す(detach)。他のプロセスがまだそのメモリを使用して
いる限り、外す(detach)操作はカレントプロセスだけにしか影響しない。その <tt>
<ref id="vm_area_struct" name="vm_area_struct"></tt> は、<tt><ref 
id="shmid_ds" name="shmid_ds"></tt> データ構造体から削除され、解放される。
カレントプロセスのページテーブルがアップデートされ、共有されていた仮想メモリ
のエリアは無効にされる。メモリを共有していた最後のプロセスが共有メモリ領域を
外す(detach)とき、物理メモリにある共有メモリのページは解放され、その共有メモ
リに関する <tt>shmid_ds</tt> データ構造体も解放される。

<!--
Further complications arise when shared virtual memory is not locked into
physical memory. In this case the pages of the shared memory may be swapped
out to the system's swap disk during periods of high memory usage. How shared
memory memory is swapped into and out of physical memory is described in
Chapter  mm-chapter. 
-->
<p>共有仮想メモリが物理メモリにロックされないときは、さらに複雑なことが起こる。
その場合、共有メモリのページは、物理メモリの消費が激しい間は、システムのス
ワップディスクにスワップアウトされる。共有メモリが物理メモリからスワップアウ
トやスワップインされる方法は、<ref id="chapter_mm_sect8-2" 
name="「メモリ管理」">の章で解説している。


<!--
Footnotes:

1 REVIEW NOTE: Explain process groups. 
-->
<label id="chapter_ipc_fn">
<footnote>
(脚注1)プロセスグループについて、説明すること。(訳注: 原文のままです。)
</footnote>