Terminate and Stay Resident (TSR) はMS-DOSのオペレーティングシステムにあるシステムコールの1つで、プロセスを終了させてシステムに制御を戻すが、そのメモリは残しておくという機能を提供する。しばしば、割込み(キー押下など)を契機として制御を戻すことで、擬似的なマルチタスクを実現するなどに使われた。このシステムコールを利用するプログラムも一般にTSRと呼ばれる。TSRプログラムには、OSがサポートしていないハードウェア用のデバイスドライバとして機能するものや、スケジューリングやアドレス帳などのよく使う小さなユーティリティプログラムなどがある。

## 背景

通常、MS-DOSでは一度に1つのプログラムしか実行できない。実行中のプロセスが終了する場合、制御を親プロセスに戻すため、INT 21H/4CH というシステムコールを使う。そのプログラムが使っていたメモリは解放されるため、最初からロードする以外に再び呼び出すことはできなくなる。しかし、プログラム終了時にシステムコール INT 27H か INT 21H/31H を使うと、MS-DOSはそのプログラムのメモリを解放しないままプロセスを終了する。

## TSRの使い方

システムコール INT 27H は 'Terminate But Stay Resident' と呼ばれるため、それを使うプログラムを 'TSR' と称した。これを使うと、プログラムは最大64KBのメモリだけをそのままの状態で残すことができる。MS-DOS 2.0 ではそれを改良したシステムコール INT 21H/31H ('Keep Process') が追加された。これは残すメモリ量の制限を外し、プロセスの終了コードを指定できるようにしたものである。

終了後にコードを実行させるためのきっかけの一例としては、なんらかの割込みベクタを自分自身が持つ割込みハンドラを指すよう書き換え、再び呼び出されるようにする。たとえば、ハードウェア割込を利用すれば、ハードウェアのイベントにプログラムを反応させることができる。ソフトウェア割込を利用すれば、別のプログラム中からINT命令で簡単に呼出ができる。(ハードウェア割込の一種であるが)タイマー割込やVSYNC割込により、定期的に呼出すこともできる。割込みの利用は一例であって、他の方法もある(MS-DOSにデバイスドライバとして登録する等)。

実行させるコードは持たず、単にデータ領域としてメモリを確保するだけという利用法もある。例えばPC-9801は比較的後期の機種になるまでパレットの読出しができなかったため、ユーザにより考案された「常駐パレット」などはそういった用法である。

割込みベクタは、連鎖させる利用法もある。一般に、次のどちらかのように利用する。

- ある割り込みを完全に独占し、それ以前に同じ割り込みベクタを書き換えていた他の割り込みハンドラは呼ばない。
- そのTSR自身のコードを実行する前、あるいは実行した後に、以前の割り込みベクタに従って、他の割り込みハンドラを連鎖的に呼ぶ。

前者では競合するTSRの機能が停止するし、後者では共存できるかもしれないが必ずしも全てうまくゆくとは限らない(グラフィックなどの似たような機能を、複数のTSRがまずいタイミングで利用してしまうかもしれないし、連鎖による処理時間の遅れによりうまく働かなくなるかもしれない。そういったように一般に「相性問題」と言われるような現象を起こしやすい)。

'Terminate and Stay Resident' はコンピュータウイルスでもよく使われ、PCの制御を奪ったり、バックグラウンドに潜んだりといった動きをした。たとえば、ディスクI/Oや実行イベントに対応してウイルスが動き、実行ファイル (.EXE や .COM) が実行されるときにそのファイルに感染したり、データファイルをオープンしたときにそのファイルに感染した。

MS-DOSのバージョンが上がるにつれ、(あまり普及しなかったバージョン4や)特にバージョン5.0以降では、MS-DOS自身の標準添付ユーティリティ類にもこれを使ったものが増えた。例えば、DOSKEY コマンド行エディタや他のコマンド行からインストール可能なユーティリティである(ドライバとしてCONFIG.SYSに記述する必要がなく、AUTOEXEC.BATに記述するか、通常のコマンド行から手入力で常駐させる)。

TSRプログラムはどの時点でもロードできる。OSのブート直後にロードするには、AUTOEXEC.BATに記述する。ユーザーが必要に応じてロードすることもできる(例えば、Sidekick や Turbo Debugger)。それらプログラムはTSRであるため、他のプログラムを実行中もメモリに留まっている。TSRプログラムは自身をアンロードさせるオプションを提供しないものもあり、リブートするまでメモリに常駐し続ける。しかし、外部からアンロードすることは可能で、TurboPower Software の MARK.EXE/RELEASE.EXE というユーティリティの組み合わせを使うか、soft reboot TSR を使って、特定のキーの組み合わせを押下することで全TSRをアンロードすることができる。しかしこれらは実際には危険を伴うものであった。MS-DOSのメモリ管理システム的に整合性のある状態を復元するだけであれば簡単だが、割込みその他の資源に関してが問題である。TSRが自身の活動のきっかけのためにフックしているのが、既存のよく知られた割込みなどであることを前提として復元するわけだが、それらの判断は結局のところヒューリスティック(経験則)に頼らざるをえず、MS-DOSでは暴走・ハングアップのようなリセットするしかない異常を起こす危険が常に伴った。

## 問題

TSRプログラムは非常に便利でMS-DOSの限界を超える効力を発揮したが、同時に問題の種とも言われてきた。TSRプログラムはある意味でOSをハイジャックするものであり、TSRとアプリケーションの組合せや、TSR同士の組合せによってはシステムがクラッシュする事態が発生した。また上述したように、コンピュータウイルスにもTSRプログラムの形態をとるものもあり、それらは故意に問題を引き起こした。さらに、MS-DOSシステムにおけるプログラムのコードは、たとえハードウェアに大量のメモリが搭載されていたとしても、メモリ空間の先頭640KB(機種によっては768KB)にロードしなければならなかった(コンベンショナルメモリ)。TSRも例外ではなく、先頭640KBにコードが置かれるため、アプリケーションが利用できるメモリ範囲がそのぶんだけ減ってしまう。したがって、TSRプログラムを作成する場合、第一にそのサイズをなるべく小さくしなければならず、さまざまなベンダーのソフトウェア製品との相性を調べなければならなかった。

また、前述のようにアンロードさせるオプションが提供されないことも多かったことには理由があった。MS-DOSでは「アリーナ」と呼ばれる数珠繋がりのデータ構造でメモリを管理しているので、「以前に実行され常駐した自分自身が、メモリのどこかにいないだろうか?」という処理のためには、その「数珠繋がりの先頭」をMS-DOSに教えてもらう必要があるのだが、そのためのシステムコールは、非公式に Get List-of-Lists などと呼ばれていたundocumentedなAPIで、正式には保証されておらず、そういった点でも不安があった。

1980年代末から1990年代初め、PC上の多くのコンピュータゲームはますますメモリを必要とするようになり、TSRに残されたメモリ領域はますます小さくなっていった。TSRを常駐させつつゲームに必要なメモリを確保するテクニックはどんどん難しくなっていった。多くのゲーマーはそれぞれのゲーム用に異なった構成設定のブートディスクを用意した。1990年代中盤以降もMS-DOS向けゲームがいくつも登場して640KBの限界を突破し、先頭1MBより上位のメモリにゲームのデータやコードの一部を置き、オーバーレイとして下位1MBの領域にスワップインさせて実行するという技法が使われた。オーバーレイを多用したプログラミングは非常に複雑であるため、プログラムが約512KBを超える場合、1MBの制限を超えるもっと簡単な方法として、VCPIやDPMIを実装したサードパーティ製DOSエクステンダが使われた。それによって、x86プロセッサがリアルモードからプロテクトモードに移行すると1MBを超える領域でコードを実行することができた。しかしMS-DOSと(DOSエクステンダに対応している以外の)MS-DOSプログラムは全てリアルモードで動作するものであり(VCPIやDMPIはプロテクトモードのプログラムをMS-DOSに対してリアルモードであるように見せる)、TSRやデバイスドライバもリアルモードで動作する。従って、それらに制御が渡る際には、DOSエクステンダはリアルモードに戻してから制御を渡す必要があり、時間的なペナルティが発生した(あるいは、仮想86モード中の互換環境でリアルモード用のコードを動かすタイプもあった。その場合、仮想化されている機能が重く、特に386の仮想86モードはIO命令そのものが重かったため、PC-98ではグラフィック(GRCG)のために非常に重くなるものがあった)。さらに、MS-DOS以上に問題であるのがBIOSであった。

## 復権

EMSボードと Intel 80386 プロセッサが1980年代後半に登場し、先頭640KBより上位のアドレスにTSRをロードできるようになった。これにはソフトウェアの複雑化(拡張メモリマネージャ)を伴ったが、数年間はこれで何とか間に合った。有名なメモリマネージャとしては、クォーターデックのQRAMとQEMM、Qualitas の 386Max、コンパックのCEMM、後発だがマイクロソフトのEMM386などがある。TSRをロード可能な640KBより上位のメモリを "Upper Memory Block" (UMB) と呼ぶ。その後、メモリマネージャがTSRの最適配置を自動的に行い、先頭640KBをなるべく空けるようになった(クォーターデックの Optimize、マイクロソフトの memmaker)。

## 終焉

DOSエクステンダを使ったゲームが開発されるようになり(初期の例としてDOOMがある)、TSRに関連したメモリ容量問題の多くは解消された。そして Windows により、TSRの多くは不要となり、一部のTSRは非互換によって使えなくなった。ただし、NT系 Windows 以前のWin16アプリケーションではTSR風の技法が可能で、IDTにパッチを当てるものもあった(リアルモードのWindowsでは可能だったため)。その後は Windows も Windows NT となり、またその他のマルチタスク型のOS(Windows NT、macOS、PC-UNIXなど)がPC向けにも普及し、複数のプログラムやデバイスドライバが同時並行して動作できるようになり、その際にTSRのような特殊な技法は不要となった。割り込みは、カーネルが独占的に管理するようになった。

## Macintosh

実装は全く異なるが、似たような目的のものとして Macintosh のデスクアクセサリ (DA) がある。初期のMacintoshのOSはMS-DOSのようにシングルタスクで、その制限に対処するべくDAが生まれた。DAは任意の時点で動作中のアプリケーションの中で動作できる小さなプログラムで、「計算機」などが代表であろう。さまざまなサードパーティがアプリケーションをDAとして実装した。例えば、ワードプロセッサから抜け出さずに挿絵を描くためのお絵かきソフトなどがあり、擬似的なマルチタスクを実現していた。

## 注

1. ↑  PC DOS等のMS-DOS類似品以外にも、シングルタスクのOSにおいて似たような機構はあり得るが、当記事ではもっぱらMS-DOS系の機能を説明する。
2. ↑  以下、この記事ではPC DOS等も含めた総称として「MS-DOS」と呼ぶ。
3. ↑  しかし、メモリを断片化を防ぐため、実際には結構なノウハウがある。
4. ↑  もっとも、Microsoftから出ていた書籍のサンプルコード中で使用している例は存在していた、という微妙さであったが