投稿

7月, 2019の投稿を表示しています

Linuxシステムコール:Linuxのシステムコール実装

イメージ
Linuxのシステムコール実装  これまで述べてきたようにOS(カーネル)の持つ機能へのインターフェイスがシステムコールですが、システムコールの実態はカーネルの中にあります。このため、ユーザープログラムがシステムコールを呼び出すとユーザーモードからカーネルモードへの切り替わりが発生し、カーネル内部での処理完了でユーザーモードに復帰します。  例として、ファイルからデータを読み出す場合を見てみましょう。  ユーザープログラムがファイルを読むため、システムコールを呼び出します。このときCPUのソフトウェア割り込み、またはシステムコール命令が発行されることで、CPUはカーネルモードに移行します。システムコール命令を発行するとき、特定のレジスタに実行したいシステムコールの番号を設定しておきます。CPUはカーネルモードに切り替わるとシステムコール番号からシステムコールテーブルを参照して、カーネル内部の所定の処理を呼び出します。  この例では、ファイル読み込みが呼ばれ、その中で物理的なファイルを読み込み、ユーザー領域のバッファにデータを転送し、ユーザープログラムがシステムコールを呼んだ場所にリターンします。ユーザー空間にリターンすることで、CPUのモードもカーネルモードからユーザーモードに移行します。  システムコールを呼び出すことで、これらの一連の処理が実行されています。  少し余談になりますが、ライブラリもハードウェアとして実態のファイルにアクセスするためにシステムコールを使っています。なぜ同じような目的なのにわざわざライブラリにしているのでしょうか?  目的は2つあります。1つはシステムコールのラッパーとしての役割、もう一つは抽象化したシステムの提供です。  OSがWindowsである場合、ファイル読み込みのシステムコールは ReadFile() ですが、Windows上で動作するc言語のstdioで定義されているファイル読み込みは同じ fread() で、Linux上で動作する fread() と同様の動作をします。  このように、OSが変わっても同様のプログラミングが可能なようにする役割もライブラリは持っています。  また、抽象化とは、今回の例ではファイルの読み込みですが、ファイル読み込みはシステムコールでは read()

Linuxシステムコール:Linuxのメモリ空間

イメージ
Linuxのメモリ空間  システムコールについて説明する前に、Linuxのメモリ空間について解説します。Linux上で動作するプログラムは、カーネル区間とユーザー空間に分けられています。  カーネル空間はその名が示すように、Linuxカーネルそのものが動作する空間で、物理アドレスを参照することができるため、すべてのハードウェア資源に直接アクセスすることができます。  これに対してユーザー空間は、論理アドレスに変換されたメモリ空間で動作するためユーザー領域として割り当てられた空間内でしか動作することができません。この、限られたメモリ空間はプロセスが起動する毎にカーネルが割り当てを行います。  なぜ、このような方式となっているのでしょうか?  下記のプログラムをLinux上で実行するとどうなるか想像がつきますね?お手元のLinuxでソースをコンパイルして実行してみてください。 #include #define MAX 4096  static char buf[16];  int main(int argc, char** argv) {      int i;      for(i = 0; i < MAX; i++) {          buf[i] = ' ';      }  } 実行すると、 「Segmentation fault (コアダンプ)」 と、表示されてプログラムは強制終了されてしまいます。 どうして強制終了されたのでしょうか?  このプログラムは、ユーザー空間で実行しました。カーネルはプロセスを起動する時に論理アドレスによる限られたメモリ空間を割り当てます。さきほどのプログラムは自分のメモリの外側までアクセスしたので、不正なメモリアクセスを行ったとして強制終了されました。  このようなシステム構成とすることで、ある1つのプログラムが問題を起こしても他のプログラムやハードウェアには問題を与えにくくすることができます。こうすることで、システム全体が暴走したり、突然停止するような事態を防ぐことができます。  この、カーネル空間とユーザー空間は、CPUのハード的な能力を使って実現しています。CPUは幾つかのモードを持っており

Linuxシステムコール:システムコールとは?

イメージ
システムコールとは?  OSが持つ機能を利用するための呼び出しを、Linuxではシステムコールと呼んででいます。OSによってはカネールコール、スーパーバイザコールあるいはサービスコールとも呼ばれることもあります。  一般的に、OSはコンピューター上の各種資源であるメモリやCPU、あるいはペリフェラルとして接続されているタイマーやファイル、表示や音声のデバイスなど多くのハードウェア・デバイスを管理しています。システムコールの目的の1つが、ユーザープログラムがこれらのハードウェアにアクセスするためのインターフェイスです。  例えば、メモリを動的に確保したいときに、OSが管理しているメモリ領域からメモリブロックを取得したり、不要になったときに返すなどのメモリを利用するためのシステムコールであったり、ファイルからデータを読み込んだり、書き込んだりするためのシステムコールなどがあります。これらのシステムコールは、物理的に存在しているハードウェアに何らかのアクセスを行います。そして、複数のプロセスから同時にアクセスを行った場合に調停を行う手段を提供していることもあります。  逆に物理的な存在ではない、プロセスやスレッドと言った実行単位の管理を行うのもOSのしごとです。現代のプログラミング環境は、マルチタスク環境が一般的となっているため、ユーザーが動作させるプログラムの単位であるプロセスやスレッドなどをどのような順番で実行させるか、どのCPUコアを割り当てるかといった実行管理や、動作中のプロセス間での通信手段をサポートするなど、システム全体が協調動作するためのサービスもOSが提供しています。やはりこのようなサービスのインターフェイスもシステムコールとして整備されています。  さて、ここまでは一般的なシステムコールについてでしたが、ここから先はLinuxのシステムコールについて解説しましょう。  Linuxは多くのシステムコールを持っています。手元のARM Ver4.14では397個、x86 32bitでは384個のシステムコールがあり、その中にはいくつか使われなくなった番号も含まれます。  ですが、他のUnix互換のOSと 完全に同じではありません 。例えば、FreeBSDなどは560個を超えるシステムコールを持っており、他方には存在しないシステ