<!--Chapter 2 Software Basics-->
<sect>ソフトウェアの基本<label id="chapter_sb">
<p><figure><ph vspace="75"><img src="./The-Linux-Kernel-images/penguin2.gif">
</figure>

<!--
A program is a set of computer instructions that perform a particular task.
That program can be written in assembler, a very low level computer
language, or in a high level, machine independent language such as the C
programming language. An operating system is a special program which
allows the user to run applications such as spreadsheets and word
processors. This chapter introduces basic programming principles and gives
an overview of the aims and functions of an operating system. 
-->
<p>プログラムとは、特定のタスクを実行するコンピュータ命令のセットである。
プログラムは、低水準コンピュータ言語であるアセンブラでも記述でき、C のような
マシンに依存しない高水準のプログラム言語でも記述できる。オペレーティ
ングシステムは、特別なプログラムであり、ユーザによるスプレッドシートやワード
プロセッサといったアプリケーションの実行を可能にするものである。この章
では、基本的なプログラミングの原則を紹介し、オペレーティングシステムの目的や
機能の概観を述べる。

<!--2.1  Computer Languages-->
<sect1>コンピュータ言語<label id="chapter_sb_sect1">
<p>

<!--2.1.1  Assembly Languages-->
<sect2>アセンブリ言語<label id="chapter_sb_sect1-1">

<!--
The instructions that a CPU fetches from memory and executes are not at all
understandable to human beings. They are machine codes which tell the
computer precisely what to do. The hexadecimal number 0x89E5 is an Intel
80486 instruction which copies the contents of the ESP register to the EBP
register. One of the first software tools invented for the earliest computers
was an assembler, a program which takes a human readable source file and
assembles it into machine code. Assembly languages explicitly handle
registers and operations on data and they are specific to a particular
microprocessor. The assembly language for an Intel X86 microprocessor is
very different to the assembly language for an Alpha AXP microprocessor.
The following Alpha AXP assembly code shows the sort of operations that a
program can perform: 
-->
<p>CPU がメモリから取り出して実行する命令は、人間が見ても全く意味不明である。
それらの命令はマシン語であり、コンピュータに何を実行すべきかを正確に伝達する。
例えば、16 進数 0x89E5 は、Intel 80486 の場合、ESP レジスタの内容を EBP レジ
スタにコピーせよという命令に該当する。黎明期のコンピュータのために最初に
発明されたソフトウェアのひとつにアセンブラがある。それは、人間が読んで意味の
わかるソースをマシン語に変換するプログラムである。アセンブリ言語は直接レジスタ
を操作し、そこにあるデータを処理することができるが、その方法はマイクロプロ
セッサに固有のものとなる。Intel X86 プロセッサのアセンブリ言語は、Alpha AXP 
マイクロプロセッサのアセンブリ言語とはかなり異なっている。次の Alpha AXP 
アセンブリコードは、プログラムが実行する処理の一種を示している。

<tscreen><verb>
ldr r16, (r15)    ; Line 1
ldr r17, 4(r15)   ; Line 2
beq r16,r17,100   ; Line 3
str r17, (r15)    ; Line 4
100:              ; Line 5
</verb></tscreen>

<!--
The first statement (on line 1) loads register 16 from the address held in
register 15. The next instruction loads register 17 from the next location in
memory. Line 3 compares the contents of register 16 with that of register 17
and, if they are equal, branches to label 100. If the registers do not contain
the same value then the program continues to line 4 where the contents of r17 
are saved into memory. If the registers do contain the same value then no data
needs to be saved. Assembly level programs are tedious and tricky to write
and prone to errors. Very little of the Linux kernel is written in assembly
language and those parts that are are written only for efficiency and they are
specific to particular microprocessors. 
-->
<p>第一文(Line1)は、レジスタ 16 に対して、レジスタ 15 に保持されたアドレスに
ある(メモリの)内容をロードする。次の命令は、レジスタ 17 に対して、次のアドレス
(レジスタ 15 + 4)のメモリ内容をロードする。Line 3 は、レジスタ 16 
とレジスタ 17 の内容を比較し、同一なら Label 100 に分岐する。両方のレジスタが
同じ内容でない場合、プログラムは 4 行目に移行し、レジスタ 17 の内容がメモリに
保存される。同じ内容の場合は、データを保存する必要はない。アセンブリレベルの
プログラムは、冗長であり、トリッキーな書き方が必要で、エラーが生じやすい。
Linux カーネルはアセンブリ言語で書かれた部分はほとんどなく、その部分も処理効
率を上げる目的のためだけに書かれたものであり、それらは特定のプロセッサに固有
のものとなっている。

<!--2.1.2  The C Programming Language and Compiler-->
<sect2>C 言語とコンパイラ<label id="chapter_sb_sect1-2">

<!--
Writing large programs in assembly language is a difficult and time
consuming task. It is prone to error and the resulting program is not portable,
being tied to one particular processor family. It is far better to use a 
machine independent language like C. C allows you to describe programs in 
terms of their logical algorithms and the data that they operate on. Special 
programs called compilers read the C program and translate it into assembly 
language, generating machine specific code from it. A good compiler can 
generate assembly instructions that are very nearly as efficient as those 
written by a good assembly programmer. Most of the Linux kernel is written in 
the C language. The following C fragment: 
-->
<p>アセンブリ言語でプログラムを書くことは、困難で時間のかかる仕事である。
エラーを生じやすく、出来たプログラムは特定のプロセッサファミリーに束縛される
ので移植性がない。マシンに依存しない C のような言語を使う方がずっとよい。
C を使えば、C で利用可能な論理アルゴリズムとデータ構造を使ってプログラムを
書くことができる。コンパイラと呼ばれる特別なプログラムは、C プログラム
を読み込んで、アセンブリ言語に変換し、それによってマシン語を生成する。よく
出来たコンパイラは、優秀なアセンブリプログラマが書いたのとほとんど同じくらい
効率的なアセンブリ命令を生成することができる。Linux カーネルの大部分は、C 
言語で書かれている。次に C プログラムの一部を示す。

<tscreen><verb>
if (x != y)
        x = y ;
</verb></tscreen>

<!--
performs exactly the same operations as the previous example assembly
code. If the contents of the variable x are not the same as the contents of
variable y then the contents of y will be copied to x. C code is organized into
routines, each of which perform a task. Routines may return any value or data
type supported by C. Large programs like the Linux kernel comprise many
separate C source modules each with its own routines and data structures.
These C source code modules group together logical functions such as
filesystem handling code. 
-->
<p>これは、先ほどのアセンブリコードの例とまったく同じ処理をするものである。
変数 x の内容が変数 y の内容と同一でない場合、y の内容が x にコピーされる。
C コードは、特定のタスクを処理するルーチンとしてまとめることができる。ルーチン
は C でサポートされているすべての値やデータ型を返すことができる。Linux カーネル
のような巨大なプログラムは、多数の独立した C ソースモジュールから構成されてい
て、それぞれが独自のルーチンとデータ構造を持っている。そうした C のソースコード
モジュールは、ファイルシステム処理コードのグループのように、論理的な機能
別にグループ化されている。

<!--
C supports many types of variables, a variable is a location in memory which
can be referenced by a symbolic name. In the above C fragment x and y refer
to locations in memory. The programmer does not care where in memory the
variables are put, it is the linker (see below) that has to worry about that.
Some variables contain different sorts of data, integer and floating point and
others are pointers. 
-->
<p>C では、種々の変数型がサポートされているが、変数とは、シンボル名で参照可能な
メモリ内の位置のことである。上記の C のプログラムでは、x と y は、メモリ内の
位置を参照している。プログラマは、メモリ内に変数が置かれた位置を知る必要はな
く、それに配慮する必要があるのはリンカ(linker)(下記参照)だけである。変数には、
さまざまな種類のデータ、整数、浮動小数点数を格納するためのものとポインタ
(pointer)とがある。

<!--
Pointers are variables that contain the address, the location in memory of
other data. Consider a variable called x, it might live in memory at address
0x80010000. You could have a pointer, called px, which points at x. px might
live at address 0x80010030. The value of px would be 0x80010000: the
address of the variable x. 
-->
<p>ポインタは、アドレスを内容とする変数である。すなわち、他のデータのメモリ内
での位置を表す。x という変数があるとして、それがメモリ内のアドレス 
0x80010000 に存在するとする。その場合、x を差すポインタ、たとえば px を作
ることができる。ここで px は、アドレス 0x80010030 にあるとする。だとすると、
px の値は、変数 x のアドレスである 0x80010000 を内容として持つ。

<!--
C allows you to bundle together related variables into data structures. For
example, 
-->
<p>C を使えば、関連のある変数をデータ構造体としてまとめることができる。たとえ
ば、次のようなデータ構造体があるとする。

<tscreen><verb>
struct {
        int i ;
        char b ;
} my_struct ;
</verb></tscreen>

<!--
is a data structure called my_struct which contains two elements, an
integer (32 bits of data storage) called i and a character (8 bits of data)
called b. 
-->
<p>上記の my_struct というデータ構造は、ふたつの要素を含んでいる。i という整数
(32 ビットのデータ記憶領域)と、b という文字(8 ビットのデータ)という要素である。

<!--2.1.3  Linkers-->
<sect2>リンカ<label id="chapter_sb_sect1-3">

<!--
Linkers are programs that link together several object modules and libraries
to form a single, coherent, program. Object modules are the machine code
output from an assembler or compiler and contain executable machine code
and data together with information that allows the linker to combine the
modules together to form a program. For example one module might contain
all of a program's database functions and another module its command line
argument handling functions. Linkers fix up references between these object
modules, where a routine or data structure referenced in one module actually
exists in another module. The Linux kernel is a single, large program linked
together from its many constituent object modules. 
-->
<p>リンカとは、いくつかのオブジェクトモジュールやライブラリをリンクさせ、ひと
つの整合性のあるプログラムを作成するためのプログラムである。ここでオブジェクト
モジュールとは、アセンブラやコンパイラが出力したマシンコードであり、それに
は、実行可能なマシンコードとデータが含まれると同時に、リンカがモジュールを
結合してひとつのプログラムを作るための情報も含まれている。たとえば、ある
モジュールには、あるプログラムのデータベース関数のすべてが含まれているかもし
れず、ほかのモジュールにはコマンドライン引数を処理するための関数が含まれてい
るかもしれない。リンカはそうしたモジュール間での参照関係を解決するので、それ
によって、あるモジュールで参照されているルーチンやデータ構造が、別のモジュー
ルで実際に存在できるようになる。Linux カーネルという単一の巨大なプログラム
は、多くの構成要素であるオブジェクトモジュールを相互にリンクすることによって
作られている。

<!--2.2  What is an Operating System?-->
<sect1>オペレーティングシステムとは何か？<label id="chapter_sb_sect2">

<!--
Without software a computer is just a pile of electronics that gives off heat.
If the hardware is the heart of a computer then the software is its soul. An
operating system is a collection of system programs which allow the user to
run application software. The operating system abstracts the real hardware of
the system and presents the system's users and its applications with a
virtual machine. In a very real sense the software provides the character of
the system. Most PCs can run one or more operating systems and each one
can have a very different look and feel. Linux is made up of a number of
functionally separate pieces that, together, comprise the operating system.
One obvious part of Linux is the kernel itself; but even that would be useless
without libraries or shells. 
-->
<p>ソフトウェアがなければ、コンピュータは単に熱を放出する電子部品の固まりに
すぎない。ハードウェアがコンピュータの心臓だとすると、ソフトウェアはその
魂である。オペレーティングシステムは、システムプログラムの集合体であり、それ
がユーザによるアプリケーションプログラムの実行を可能にしている。オペレー
ティングシステムは、システム上の実(real)ハードウェアを抽象化して、システムの
ユーザやアプリケーションに仮想マシンを提供する。オペレーティングシステムは、
本当の意味での「システム」を提供しているのである。大部分の PC では、複数の
オペレーティングシステムの走行が可能であり、それらはそれぞれに違った外観と
操作性を持っている。Linux は、機能的には別個の複数の部分から成り立っていて、
それらがひとつになってオペレーティングシステムを構成している。Linux の特徴的
な部分のひとつが、カーネルである。しかし、それさえもライブラリやシェルがなけ
れば役に立たない。

<!--
In order to start understanding what an operating system is, consider what
happens when you type an apparently simple command: 
-->
<p>オペレーティングシステムがどういうものか理解するために、非常に単純なコマンド
を打ったときに何が起こるのかを考えてみよう。

<tscreen><verb>
$ ls
Mail            c               images          perl
docs            tcl
$ 
</verb></tscreen>

<!--
The $ is a prompt put out by a login shell (in this case bash). This means that
it is waiting for you, the user, to type some command. Typing ls causes the
keyboard driver to recognize that characters have been typed. The keyboard
driver passes them to the shell which processes that command by looking for
an executable image of the same name. It finds that image, in /bin/ls.
Kernel services are called to pull the ls executable image into virtual memory
and start executing it. The ls image makes calls to the file subsystem of the
kernel to find out what files are available. The filesystem might make use of
cached filesystem information or use the disk device driver to read this
information from the disk. It might even cause a network driver to exchange
information with a remote machine to find out details of remote files that this
system has access to (filesystems can be remotely mounted via the
Networked File System or NFS). Whichever way the information is located,
ls writes that information out and the video driver displays it on the screen. 
-->
<p><tt>$</tt> は、ログインシェル(ここでは、bash)が出力するプロンプトである。
プロンプトとは、ユーザのコマンド入力をシェルが待っているということを
意味する。<tt>ls</tt> と打ち込むと、キーボードドライバは、文字が打ち込ま
れたことを認識し、そのコマンドをシェルに渡す。シェルは、それを処理するため
に、同じ名前の実行イメージがあるかどうかを探す。シェルが <tt>/bin/ls</tt> に
そのイメージがあることを発見すると、カーネルサービスを呼び出す。呼び出された
カーネルサービスは <tt>ls</tt> の実行イメージを仮想メモリに置いて、その実行を
始める。実行された <tt>ls</tt> のイメージは、カーネルのファイルサブシステムを
呼び出して、どのようなファイルがあるのかを探し出すよう命じる。ファイルシステ
ムは、キャッシュしておいたファイルシステムの情報を利用するか、ディスクデバイ
スドライバを使ってディスクからその情報を読み出させる。あるいは、(Network File 
System(NFS)経由でファイルシステムをリモートマウントしている場合)ネットワーク
ドライバを使用してリモートマシンと情報交換をし、ローカルシステムがアクセスし
ているリモートファイルの詳細について情報を探し出させるかもしれない。その情報
がいずれにある場合でも、<tt>ls</tt> はそうした情報を出力し、ビデオドライバが
それをスクリーンに表示する。

<!--
All of the above seems rather complicated but it shows that even most simple
commands reveal that an operating system is in fact a co-operating set of
functions that together give you, the user, a coherent view of the system. 
-->
<p>上記の説明はやや複雑に思えるかもしれない。しかし、この非常に単純なコマンド
の実行からでも明らかなように、オペレーティングシステムとは、実際、協調して働
く一連の関数のセットであり、それらが一体となることで、ユーザに整合性のあるシ
ステムの概観を提供しているのである。


<!--2.2.1  Memory management-->
<sect2>メモリ管理<label id="chapter_sb_sect2-1">

<!--
With infinite resources, for example memory, many of the things that an
operating system has to do would be redundant. One of the basic tricks of any
operating system is the ability to make a small amount of physical memory
behave like rather more memory. This apparently large memory is known as
virtual memory. The idea is that the software running in the system is fooled
into believing that it is running in a lot of memory. The system divides the
memory into easily handled pages and swaps these pages onto a hard disk as
the system runs. The software does not notice because of another trick,
multi-processing. 
-->
<p>メモリ等のリソースが無限にあるなら、オペレーティングシステムが果たすべき
役割の多くは、余計なものとなるかもしれない。どんなオペレーティングシステム
にもある基本的なトリックのひとつに、少ない物理メモリを実際以上に見せる能力
がある。この一見巨大なメモリは、仮想メモリと呼ばれる。このアイデアは、システム
上で実行されているソフトウェアを騙して、大量のメモリがあるように思いこませる
というものである。すなわち、システムはメモリをページという扱いやすい単位に
分割して、システム実行時に、そうしたページをハードディスク上にスワップ(swap)
する。ソフトウェアがそれに気付かないのは、もうひとつのトリックであるマルチ
プロセス機能のせいである。

<!--2.2.2  Processes-->
<sect2>プロセス<label id="chapter_sb_sect2-2">

<!--
A process could be thought of as a program in action, each process is a
separate entity that is running a particular program. If you look at the
processes on your Linux system, you will see that there are rather a lot. For
example, typing ps shows the following processes on my system: 
-->
<p>プロセスとは、実行中のプログラムであると考えることができる。個々のプロセス
は個別の実体であり、それぞれが特定のプログラムを実行している。Linux 
システム上のプロセスを見た場合、かなり多くのプロセスが存在することに気付くだ
ろう。たとえば、<tt>ps</tt> とタイプすると、筆者のシステム上では次のプロセスが
表示される。

<tscreen><verb>
$ ps
  PID TTY STAT  TIME COMMAND
  158 pRe 1     0:00 -bash
  174 pRe 1     0:00 sh /usr/X11R6/bin/startx
  175 pRe 1     0:00 xinit /usr/X11R6/lib/X11/xinit/xinitrc --
  178 pRe 1 N   0:00 bowman
  182 pRe 1 N   0:01 rxvt -geometry 120x35 -fg white -bg black
  184 pRe 1 <   0:00 xclock -bg grey -geometry -1500-1500 -padding 0
  185 pRe 1 <   0:00 xload -bg grey -geometry -0-0 -label xload
  187 pp6 1     9:26 /bin/bash
  202 pRe 1 N   0:00 rxvt -geometry 120x35 -fg white -bg black
  203 ppc 2     0:00 /bin/bash
 1796 pRe 1 N   0:00 rxvt -geometry 120x35 -fg white -bg black
 1797 v06 1     0:00 /bin/bash
 3056 pp6 3 <   0:02 emacs intro/introduction.tex
 3270 pp6 3     0:00 ps
$     
</verb></tscreen>

<!--
If my system had many CPUs then each process could (theoretically at least)
run on a different CPU. Unfortunately, there is only one so again the operating
system resorts to trickery by running each process in turn for a short period.
This period of time is known as a time-slice. This trick is known as
multi-processing or scheduling and it fools each process into thinking that it
is the only process. Processes are protected from one another so that if one
process crashes or malfunctions then it will not affect any others. The
operating system achieves this by giving each process a separate address
space which only they have access to. 
-->
<p>筆者のシステムに複数の CPU があれば、それぞれのプロセスを、(少なくとも
理論的には)違う CPU 上で実行することが可能である。しかし残念ながらひとつ
しかないため、オペレーティングシステムはここでもトリックを使って、短い時間で
プロセスを順番に実行する。その時間間隔はタイムスライス(time-slice)と呼ばれ、
このトリックは、マルチプロセッシング(multi-processing)もしくはスケジューリン
グ(scheduling)と呼ばれる。すなわちこれは、個々のプロセスを騙して、自分が唯一の
プロセスであると思い込ませるようにするものである。個々のプロセスは他のプロセ
スから保護された状態にあるので、ひとつのプロセスがクラッシュしたりおかしな動き
をしても、他のプロセスに影響を与えることはない。オペレーティングシステムはこの
ことを実現するために、個々のプロセスに自分だけがアクセスできる個別のアドレス
空間を付与している。

<!--2.2.3  Device drivers-->
<sect2>デバイスドライバ<label id="chapter_sb_sect2-3">

<!--
Device drivers make up the major part of the Linux kernel. Like other parts of
the operating system, they operate in a highly privileged environment and can
cause disaster if they get things wrong. Device drivers control the interaction
between the operating system and the hardware device that they are
controlling. For example, the filesystem makes use of a general block device
interface when writing blocks to an IDE disk. The driver takes care of the
details and makes device specific things happen. Device drivers are specific
to the controller chip that they are driving which is why, for example, you
need the NCR810 SCSI driver if your system has an NCR810 SCSI controller.
-->
<p>デバイスドライバは、Linux カーネルの重要な部分を形成している。オペレーティ
ングシステムの他の部分と同様に、デバイスドライバは非常に特権的な環境で
実行されるため、それらが上手く動かない場合は酷い状態になることがある。デバイス
ドライバは、デバイスを制御すると同時に、オペレーティングシステムとハードウェア
間での相互作用も制御する。たとえば、ファイルシステムは、IDE ディスクにブロック
単位の書き込みを行うとき、汎用のブロックデバイスインターフェイスを利用する。
ドライバはその IDE ディスクの詳細に気を配り、そのディスク固有の処理が適切に
実行されるようにする。デバイスドライバは、操作対象であるコントローラチップに
固有のものであるため、たとえば、システムで NCR810 SCSI コントローラを使用してい
る場合、NCR810 SCSI ドライバーが必要になる。

<!--2.2.4  The Filesystems-->
<sect2>ファイルシステム<label id="chapter_sb_sect2-4">

<!--
In Linux, as it is for Unix TM , the separate filesystems that the system may
use are not accessed by device identifiers (such as a drive number or a drive
name) but instead they are combined into a single hierarchical tree structure
that represents the filesystem as a single entity. Linux adds each new
filesystem into this single filesystem tree as they are mounted onto a mount
directory, for example /mnt/cdrom. One of the most important features of
Linux is its support for many different filesystems. This makes it very 
flexible and well able to coexist with other operating systems. The most 
popular filesystem for Linux is the EXT2 filesystem and this is the filesystem
supported by most of the Linux distributions. 
-->
<p>Linux では、Unix と同様に、システム上で個別のファイルシステムを使用する場
合、そのアクセス手段として、(ドライブ番号やドライブ名などの)デバイス識別子は
利用しない。そのかわり、ファイルシステムは、単一の階層的なツリー構造に組み込
まれ、それによって単一の実体として表現される。Linux は、新しい個々のファイル
システムをその単一のファイルシステムに付け加える際、たとえば <tt>/mnt/cdrom
</tt> といったマウントディレクトリ上にマウントするという方法を取る。Linux の
最も重要な特徴のひとつは、多くの異なるファイルシステムのサポートである。
それによって、Linux は、非常に柔軟で、他のオペレーティングシステム
とも上手く共存できるものになっている。Linux の最も一般的なファイルシステムは、
EXT2 ファイルシステムであり、このファイルシステムは、ほとんどの Linux 
ディストリビューションでサポートされている。

<!--
A filesystem gives the user a sensible view of files and directories held on
the hard disks of the system regardless of the filesystem type or the
characteristics of the underlying physical device. Linux transparently
supports many different filesystems (for example MS-DOS and EXT2) and
presents all of the mounted files and filesystems as one integrated virtual
filesystem. So, in general, users and processes do not need to know what sort
of filesystem that any file is part of, they just use them. 
-->
<p>ファイルシステムは、システムのハードディスク上に保存されているファイルや
ディレクトリに関する分かり易い展望をユーザに与える。その際、ファイルシステム
のタイプや、基礎となる物理デバイスの性質の違いは捨象される。Linux は多くの異
なるファイルシステム(たとえば MS-DOS や EXT2)を透過的にサポートし、マウントされ
たファイルやファイルシステムをひとつに統合された仮想ファイルシステムとして
提供する。したがって、一般的に、ユーザやプロセスは、特定のファイルがどのよう
な種類のファイルシステムに属しているのかを知る必要なしに、それを使用できる。

<!--
The block device drivers hide the differences between the physical block
device types (for example, IDE and SCSI) and, so far as each filesystem is
concerned, the physical devices are just linear collections of blocks of data.
The block sizes may vary between devices, for example 512 bytes is common
for floppy devices whereas 1024 bytes is common for IDE devices and, again,
this is hidden from the users of the system. An EXT2 filesystem looks the
same no matter what device holds it. 
-->
<p>ブロックデバイスドライバは、物理的なブロックデバイスのタイプ(たとえば、IDE 
や SCSI)の違いを隠すことが出来る。それゆえ、ファイルシステムに関する限り、物理
デバイスは、データブロックの線形的な集合にすぎない。ブロックサイズは、デバイス
によって異なり、たとえば、フロッピーディスクは 512 バイトが一般的であり、IDE 
ハードディスクでは 1024 バイトが一般的である。しかし、これについても、システム
のユーザからは隠されている。EXT2 ファイルシステムは、そのファイルシステムが置
かれたデバイスがどのようなものであっても、同じ外観を持つ。

<!--2.3  Kernel Data Structures-->
<sect1>カーネルのデータ構造<label id="chapter_sb_sect3">

<!--
The operating system must keep a lot of information about the current state
of the system. As things happen within the system these data structures
must be changed to reflect the current reality. For example, a new process
might be created when a user logs onto the system. The kernel must create a
data structure representing the new process and link it with the data
structures representing all of the other processes in the system. 
-->
<p>オペレーティングシステムは、システムの現在の状態について多くの情報を保持
する必要がある。システム内で何かが起こったら、それに関するデータ構造は
現在の状態を反映するように書き換えられなければならない。たとえば、ユーザがシス
テムにログオンすると、新しいプロセスが生成される。カーネルは、新しいプロセス
を表現するデータ構造体を作成して、それ以外のシステム上の全プロセスを表現し
ているデータ構造体にそれをリンクさせなければならない。

<!--
Mostly these data structures exist in physical memory and are accessible
only by the kernel and its subsystems. Data structures contain data and
pointers; addresses of other data structures or the addresses of routines.
Taken all together, the data structures used by the Linux kernel can look very
confusing. Every data structure has a purpose and although some are used by
several kernel subsystems, they are more simple than they appear at first
sight. 
-->
<p>このようなデータ構造体の大部分は、物理メモリ内に存在し、カーネルとそのサブ
システムからしかアクセスできないようになっている。データ構造体には、データと
ポインタ、すなわち他のデータ構造のアドレスやルーチンのアドレスが含まれている。
それらすべてを一度に見ようとした場合、Linux カーネルによって利用されている
データ構造体は、非常に紛らわしく分かりにくいものに思えるかもしれない。しか
し、すべてのデータ構造体には目的があり、数種のカーネルサブシステムから利用
される(複雑な)構造体もあるが、一般的には、それらは最初に一見した時の印象より
もずっとシンプルである。

<!--
Understanding the Linux kernel hinges on understanding its data structures
and the use that the various functions within the Linux kernel makes of them.
This book bases its description of the Linux kernel on its data structures. It
talks about each kernel subsystem in terms of its algorithms, its methods of
getting things done, and their usage of the kernel's data structures. 
-->
<p>Linux カーネルの理解は、そのデータ構造と、Linux カーネル内の種々の
関数がそれを使用する方法とを理解できるかどうかにかかっている。本書は、
Linux カーネルの説明に際し、そのデータ構造の解説に重点を置く。
個々のカーネルのサブシステムを説明するときは、そのアルゴリズム、処理方法と
同時に、それらが使用しているカーネルのデータ構造という観点を重視する。

<!--2.3.1  Linked Lists-->
<sect2>連結リスト<label id="chapter_sb_sect3-1">

<!--
Linux uses a number of software engineering techniques to link together its
data structures. On a lot of occasions it uses linked or chained data
structures. If each data structure describes a single instance or occurance of
something, for example a process or a network device, the kernel must be
able to find all of the instances. In a linked list a root pointer contains the
address of the first data structure, or element, in the list and each data
structure contains a pointer to the next element in the list. The last 
element's next pointer would be 0 or NULL to show that it is the end of the 
list. In a doubly linked list each element contains both a pointer to the next
element in the list but also a pointer to the previous element in the list. 
Using doubly linked lists makes it easier to add or remove elements from the 
middle of list although you do need more memory accesses. This is a typical 
operating system trade off: memory accesses versus CPU cycles. 
-->
<p>Linux は、多くのソフトウェア工学上のテクニックを使って、データ構造を相互に
リンクしている。多くの場合、Linux では連結あるいは連鎖データ構造体が使用されて
いる。もし、個々のデータ構造体が、単一のプロセスやネットワークデバイスといった
個別の現象や事物を記述するだけなら、カーネルにはそれらの個別データをすべて
探し出す能力が必要になる。連結リストでは、ルートポインタがリスト上の
最初のデータ構造体もしくは要素のアドレスを含んでいて、それぞれのデータ構造体が
リスト上の次の要素へのポインタを含んでいる。最後の要素に含まれる次の要素への
ポインタは(リストの終わりを示す意味がある) 0 か NULL のどちらかである。
二重連結リストでは、個々の要素が、リスト上の次の要素へのポインタとひとつ前の
要素へのポインタの両方を含んでいる。二重連結リストを使えば、リストの真ん中で
要素の追加や削除をすることが容易になるが、ただし、メモリへのアクセス頻度は増加
する。これは、メモリアクセスと CPU サイクルのどちらを優先するかという、オペレー
ティングシステムに典型的な二者択一の問題である。

<!--2.3.2  Hash Tables-->
<sect2>ハッシュテーブル<label id="chapter_sb_sect3-2">

<!--
Linked lists are handy ways of tying data structures together but navigating
linked lists can be inefficient. If you were searching for a particular 
element, you might easily have to look at the whole list before you find the 
one that you need. Linux uses another technique, hashing to get around this 
restriction. A hash table is an array or vector of pointers. An array, or 
vector, is simply a set of things coming one after another in memory. A 
bookshelf could be said to be an array of books. Arrays are accessed by an 
index, the index is an offset into the array. Taking the bookshelf analogy a 
little further, you could describe each book by its position on the shelf; 
you might ask for the 5th book. 
-->
<p>連結リストは、データ構造体を結びつけるには手軽な方法だが、連結リストを辿る
のは非効率な場合がある。特定の要素を検索するなら、リスト全体を簡単に眺めて、
その上で必要な要素を見つけるようにすべきだろう。Linux は、ハッシング(hashing)
という別のテクニックを使って、連結リストの限界を克服している。
ハッシュテーブル(hash table)は、ポインタの配列(array)もしくはベクトル(vector)
である。配列もしくはベクトルとは、単にメモリ内に連続する一連の要素のことであ
る。たとえば、本棚は、本の配列(array)であると言える。配列はインデックスでアクセ
スが可能である。インデックスとは配列へのオフセット(offset)である。再度本棚の
類推で考えると、それぞれの本は、本棚上の位置で表すことができる。5 冊目
(offset)の本という言い方でそれを指定できる。

<!--
A hash table is an array of pointers to data structures and its index is 
derived from information in those data structures. If you had data structures
describing the population of a village then you could use a person's age as an
index. To find a particular person's data you could use their age as an index
into the population hash table and then follow the pointer to the data 
structure containing the person's details. Unfortunately many people in the 
village are likely to have the same age and so the hash table pointer becomes 
a pointer to a chain or list of data structures each describing people of the 
same age. However, searching these shorter chains is still faster than 
searching all of the data structures. 
-->
<p>ハッシュテーブルは、データ構造体に対するポインタの配列であり、そのインデッ
クスは、それらのデータ構造体内の情報から抽出される。ある村の人口を表すデータ
構造体があるとすると、その住人の年齢をインデックスとして使うことができる。
特定の住人のデータを検索する場合、年齢をインデックスとして使用して、その村の
人口についてのハッシュテーブルを検索し、該当するポインタを辿れば、ポイント先
の構造体にその住人の詳細が含まれている。残念ながら、村には、同年齢の住人が
大勢いる場合が多いので、ハッシュテーブルのポインタは、同年齢の住人を記述した
データ構造体の連鎖かリストに対するポインタになるだろう。しかし、こうした短
い連鎖を検索することは、データ構造体すべてを検索するよりもずっと高速である。

<!--
As a hash table speeds up access to commonly used data structures, Linux
often uses hash tables to implement caches. Caches are handy information
that needs to be accessed quickly and are usually a subset of the full set of
information available. Data structures are put into a cache and kept there
because the kernel often accesses them. There is a drawback to caches in
that they are more complex to use and maintain than simple linked lists or
hash tables. If the data structure can be found in the cache (this is known as
a cache hit, then all well and good. If it cannot then all of the relevant data
structures must be searched and, if the data structure exists at all, it must 
be added into the cache. In adding new data structures into the cache an old
cache entry may need discarding. Linux must decide which one to discard, the
danger being that the discarded data structure may be the next one that Linux
needs. 
-->
<p>ハッシュテーブルを使うと、よく利用されるデータ構造体へのアクセスを高速化で
きるので、Linux は、しばしばハッシュテーブルを、キャッシュ(cache)の実装のために
使用している。キャッシュはすばやいアクセスが必要な際の手軽な情報源であり、
通常、手に入る情報のフルセットに対するサブセットとなっている。
カーネルがあるデータ構造体に対し頻繁にアクセスする場合、そのデータ構造体は
キャッシュに入れられて保存される。キャッシュの欠点は、単純な連結リストや
ハッシュテーブルよりも使用と管理が複雑になることである。もしデータ構造体が
キャッシュ内で見つかれば(これは、キャッシュヒット(cache hit)と言われる)、
問題のない良い結果が得られる。しかし、もし見つからない場合、関連するすべて
のデータ構造体が検索され、該当するデータ構造体が存在した際には、それを
キャッシュに追加しなければならない。データ構造体をキャッシュに追加すると、
古いキャッシュエントリを破棄する必要が生じる。Linux はどれを破棄するか決定し
なければならないのだが、問題は、破棄されたデータ構造体は、Linux が次に必要とす
るデータそのものである場合があることである。

<!--2.3.3  Abstract Interfaces-->
<sect2>抽象インターフェイス<label id="chapter_sb_sect3-3">

<!--
The Linux kernel often abstracts its interfaces. An interface is a collection 
of routines and data structures which operate in a particular way. For example
all network device drivers have to provide certain routines in which particular
data structures are operated on. This way there can be generic layers of code
using the services (interfaces) of lower layers of specific code. The network
layer is generic and it is supported by device specific code that conforms to a
standard interface. 
-->
<p>Linux はしばしばそのインターフェイスを抽象化する。インターフェイスとは、
特定の方法で操作されるルーチンとデータ構造体の集合である。たとえば、すべての
ネットワークデバイスドライバは、一定のルーチンを提供しなければならない。
そして、そのドライバのルーチンが、デバイス固有のデータ構造体を処理する。
この方法を使うと、汎用コードから成るレイヤーの存在が可能になる。すなわち、
汎用レイヤーのコードは、下層レイヤーにあるデバイス固有のコードが提供する
サービス(あるいは、インターフェイス)を使用するわけである。ネットワーク
レイヤーは汎用コードから成り、その汎用コードが、標準インターフェイスに準拠
した、デバイス固有のコードによってサポートされている。

<!--
Often these lower layers register themselves with the upper layer at boot
time. This registration usually involves adding a data structure to a linked 
list. For example each filesystem built into the kernel registers itself with 
the kernel at boot time or, if you are using modules, when the filesystem is 
first used. You can see which filesystems have registered themselves by looking
at the file /proc/filesystems. The registration data structure often
includes pointers to functions. These are the addresses of software functions
that perform particular tasks. Again, using filesystem registration as an
example, the data structure that each filesystem passes to the Linux kernel
as it registers includes the address of a filesystem specfic routine which
must be called whenever that filesystem is mounted. 
-->
<p>しばしばそうした下層レイヤーは、起動時に上層レイヤーと伴に登録される。
この登録の際には、通常、データ構造体を連結リストに追加する処理がなされる。
たとえば、あるファイルシステムがカーネルに組み込まれている場合、その個々の
ファイルシステムは起動時にカーネルに登録される。あるいは、もしモジュールに
なっている場合は、ファイルシステムが最初に呼びだされたときに、登録がなされ
る。<tt>/proc/filesystems</tt> というファイルを見れば、どのファイルシステムが
登録されているかが分かる。
カーネルへの登録に使用されるデータ構造体には、しばしば、複数の関数へのポイン
タが含まれている。それらは、特定のタスクを実行する関数のアドレスである。
再度、ファイルシステムの登録を例にとると、個々のファイルシステムが登録の際に
カーネルに渡すデータ構造体には、そのファイルシステムに固有のルーチンのアドレ
スが含まれている。そして、そのルーチンのアドレスを使用して当該ルーチンを呼び
出すことで、当該ファイルシステムがマウントされる仕組みになっている。