OS自作入門 -Advent28-

NO IMAGE

Step8 スレッドを実装する 前半戦

さて、今日からスレッドの実装を行う。これまでは確かに1プロセスで動作しており、複数個の処理を並行して実行することはできないようになっている。これだとちょっと待ちがありすぎて実際には使いもんにならん。ということでスレッドを実装する話。合わせて「システム・コール」も実装することになるらしい。ここを乗り越えればかなりOSっぽくなりそうではある。スレッドの実装は8,9stepに渡るので長い戦いになりそうだ。

OSの概要

OSの存在意義についての話が載っている。抜粋すると、Lチカと呼ばれるようなLEDをチカチカさせるようなプログラムを考えた時、メインループ内でコマンドを受け取り実行をしたりするようにしておくとそのコマンドが重たい場合にLチカが途中で止まる(重たいコマンドが終了するまで実行できない)ということになってしまう。また、重たいコマンドの中で定期的に状態を保持し、メインループに戻りLチカを行い、重たいコマンドの処理内容を途中から再開するというような方法を取ることもできるが、コマンドによっていちいちメインループとの状態復旧などの処理を記載しないといけなかったりして手間(というか考えたくない、独立しててほしい)。

また、例えばLANコントローラを通してネットワーク経由での重たいファイルのダウンロード等も同じ話で、中断・再開の処理を作り込んだりする必要が出てくる。

そこでこの処理の切り替えと、状態の中断・保存・再開の処理を共通化しようということを考えだした。まず、実行する処理をサービス単位で区切る(上記例だと、Lチカ、重たいコマンドの処理、LANコントローラを通してのファイルダウンロード)、これを タスク と呼ぶ。OSのもつスレッド管理機能を利用することで、タスクをスレッドとして実装することができるようになる。

int start_threads()
{
  kz_run(led_main);
  kz_run(heavy_command_main);
  kz_run(download_file);
}

int led_main()
{
  while(1) {
    kz_recv(...);
  }
}

int heavy_command_main()
{
  while(1) {
    kz_recv(...);
  }
}

int download_file()
{
  while(1) {
    kz_recv(...);
  }
}

こんな感じに。kz_runkozosOSが持つスレッド化のためのコマンドである。led_main, heavy_command_main, download_fileはそれぞれ処理の実体であり、プログラムをタスクごとに独立して動作できるようにしたものをスレッドと呼んでいる。

上記プログラム中に出現するkz_run, kz_recvがOSに対するサービス要求で、 システム・コール と呼ばれている。タスクの切り替え自体はOSが適当なタイミングで行うが、具体的には割込み発生時、システム・コールが呼ばれた時に行われる。この時に、次のスレッドの選択とスレッドの再開処理をそれぞれ スケジューリングディスパッチ と呼ぶ。

アプリケーションプログラムとは何か?

上記3つの処理は最終的には一つの実行形式ファイルになる。しかしながら、各スレッドのコンテキストは別々となるため処理単位も同様に別々となる。そのためこれは「OSの上で3つのプログラムが動作している」と言うことができる。このようにOSの上でタスクとして独立して動作するプログラムを アプリケーション・プログラム と呼ぶ。また、これらはユーザーが作成してOS上で動作させるため ユーザ・アプリケーション とも呼ばれ、スレッドで動作するならばそのスレッドは ユーザ・スレッド と呼ばれる。

アプリケーション・プログラムは 応用プログラム であり、OSなどのコンピュータ・システムを動作させるために必要なプログラムを 基本プログラム と呼ぶ。このOSの中核のことを コア(core)カーネル(kernel) と呼ぶ。

システム・コール

OSが持つ機能を利用するにはOSのサービス関数を呼び出す必要がある。しかし、これをライブラリ的に直接呼ぶのは適切ではなく、OSの動作はアプリケーション・プログラムの知らないところで動作していて、完全に独立していてほしい。なぜなら全てのアプリケーション・プログラムをOSの制御下におくことができず(OSをライブラリ的に呼ぶのを忘れたり)、アプリケーション・プログラムにバグがあった時にシステム全体が止まってしまったりすることが考えられる。

OSは基本的には割込みドリブンなプログラムであり、スレッドからOSの機能を利用したい場合にはスレッド側から明示的に割込みを発生させるのが適切である。そのため多くのCPUは システム・コール命令 と呼ばれる命令を持っている。これを実行すると システム・コール割込み というソフトウェア割みが発生する。こうすることにより外部割込みと同様にCPUが割込み処理を行なってくれるようになる。


今日はここまでかな。次回からソースコードの修正を行なっていこう。OSの機能を用いるのは直接関数実行するんじゃなくて、割込みを使って実行する。という割込みドリブンが基本となっている。というのが一番の理解ポイントかな。先に実装していけばより理解が深まるだろう。少しずつOSとアプリケーションの違いがはっきりしてきた。疑問があるとすればプロセスとスレッドの違いはなんなんだろう。。。javaとかで書くprocessはここでいうスレッドと同じ概念な気がするなぁ。スレッドはCPUの割当て実行単位という理解でいいのかな。じゃぁプロセスってなんだ。。。