以下、本発明実施の形態について図面を用いて説明する。
(第1の実施形態)
本実施形態において、スレッドが正常に稼働しているか否かを監視(以下、スレッド監視)する装置として、通信システムを構成するゲートウェイの機能を有する計算機を例に説明する。
なお、本実施形態におけるAPI関数フック処理とは、API関数に対して利用者が独自の処理を追加または処理内容を変更することである。また、ライブラリとは、特定の処理および機能を行うための再利用可能なコード(プログラム)を含む、データの集まりである。また、共有ライブラリとは、複数のプログラムによって共有されるライブラリであり、API関数も共有ライブラリとして提供される。また、スレッドとは、計算機による処理の分割単位であり、計算機がスレッドを生成することによって、計算機は、分割した処理を並列に実行することができる。
図11は、従来技術のスレッド監視方法を示す説明図である。
従来のゲートウェイ機器におけるスレッド監視の処理は、図11に示すように、複数のスレッド12、監視スレッド11、および、カーネル100によって実行される。従来のゲートウェイ機器は、プロセッサおよびメモリ(主記憶装置)を備える。ゲートウェイ機器に備わるプロセッサがメモリを用いてOSまたはアプリケーションプログラムを実行することによって、カーネル100、監視スレッド11およびスレッド12を実行する。
カーネル100は、ゲートウェイ機器のOSを実行するための処理単位である。監視スレッド11は、プログラムを実行するための処理単位であり、スレッド12のスレッド監視を行うスレッドである。スレッド12は、プログラムを実行するための処理単位である。
図11に示すスレッド12は、ゲートウェイ機器に送信されるパケットを受信し、受信したパケットを加工し、加工されたパケットを送信する処理を行う。スレッド12は、命令メッセージキュー130、および、生存フラグ140をメモリに保持する。命令メッセージキュー130は、カーネル100、他のスレッド12、または、監視スレッド11から送信される命令メッセージを保持するためのキューである。生存フラグ140は、スレッド12によって更新される記憶領域であり、監視スレッド11によって参照および更新される。
スレッド12が開始された後(121)、スレッド12は、命令メッセージキュー130に命令メッセージが追加されるまで待つ(122)。ステップ122の後、スレッド12は、命令メッセージキュー130に追加された命令メッセージが、監視命令メッセージ131か否かを判定する(123)。
命令メッセージキュー130は、スレッド12へ送信された命令メッセージを格納するデータ構造を含む。スレッド12は、命令メッセージキュー130に命令メッセージが追加された順番に命令メッセージを処理する。
ステップ123において、命令メッセージキュー130に追加された命令メッセージが監視命令メッセージ131であると判定された場合、スレッド12は、スレッド12が生存していると報告するための処理(生存報告)を実行する(124)。
ステップ124における生存報告は、あらかじめ保持された1ビットの生存フラグ140に、1を格納する処理(有効化)である。生存フラグ140は、スレッド12が生成された際に生成される。
ステップ123において、命令メッセージキュー130に追加された命令メッセージが監視命令メッセージ131ではなく、パケット受信命令メッセージである場合、スレッド12は、パケットを受信し(125)、受信したパケットを加工し(126)、加工されたパケットを送信する(127)。スレッド12は、ステップ124またはステップ127が終了後、ステップ122に戻り、次の命令メッセージが命令メッセージキュー130に追加されるまで待つ。
一方、監視スレッド11が開始された後、監視スレッド11は、所定の監視周期が経過したか否かを判定し(112)、監視周期が経過するまで待つ。監視周期が経過した場合、監視命令メッセージ131を生成し(113)、スレッド12の命令メッセージキュー130の末尾に監視命令メッセージ131を追加する。ステップ113の後、生存フラグ140を参照し、スレッド12の生存確認300を行う。
生存確認300において、監視スレッド11は、生存フラグ140に1が格納されているか否かを判定し、1が格納されている場合、スレッド12は生存していると判定し、生存フラグ140に0を格納する(無効化)。
生存確認300の後、監視スレッド11は、ステップ112に戻る。
図12は、従来技術の生存確認300の処理を示すフローチャートである。
監視スレッド11は、図12のフローチャートに示すように生存確認300を行う。まず、監視スレッド11は、生存フラグ140に1が格納されているか否か判定する(310)。そして、生存フラグ140に1が格納されている場合、監視スレッド11は生存フラグ140に0を格納し(320)、監視スレッド11はスレッド12が正常であると判定する(330)。
ステップ310において、生存フラグ140に1が格納されていないと判定された場合、監視スレッド11は、スレッド12が異常であると判定する(340)。ステップ330またはステップ340が終了した後、監視スレッド11は、生存確認300を終了する(350)。
さらに、OSの機能によってソフトウェア割り込み150が発生した場合、カーネル100は、割り込み処理を開始する(101)。図11に示すソフトウェア割り込み150は、パケットをゲートウェイ機器が受信した場合に実行される。
カーネル100は、他の機器がゲートウェイ機器に送信したパケットを、NIF(Network InterFace)から受信する(102)。ステップ102の後、カーネル100は、ソケットバッファに受信したパケットデータをコピーする(103)。
ここで、ソケットバッファとは、カーネル100が受信したパケットの内容を一時的に保存しておくメモリである。ソケットバッファは、スレッド12がパケットを受信するために用いられる。
ステップ103の後、カーネル100は、パケット受信命令メッセージ132を生成し(104)、生成されたパケット受信命令メッセージ132を命令メッセージキュー130の末尾に追加する。そして、ステップ104の後、カーネル100は、割り込み処理を終了する(105)。
図11および図12に示す処理によって、スレッド12は、パケットの受信処理とスレッド監視処理における生存報告処理との両方を実現する。また、監視スレッド11が監視命令メッセージ131を命令メッセージキュー130に追加するため、監視スレッド11は、監視スレッド11が生存確認300をする前にスレッド12のWAIT状態を終了させ、ステップ124における生存報告を実行させることができる。
しかし、図11および図12に示す処理を、スレッド監視方法を導入していないシステムに適用する場合、開発者が、監視対象となるスレッド12のソースコードを生存報告をするように変更し、さらに、変更されたソースコードをコンパイルしなければならない。また、監視スレッド11による監視命令メッセージ131の送信およびスレッド12による監視命令メッセージ131の受信のため、ゲートウェイ機器のCPU処理時間が増加する問題がある。
さらに、図11の処理において、スレッド12は監視命令メッセージ131を契機に生存報告を行うため、パケットを受信する処理(ステップ125〜ステップ127)に時間がかかった場合に生存報告が間に合わなくなる可能性がある。この場合、監視スレッド11は、スレッド12を異常と誤判定する可能性がある。
このため、本発明の第1の実施形態は、監視命令メッセージ131を利用しない方法として、API関数フックによるスレッド監視方法を用いる。
図1は、本発明の第1の実施形態のスレッド監視方法を示す説明図である。
図1に示すスレッド監視の処理は、スレッド120、監視スレッド110、およびカーネル100によって実行される
第1の実施形態のスレッド監視方法は、ステップ122における命令メッセージキュー130への命令メッセージの追加を待つ処理において、スレッド120が、スレッド120をWAIT状態にするAPI関数(例えば、sleep API関数)をAPI関数フックすることによって、ステップ122の処理を横取りする方法である。なお、API関数フックの方法は後述する。
そして、第1の実施形態のスレッド監視方法は、横取りされたAPI関数に含まれる固有の処理(スレッド120をWAIT状態にするAPI関数の処理)に、生存報告200をする処理を追加させる。例えば、横取りされたAPI関数がsleep API関数である場合、スレッド120は、スレッド120を指定された秒数の間停止する処理に加え、生存報告200をする処理を追加させる。
これによって、スレッド120は、図11におけるステップ124において実行されていた生存報告を、スレッド監視の対象のスレッド120のソースコードの変更とコンパイルとを行うことなく、ステップ122において実行できる。また、監視命令メッセージ131に関する、ステップ113における生成処理とステップ123における受信判定処理とが不要になり、プログラムサイズの縮小とプロセッサの処理時間の削減とが可能になる。
そして、API関数フックは、監視対象であるスレッド120のソースコードに変更を加えない方法であるため、既存システムに変更を加えずにスレッド監視方法を提供することができる。
さらに、第1の実施形態のスレッド監視方法はフックする対象のAPI関数を選択することができるため、ステップ125におけるパケットの受信処理、ステップ126におけるパケットの加工処理、または、ステップ127におけるパケットの送信処理が、API関数フックする対象として選択されることによって、ステップ125〜ステップ127における処理のいずれかにおいて、スレッド120が生存報告200をすることも可能である。
そしてこれによって、第1の実施形態のスレッド監視方法は、ゲートウェイ機器が受信するパケットのサイズが大きく、ステップ125〜ステップ127の処理に要する合計時間が、監視スレッド110が保持する所定の監視周期よりも大きくなった場合も、後述する処理によって、監視スレッド110がスレッド120を異常状態として誤判定することを防ぐことができる。
なお、後述する本実施形態におけるAPI関数フックを実現する方法には、Unix(登録商標)またはLinux(登録商標)系OSにおいて、開発者または所定のプログラムが、フック処理を定義した共有ライブラリをあらかじめ生成し、生成された共有ライブラリへのパスをLD_PRELOAD環境変数等の環境変数に追記する方法を用いる。スレッド120を含むプロセスが起動時にLD_PRELOAD環境変数を読み出し、LD_PRELOAD環境変数で指定された共有ライブラリ内のAPI関数をロードする。このため、スレッド120の実行時に共有ライブラリで定義したAPI関数を実行するため、スレッド120に含まれるAPI関数がAPI関数フックされる。
しかし、本実施形態におけるAPI関数フックを実現する方法は、OSまたはAPI関数フック方法を限定するものではない。すなわち、スレッド120が実行される際に、処理される関数に新たな処理を追加できれば、いかなるOSまたは関数フック方法を用いてもよい。
また、後述する本実施形態において、API関数フックを行うプログラムは標準Cライブラリ(GLIBC)であるとして説明するが、API関数フックを実現するプログラミング言語は、CおよびC++に限定されるものではない。
また、前述および後述のスレッド120は、ゲートウェイ機器において実行されるが、本実施形態のスレッド120はゲートウェイ機器のみに限らず、いかなる計算機においても実行される。そして、いかなる計算機においても、本実施形態のスレッド監視方法が実行されうる。
図2は、本発明の第1の実施形態の機器40のハードウェア構成を示すブロック図である。
本実施形態を実現する機器40は、少なくとも一つのプロセッサ400、メモリ420、および、NIF440を備える。また、プロセッサ400およびメモリ420は、バス410によって接続され、メモリ420およびNIF440はバス430によって接続される。
プロセッサ400は、CPU等の演算装置であり、OSおよびアプリケーションプログラム等のソフトウェアを実行する。メモリ420は、プロセッサ400がソフトウェア実行時に、プログラム実行バイナリおよびプログラムが使用するデータを格納するための記憶領域である。
NIF440は、機器40とは別の機器とパケットを送受信するための装置である。プロセッサ400、メモリ420、およびNIFは、バス410およびバス430によって接続されるため、互いに命令メッセージおよびデータを送信することが可能である。
なお、プロセッサ400は、マルチタスク可能なマルチコアまたはマルチプロセッサであることが望ましいが、マルチタスクに対応したシングルコアまたはシングルプロセッサでも本発明を適用可能である。ここでマルチタスクとは、プロセッサ400が複数の処理を切り替えながら複数の処理を実行する方法である。従って、マルチタスクが可能なハードウェアで稼働するソフトウェアであれば、本発明を適用することができる。
また、機器40は、物理的に一つの計算機によって実装されてもよいし、少なくとも一つの計算機が提供する仮想的な計算機によって実装されてもよい。
図3は、本発明の第1の実施形態のAPI関数フック群510を示す説明図である。
本実施形態におけるAPI関数フック群510とは、API関数フック対象として選択されたAPI関数の集合である。本実施形態において、監視対象となるプログラムの開発者または使用者が、あらかじめAPI関数フック群510に含まれるAPI関数を決定する。
本実施形態のスレッド監視の対象のプログラムが実行された場合、プロセッサ400は、少なくとも一つのスレッドまたは少なくとも一つのプロセスによって、プログラムの処理を実行する。
スレッドプロシージャ520は、各スレッド120が生成されてから終了するまでの処理内容が、ソースコードにおいて定義されている箇所である。よって、スレッド120はスレッドプロシージャに従って動作する。
スレッドプロシージャ520には、複数のAPI関数が含まれる。第1の実施形態のスレッドプロシージャ520に含まれるAPI関数がメモリ420にロードされる際、LD_PRELOAD環境変数530に共有ライブラリ500を指定していると、共有ライブラリ500に該当するAPI関数があればメモリ420にロードする。
共有ライブラリ500は、API関数フック群510を含む。このため、メモリ420にロードされるAPI関数が書き換わることによって、スレッドプロシージャ520に含まれる各API関数は、API関数フック群510が示す処理内容を実行する。
ただし、API関数フックされるべきAPI関数は、スレッド監視の対象のプログラムを含むソフトウェアによって異なる。例えば、一般的に、API関数フック群510として選択されるAPI関数は、定期的に実行されるAPI関数が望ましい。本実施形態のAPI関数フック群510は、開発者または使用者がスレッドプロシージャ520からフックされるAPI関数を選択することによって生成される。
開発者または使用者は、API関数を選択するために、スレッドプロシージャ520からAPI関数を抜き出すためのスクリプトを用いてもよい。API関数を抜き出すためのスクリプトは、簡易プログラミング言語によってコーディングされたプログラムである。
また、開発者または使用者は、定期的に実行されるAPI関数が既に取得されている場合、取得されたAPI関数をAPI関数フック群510に含めてもよい。
例えば、図1に示すゲートウェイ機器において、開発者または使用者は、スレッド120をWAIT状態にするAPI関数をAPI関数フック群510として選択する。また例えば、スレッド120が正常時にprintf API関数によって文字列を表示し続ける場合、開発者または使用者は、printf API関数をAPI関数フック群510として選択する。
ただし、スレッド120が無限ループを含み、かつ、無限ループ内にフック対象のAPI関数がある場合、スレッド120は無限ループ内で生存報告200をするため、スレッド120の異常動作として無限ループが検出されなくなる。従って、前述のプログラムは、無限ループを引き起こす可能性があるループ内のAPI関数を選択対象から除外し、API関数フック群510を生成する。より具体的には、前述のプログラムは、ループ文の終了条件が他のスレッドによって満たされるループ文または条件を満たした時のみ、無限ループを抜け出すループ文を選択対象から除外する。
なお、API関数フック群510に含まれるAPI関数の数は制限されない。
次に、共有ライブラリ500の生成について説明する。共有ライブラリ500は、OSによって提供されるほか、開発者がソースコードをコンパイルすることによって生成される。従って、前述のプログラムが、API関数フック群510に含まれるAPI関数を選択し、各API関数がフックされた際の処理内容をAPI関数フック群510に定義した後、前述のプログラムは、API関数フック群510をコンパイルすることによって共有ライブラリ500を生成する。なお、生成される共有ライブラリ500は、API関数ごとに別々に生成されてもよい。
図3が示す共有ライブラリ500において定義されるAPI関数の処理内容は、各API関数が有する各API関数固有の処理内容と、生存報告200の処理内容とを含む。
例えば、スレッドプロシージャ520がsleep API関数を含み、sleep API関数がAPI関数フック群510として選択された場合のsleep API関数の処理内容を図3に示す。スレッド120が実行され、sleep API関数が実行された際、スレッド120は、sleep API関数においてAPI関数フック540を行うことによって生存報告550を行う。これは、LD_PRELOAD環境変数530によって、共有ライブラリ500で定義したAPI関数がメモリ420にロードされているためである。そして、生存報告550が終了した後、スレッド120は、sleep API関数固有の処理560を実行する。
一方、スレッドプロシージャ520がprintf API関数を含み、printf API関数はAPI関数フック群510として選択されていない場合のprintf API関数の処理内容を図3に示す。スレッド120が実行され、printf API関数が実行された際、スレッド120は、printf API関数固有の処理570を実行する。これは、共有ライブラリ500が、printf API関数をフックし、printf API関数固有の処理以外の処理を行うことを定義されていないためである。
図3に示す生存報告550は、図1に示す生存報告200の処理である。すなわち、図3に示す生存報告550は、生存フラグ140に1を格納する処理である。
本実施形態の生存フラグ140が1である場合、生存フラグ140は、スレッド120が生存していることを報告したことを示す。生存フラグ140が1以外である場合、生存フラグ140は、スレッド120が生存していることを報告していないことを示す。すなわち、生存フラグ140が1以外である場合、スレッド12が異常である可能性が高い。
なお、図3におけるスレッド120は、生存フラグ140に1を格納する処理をAPI関数固有の処理を実行する前に行うが、本実施形態におけるスレッド120は、API関数固有の処理を実行した後に生存フラグ140に1を格納してもよい。また、前述のプログラムは、API関数フック時に追加される処理を少なくすることによって、API関数フックによって生じる遅延を抑えることができる。
スレッド120がAPI関数がフックされた関数内からAPI関数固有の処理を実行するためには、スレッド120は、dlsym API関数によってAPI関数固有の処理を行う関数のアドレスを取得し、生存報告550を実行した後、取得されたアドレスを指定して呼びだすことによって、スレッド120は、API関数固有の処理を実行する。ただし、API関数固有の処理を実行する度にAPI関数のアドレスを取得すると効率が悪いため、スレッド120は、プロセスが終了するまで値を保持する静的な変数に保存しておくことによって効率を改善してもよい。
図3に示す共有ライブラリ500は、API関数名、API関数の引数、追加される処理内容(生存報告550に対応)、および、API関数固有の処理の4項目を含む。共有ライブラリ500は、前述のAPI関数フック群510を生成するプログラムによって、定期的または開発者の指示によって、生成されてもよい。
API関数フックによる生存報告550について説明する。前述のプログラムによって生成された共有ライブラリ500を用いてAPI関数フックを有効にする場合、開発者は、LD_PRELOAD環境変数530に共有ライブラリ500へのパス(配置場所)を格納する。そして、パスを格納されたLD_PRELOAD環境変数530を用いてソフトウェアが起動した場合、起動されたソフトウェアに含まれるプロセスにおいてAPI関数フック540が有効になり、生存報告550が行われる。
なお、API関数フックを有効にしたプロセスから子プロセスが起動された場合も、子プロセスにおいてAPI関数フックが有効になる。子プロセスへのAPI関数フックを無効にする場合、親プロセスが実行される関数は、環境変数を削除するunsetenv API関数を含み、親プロセスが実行された後、親プロセスは、LD_PRELOAD環境変数530を無効にした状態において子プロセスを起動する。
このとき、本実施形態の機器40は、予めAPI関数フックを有効にするプロセス数をメモリ420が保持する環境変数などに格納させ、API関数フックの回数が環境変数に格納されたプロセス数を超えた場合、API関数フックを無効にするプログラムを有することによって、API関数フックの回数およびAPI関数フックの範囲を制御してもよい。
図4は、本発明の第1の実施形態の監視スレッド110が保持するデータおよびスレッド120が保持するデータを示す説明図である。
監視スレッド110は、メモリ420に監視対象リスト610を保持する。また、各スレッド120(120−1、120−2)は、メモリ420に監視情報620(620−1、620−2)を保持する。
監視対象リスト610は、各スレッドを一意に識別するための識別子と、各監視情報620がメモリ420のいずれの領域に格納されるかを示すポインタとを含む。監視スレッド110は、各スレッド120を監視する場合、監視対象リスト610を参照することによって、監視情報620から情報を取得する。
監視情報620は、各スレッド120を監視するために必要な情報を、スレッド120毎に保持する構造体である。監視情報620は、生存フラグ140および連続NG回数621を含む。
生存フラグ140は、図1に示す生存フラグ140と同じであり、スレッド120が正常状態であることを示す1ビットのフラグである。各スレッド120は、生存フラグ140を一つ保持する。生存フラグ140は、スレッド120および監視スレッド110によって更新される。
連続NG回数621は、後述する異常動作検出800の処理によって、スレッド120−1が無効であると連続して判定された場合に、無効であると判定された回数を含む。連続NG回数621は、監視スレッド110によって更新される。
メモリ420が監視情報620を保持する方法としては、各スレッド120固有の記憶領域に各スレッド120に対応した監視情報620を保持する方法がある。また、メモリ420における各スレッド120間の共有メモリ領域に、監視情報620の構造体を含む一つのテーブルを保持し、このテーブルによって各監視情報620を一括管理する方法がある。
ここで、スレッド120固有の記憶領域とは、アドレスが指定されなければ他のスレッドからアクセスされないため、各スレッド120が固有の記憶領域に監視情報620を保持した場合、他のスレッド120が誤って自らが保持する監視情報620にアクセスすることを防ぐことができる。
また、各スレッド120間の共有メモリ領域とは、プロセス間で共有できる領域であり、プロセスに含まれる各スレッド120が共有メモリ領域に監視情報620を保持した場合、プロセスごとに監視することが可能になる。
さらに、共有メモリ領域に監視情報620が格納された場合、監視情報620は、スレッド名などの情報を含むことによって、デバッグ時の情報として用いられてもよい。また、共有メモリ領域に監視情報620が格納された場合、監視情報620は、ロックハンドルを含むことによって、共有リソースのロック処理とアンロック処理とに用いられてもよい。ここで、ロックハンドルとはロック処理とアンロック処理とに必要なキーである。
監視情報620は、スレッド120が生成される際に、スレッド120毎にメモリ420に生成される。プロセッサ400は、スレッド120が生成された際に、スレッド120の処理によって監視情報620をメモリ420に生成する。
本実施形態のスレッド120の動作には、メモリ420に監視情報620を生成する処理と、生成された監視情報620のメモリ420における位置を示すポインタを監視リスト610に登録する処理とが含まれる。これは、pthread_create API関数(スレッド生成命令)にAPI関数フックを行い、生成および登録処理をあらかじめ設定することによって可能である。
このため、スレッド120は、スレッド120が新たに生成された場合、スレッド120の監視情報620の位置を示すポインタと、スレッド120の識別子とを監視リスト610登録する。
そして、監視スレッド110は、監視対象リスト610に従って異常動作検出を行う。生成された監視情報620は、監視情報620に対応するスレッド120がプロセッサ400によって実行される間、メモリ420に保持される。そして、各スレッド120の処理の終了に従って、スレッド120は、監視情報620をメモリ420から削除し、監視対象リスト610からスレッド120のエントリを削除する。これは、pthread_exit API関数(スレッド終了命令)にAPI関数フックを行い、削除処理を追加することで実現できる。
また、本実施形態の監視スレッド110は、生成されたスレッド120を示す識別子と生成されたスレッド120を含むプロセスを示す識別子とを、メモリ420に格納する処理を含んでもよい。これによって、後述の処理によって、監視スレッド110がスレッド120を異常であると判定した場合、監視スレッド110は、スレッド120の識別子に基づいてスレッド120を含むプロセスの識別子をメモリ420から取得し、取得された識別子を用いて別プロセスからプロセスを再起動してもよい。
また、本実施形態においてスレッド120は、監視情報620が削除された旨を監視スレッド110に通知してもよく、また、監視情報620が削除された旨を監視スレッド110に通知しなくてもよい。
監視情報620が削除されたことが通知されない場合においても、監視対象リスト610に含まれる各エントリは、監視情報620が削除された時点でスレッド120によって削除されるため、監視スレッド110はスレッド120への異常検出を行わない。
図5は、本発明の第1の実施形態の生存報告200および異常動作検出800を示すシーケンス図である。
図5は、スレッド120による生存報告200と監視スレッド110による異常動作検出800とによって行われるスレッド監視の処理を示す。
スレッド120が実行される間、スレッド120が実行するAPI関数のうち、API関数フックされるAPI関数が、監視情報620に生存報告200を行う。具体的には、API関数フックされるAPI関数が、生存フラグ140に1を格納する。
一方で、監視スレッド110は、監視対象リスト610を用いて監視情報620を参照することによって、異常動作検出800を実行する。監視スレッド110は、監視対象リスト610のポインタが示す監視情報620をすべて参照することによって、監視対象リスト610に識別子が格納されるすべてのスレッド120に異常動作検出800を行う。
監視スレッド110は、監視対象リスト610に識別子が格納されていないスレッド120に、異常動作検出800を行えない。このため、実行中のスレッド120を示す識別子は、監視対象リスト610に常に格納される必要がある。本実施形態において、監視対象リスト610に実行中のスレッド120を示す識別子を格納する方法は、スレッド120が生成された際に監視対象リスト610に識別子が格納され、スレッド120が終了した際に監視対象リスト610から削除することによって実現される。
なお、監視対象リスト610のデータ構造はリスト構造に限定するものではなく、テーブル構造でもよい。また、図5に示す異常動作検出800は、一定の監視周期によって実行されるが、本実施形態の異常動作検出800は、開発者または使用者等が監視スレッド110に対応するコマンドを実行することによって、不定期または任意のタイミングによって実行されてもよい。
図6は、本発明の第1の実施形態の監視スレッド110による異常動作検出800を示すフローチャートである。
所定の監視周期において監視スレッド110が異常動作検出800を開始する(801)。監視スレッド110は、開発者または使用者からの指示によって、異常動作検出800を実行してもよい。
なお、異常動作検出800は、監視対象リスト610に格納されるすべての監視情報620に行われるが、図6に示す処理は、一つの監視情報620に行われる処理を示す。複数の監視情報620に異常動作検出800が行われる場合、監視スレッド110は、図6に示す処理を複数の監視情報620に対して並列に行ってもよいし、複数の監視情報620に順次行ってもよい。
ステップ801の後、監視スレッド110は、監視対象リスト610を用いてスレッド120の監視情報620を参照する。そして、各スレッド120に本実施形態の生存確認300を実行し、スレッド120の生存確認300の結果が有効か否かを判定する(810)。
ステップ810において行われる生存確認300の処理の流れは、図12に示す生存確認300の処理の流れと同様である。しかし、本実施形態の生存確認300のステップ330において、監視スレッド110は、生存フラグ140が有効であると判定する。また、本実施形態の生存確認300のステップ340において、監視スレッド110は、生存フラグ140が無効であると判定する。これは、異常動作検出800における生存確認300は、スレッド120が正常であるか否かを判定する処理ではないためである。
ステップ810において、生存確認300の結果が有効であると判定された場合、生存フラグ140はスレッド120が生存報告200を正常に行っていることを示す。このため、監視スレッド110は、連続NG回数621に0を格納する(820)。
そして、ステップ820の後、監視スレッド110は、スレッド120が正常であると判定する(860)。連続NG回数621は、監視周期ごとに実行されるステップ810において、生存フラグ140が無効であると連続して判定された場合に、無効と判定された回数を示す。
ステップ810において、生存確認300の結果が無効であると判定された場合、監視スレッド110は、スレッド120がNGであると判定する(830)。ステップ830の後、連続NG回数621に1を加算する(840)。例えば、二つ前の監視周期におけるステップ810において有効と判定され、一つ前の監視周期におけるステップ810において無効と判定された生存フラグ140を、監視スレッド110がステップ810において無効と判定する場合、ステップ840の後の連続NG回数621には、2が格納される。
ステップ840の後、監視スレッド110は、連続NG回数621が示す値と所定の保護回数とを比較し、連続NG回数621が示す値が所定の保護回数以下であるか否かを判定する(850)。
ここで、保護回数とは、各監視周期におけるステップ830においてNGであると連続して判定された場合、すなわち、各監視周期におけるステップ810において無効であると連続して判定された場合、監視スレッド110がスレッド120を異常と判定しない連続NG回数621の上限値である。監視スレッド110は、連続NG回数621の値が保護回数の値を超えるまで、スレッド120を異常と判定しない。
例えば、保護回数が1である場合、ステップ830における判定が2回連続した後、監視スレッド110は、スレッド120が異常な動作を行っていると判定(異常動作検出)する。
ステップ850において、連続NG回数621が所定の保護回数以下であると判定された場合、監視スレッド110は、ステップ860を実行することによって、スレッド120が正常であると判定する。
ステップ850において、連続NG回数621が所定の保護回数よりも大きいと判定された場合、監視スレッド110は、スレッド120が異常であると判定する(870)。ステップ860またはステップ870の後、監視スレッド110は、スレッド120への異常動作検出800を終了する(880)。
前述の保護回数は、本実施形態のスレッド監視の処理におけるパラメータとしてあらかじめ開発者または使用者によって、機器40のメモリ420に格納される。保護回数を1以上の値とすることによって、生存報告200が監視周期内で一度も実行されない場合、開発者または使用者は、スレッド120の異常動作の誤判定を防ぐことができる。
また、連続NG回数621が保護回数以下である場合、監視スレッド110は、スレッド120がNGと判定されたことをログに出力してもよい。これは、開発者または使用者が、出力されたログを参照することによって、スレッド120のデバッグまたは性能改善を行うことができるためである。
スレッド120において無限ループまたはデッドロックが発生した場合、スレッド120は生存報告200を行わない。このため、無限ループまたはデッドロックが発生した時点から、異常動作検出800が2回以上実行された場合、ステップ810において生存フラグ140は必ず0である。このため、監視スレッド110は、無限ループまたはデッドロックが発生したスレッド120がNGであると判定できる。さらに、連続NG回数621が保護回数を超えた場合、監視スレッド110は、スレッド120の異常を検出できる。
前述の図6に示す処理によって、監視スレッド110はスレッド120の状態が正常であるか否かを判定できる。
なお、本実施形態において、開発者または使用者が監視スレッド110を生成および実行するための定義を共有ライブラリ500に設定することによって、監視スレッド110が生成されてもよい。これによって、機器40が有するプログラムが監視スレッド110を提供していない場合も、共有ライブラリ500を変更するのみで監視スレッド110を生成できるため、容易に本実施形態のスレッド監視方法を機器40に実装することができる。
また、本実施形態は、監視方法を監視スレッド110による監視方法に限定するものではなく、前述の図6および図12の処理を実行するためのプロセスまたはスレッドが実行されれば、いかなる監視方法を用いてもよい。
監視スレッド110が、スレッド120を異常と判定した場合の処理について説明する。スレッド120において無限ループまたはデッドロックが発生した場合、異常であると判定されたスレッド120を含むプロセスは、一般的に、スレッド120が異常のまま継続する。しかし、異常であると判定されたスレッド120が含まれるプロセスを継続しても、スレッド120が無限ループまたはデッドロックから自然に回復することはない。
このため、監視スレッド110は、スレッド120の異常を検出した場合、スレッド120、または、スレッド120が含まれるプロセスに、適切な処理を実行してもよい。ここで、適切な処理とは、異常が検出されたスレッド120の情報をログに残し、スレッド120が含まれるプロセスを終了してから、スレッド120が含まれるプロセスを再起動する。異常が検出されたスレッド120を含むプロセスを終了することによって、監視スレッド110は、スレッド120が利用中のメモリ420またはロックの解放漏れを、防ぐことができる。
また、監視スレッド110は、異常が検出されたスレッド120を終了させてから、再度スレッド120を生成してもよい。これによって、プロセスを終了させずに済むため、監視スレッド110は、本実施形態のスレッド監視の対象であるプログラムが提供するサービスへの影響を抑えることができる。
なお、監視スレッド110は、図6に示す処理によって異常と判定されたスレッド120の識別子に基づいて、その異常と判定されたスレッド120を含むプロセスの識別子を、メモリ420から読み出すことが可能であり、読み出されたプロセスの識別子を別プロセスに通知することで、スレッド120を含むプロセスを再起動する。
第1の実施形態によれば、スレッド120が、無限ループ、デッドロック、またはロック処理を伴わない停止状態であることによって、正常に動作していない場合に、スレッド120が異常に動作していることを検出することができる。
また、第1の実施形態によれば、API関数フックによってスレッド120を監視するための生存フラグ140を更新することによって、カーネル100の変更、スレッド監視の対象であるプログラムのソースコードの変更およびリコンパイル、または、スレッド監視の対象であるプログラムのコンパイル済み実行ファイルへの変更を伴わないスレッド監視方法を実現できる。
また、第1の実施形態によれば、既存のAPI関数の処理に生存フラグ140が追加されるのみであるため、スレッド監視の対象のプログラムの処理を大きく遅延させることがない。
(第2の実施形態)
前述の第1の実施形態においては、例えば、図1に示すステップ122における命令メッセージのWAIT状態が監視周期よりも長い場合、監視スレッド110は、正常なWAIT状態を異常として誤判定する可能性がある。第2の実施形態の方法は、例えば、スレッド120をWAIT状態にする処理を含むAPI関数など、処理が監視周期よりも長い時間かかるAPI関数を監視するための方法である。
図7は、本発明の第2の実施形態の異常動作検出の処理を示すシーケンス図である。
図7は、スレッド120による監視情報620の更新処理900、および、更新処理902を示し、監視スレッド110による異常動作検出910〜異常動作検出912を示す。また、WAIT状態901は、本実施形態のAPI関数フックされるAPI関数がWAIT状態である期間を示す。
また、第2の実施形態の監視情報620は、生存フラグ140、連続NG回数621および処理待ち数622を含む。第2の実施形態の生存フラグ140および連続NG回数621は、第1の実施形態の生存フラグ140および連続NG回数621と同じである。処理待ち数622は、スレッド120がWAIT状態901であるか否かを判定するための値を格納する領域である。
更新処理900、WAIT状態901および更新処理902は、本実施形態のAPI関数フックされる一つのAPI関数の処理である。スレッド120は、API関数フックされるAPI関数がWAIT状態901となる前に、更新処理900によって生存フラグ140に1を格納する。すなわち、更新処理900は、第1の実施形態における生存報告200の処理を含む。
一方、監視スレッド110は、更新処理900後の異常動作検出910において生存フラグ140を参照し、スレッド120が正常であると判定する。そして、スレッド120は、更新処理900後にWAIT状態901となる。第2の実施形態におけるWAIT状態901は、監視スレッド110が保持する監視周期よりも長い。
ここで、異常動作検出910〜異常動作検出912が、第1の実施形態の異常動作検出800と同じ処理を行う場合、監視スレッド110は、異常動作検出911において、生存フラグ140に0が格納されているため、WAIT状態901であるスレッド120を異常であると判定する。WAIT状態901は、スレッド120の異常状態ではないため、異常動作検出911によってスレッド120を異常と判定する結果は、誤りである。
そこで、第2の実施形態における監視スレッド110は、異常動作検出処理において監視情報620が保持する処理待ち数622を参照することによって、正常なWAIT状態901を異常と誤判定しない。第2の実施形態のスレッド120は、WAIT状態901になる前後において、監視情報620の処理待ち数622を更新する。
第2の実施形態の機器40のハードウェア構成は、図2に示す第1の実施形態のハードウェア構成と同じく、プロセッサ400、メモリ420、NIF440、バス410、および、バス430を備える。
第2の実施形態におけるAPI関数フック群510の決定方法について説明する。第1の実施形態と同じく、本実施形態のスレッド監視の対象のプログラム、すなわち、スレッド120を生成するプログラムの開発者または使用者がAPI関数フック群510に含まれるAPI関数を選択する。また、開発者または使用者が、第1の実施形態と同じく、スレッドプロシージャ520からAPI関数を抜き出すためのスクリプトを用いて、WAIT状態901になるAPI関数を取得し、取得されたAPI関数をAPI関数フック群510に含めてもよい。
第2の実施形態においてWAIT状態901になるAPI関数には、他のプロセスまたはスレッドから信号を受信するまで、スレッド120を停止させるタイマ付き状態同期関数が含まれる。また、使用者からの入力を待つ入力待ち関数、および、指定された時間の間停止するスリープ関数が含まれる。
第2の実施形態におけるスレッド120は、WAIT状態901になるAPI関数にAPI関数フックする。ここで、ロック取得関数も、WAIT状態901になるAPI関数であるが、一方で、ロック取得関数はデッドロックを引き起こす可能性があるAPI関数である。
このため、開発者または使用者は、API関数フック群510に含めることを禁止するためのリスト(API関数フック禁止リスト)に、ロック取得関数をあらかじめ格納してもよい。そして、開発者または使用者が、API関数フック禁止リストが示すAPI関数以外のAPI関数をAPI関数フック群510に選択することによって、デッドロックにおける監視スレッド110の状態の誤判定を回避できる。
なお、第2の実施形態のAPI関数フック群510には、第1の実施形態と同じくWAIT状態901にならないAPI関数が選択されてもよい。API関数フック群510に、WAIT状態901になるAPI関数と、WAIT状態901にならないAPI関数とが含まれる場合、各API関数がWAIT状態901になるか否かを示すリストをあらかじめ保持し、前述のリストを参照することによって、各API関数に追加する処理を決定してもよい。これによって、本実施形態の機器40は、第1の実施形態と第2の実施形態とを実装することができる。
次に、共有ライブラリ500の生成方法について説明する。第1の実施形態と同じく、開発者または使用者が、API関数フック群510に、各API関数の処理内容として、API関数固有の処理と、生存報告200の処理と、処理待ち数622を更新する処理とを格納する。また、API関数フック群510の処理内容は、各処理が実行される順番を示す。これによって、共有ライブラリ500が生成される。
API関数フック群510の処理内容に含まれる処理待ち数622を更新する処理は、処理待ち数622をスレッド120がWAIT状態901である間増加させる処理を追加である。
具体的には、スレッド120が、処理待ち数622の値を0に初期化してから処理待ち数622に1を加算する処理と、生存フラグ140に1を格納する処理とを実行し、その後、WAIT状態901になるAPI関数固有の処理を実行するように、開発者または使用者はAPI関数フック群510を生成する。さらに、スレッド120が、WAIT状態901になるAPI関数固有の処理の終了直後に処理待ち数622から1を減算する処理を実行するように、開発者または使用者は、API関数フック群510を生成する。
これによって、図7に示すWAIT状態901の開始直前にスレッド120は更新処理900を実行し、処理待ち数622に1を加算する。また、WAIT状態901の終了直後にスレッド120は更新処理902を実行し、処理待ち数622を0にする。このため、監視スレッド110は、異常動作検出911において処理待ち数622が0より大きい場合、スレッド120がWAIT状態901であると判定できる。
次に、第2の実施形態におけるAPI関数フックによる監視情報620の更新処理について説明する。第1の実施形態と同じく、開発者または使用者によって生成された共有ライブラリ500のパスがLD_PRELOAD環境変数530に格納された場合、スレッド120を生成するプログラムの実行ファイルが起動された後、API関数フック群510に含まれるAPI関数のフックが有効になる。
スレッド120が実行されると、API関数フックによって更新処理900および更新処理902が実行され、スレッド120はAPI関数固有の処理の直前に処理待ち数622に1を加算し、API関数固有の処理の直後に処理待ち数622から1を減算する。
次に、異常動作検出910〜異常動作検出912について説明する。異常動作検出910〜異常動作検出912は、図6に示す第1の実施形態の異常動作検出800と同様である。しかし、図6に示すステップ810において、第2の実施形態の生存確認300と、第1の実施形態の生存確認300とが異なる。
図8は、本発明の第2の実施形態の生存確認の処理を示すフローチャートである。
図8に示す処理は、第2の実施形態における図6に示す処理のステップ810に含まれる。そして、第1の実施形態のステップ810における生存確認300に相当する。
第2の実施形態の監視スレッド110がステップ810によって異常動作検出処理を開始した後、監視スレッド110は生存確認処理を開始する(1000)。監視スレッド110は、スレッド120に対応する処理待ち数622に格納される値が0より大きいか否かを判定する(1010)。
ステップ1010において処理待ち数622に格納される値が0より大きいと判定された場合、スレッド120はWAIT状態901である。このため、スレッド120は正常と判定することが可能であり、監視スレッド110はスレッド120を監視する必要がないため、生存確認の結果を有効と判定する(1020)。
ステップ1010において処理待ち数622に格納される値が0であると判定された場合、スレッド120はWAIT状態901ではない。このため、監視スレッド110は、スレッド120を監視するため、生存フラグ140に格納された値が1であるか否かを判定する(1030)。
ステップ1030において生存フラグ140に格納される値が1であると判定された場合、スレッド120は正常に実行されている。このため、監視スレッド110は、生存フラグ140に0を格納し(1040)、ステップ1020を実行する。
ステップ1030において生存フラグ140に格納される値が1ではないと判定された場合、スレッド120は異常である可能性がある。このため、監視スレッド110は、生存確認の結果を無効と判定する(1050)。
ステップ1020またはステップ1050の後、監視スレッド110はステップ810に含まれる生存確認の処理を終了する(1060)。
図6および図8に示す処理によって、図7に示す異常動作検出911を行う場合、監視スレッド110は、処理待ち数622に1が格納されているため、スレッド120が正常であると判定する。
そして、図6および図8に示す処理によって、図7に示す異常動作検出912を行う場合、監視スレッド110は、処理待ち数622に0が格納されており、かつ、生存フラグ140に1が格納されているため、スレッド120が正常であると判定する。これは、図8に示す処理によって、生存フラグ140は、WAIT状態901の間、1を示す値を保持し続けるためである。
第2の実施形態によれば、監視情報620が処理待ち数622を保持することによって、監視スレッド110は、例えば、スレッド120をWAIT状態901にするAPI関数などのAPI関数が、監視周期よりも長い時間処理する場合においても、API関数の処理中はスレッド120を正常であると判定することができる。また、処理待ち数622を生存フラグ140を参照するよりも先に参照することによって、WAIT状態901中は、生存フラグ140が0に更新されない。この結果、監視スレッド110がWAIT状態901終了直後に異常動作検出912を行っても、生存フラグ140には1が格納されているため、監視スレッド110はスレッド120を正常と判定することができる。
第2の実施形態の監視スレッド110が、スレッド120を異常であると判定した場合の処理は、第1の実施形態と同じであり、スレッド120またはスレッド120が含まれるプロセスを再起動する。
第2の実施形態によれば、WAIT状態となるAPI関数をフックすることによって、カーネル100の変更、スレッド監視の対象であるプログラムのソースコードの変更およびリコンパイル、または、スレッド監視の対象であるプログラムのコンパイル済み実行ファイルへの変更を伴わないスレッド監視方法を実現できる。
また、第2の実施形態によれば、監視スレッド110は、WAIT状態が監視周期よりも長い場合にも、正常なWAIT状態を異常として誤判定しない。
また、第2の実施形態によれば、既存のAPI関数の処理に処理待ち数622が追加されるのみであるため、スレッド監視の対象のプログラムの処理を大きく遅延させることがない。
なお、開発者または使用者は、API関数フック群510の生成処理、LD_PRELOAD環境変数530に共有ライブラリ500の識別子を設定する処理、および、監視スレッド110を実行する処理等の、第1の実施形態および第2の実施形態を行うための設定処理を、機器40が備えるキーボード等の入力装置を介して行ってもよい。
また、開発者または使用者は、前述の第1の実施形態および第2の実施形態を行うための設定処理を行うプログラムを生成し、他の計算機から機器40へNIF440を介して、生成されたプログラムを送信してもよい。そして、機器40に、送信されたプログラムによって第1の実施形態および第2の実施形態を行うための設定をさせてもよい。
また、開発者または使用者は、前述の第1の実施形態および第2の実施形態を行うための設定処理を行うプログラムを、計算機によって読み取り可能な非一時的記憶媒体によって、機器40に入力してもよい。
また、第1の実施形態および第2の実施形態において、前述の監視スレッド110は、メモリ420が保持する監視プログラムを実行するためのスレッドであるが、他の機能を有するプログラムに監視スレッド110の機能を含められることによって、実行されてもよい。
(第3の実施形態)
前述した第1の実施形態と第2の実施形態とにおいては、API関数フック群510をスレッド監視の対象であるプログラムの開発者または使用者によって予め選択する必要があった。しかし、第3の実施形態において、定期的または指定された時刻に、API関数の使用状況に基づいてAPI関数フック群510が自動的に決定される。
第3の実施形態における機器40のハードウェア構成は、図2に示す第1の実施形態の機器40と同じである。また、第3の実施形態のプロセッサ400は、第1の実施形態および第2の実施形態と同じく、図4に示す監視スレッド110およびスレッド120を実行する。
図9は、本発明の第3の実施形態のAPI関数フック群510を決定する処理を示す説明図である。
API関数フック群510を決定するために、スレッド120は、API関数の使用状況を示す統計情報1140を更新する。第3の実施形態において、スレッド120は、図9に示す統計情報1140を取得するための共有ライブラリ1100とLD_AUDIT機能とを利用し、各API関数の統計情報1140を取得する。
第3の実施形態におけるLD_AUDIT機能とは、第3の実施形態のLD_AUDIT環境変数1120が保持する機能である。第3の実施形態のLD_AUDIT環境変数1120には、共有ライブラリ1100を読み出すための識別子が格納され、共有ライブラリ1100には、API関数フックされた際の処理内容が含まれる。LD_AUDIT環境変数1120は、第3の実施形態のスレッド監視の対象であるプログラムに含まれるAPI関数をメモリ420にロードする際に読み出される。
そして、共有ライブラリ1100を読み出すための識別子が開発者または使用者によってLD_AUDIT環境変数1120に格納された後、スレッド監視の対象であるプログラムによって実行されるすべてのAPI関数は、メモリ420にロードされる際、共有ライブラリ1100で指定した処理を追加してロードする。なお、スレッドプロシージャ520には、第1の実施形態と同じく、スレッド監視の対象であるプログラムに含まれるAPI関数が含まれる。
共有ライブラリ1100には、API関数名を統計情報1140に出力する処理を示す処理内容1110が格納される。このため、各スレッド120によって実行されるAPI関数は、メモリ420にロードされる際に処理が追加されることによって、API関数固有の処理と、API関数名を統計情報1140に出力する処理とを実行する。
例えば、スレッドプロシージャ520がsleep API関数を含む場合、プロセッサ400がsleep API関数固有の処理560を実行する前に、スレッド120は、メモリ420にロードされた追加処理を実行することによって、sleep API関数の処理560にAPI関数フック1121処理を行う。そして、API関数フック1121がされた後、スレッド120はAPI関数名(すなわち、「sleep」)を統計情報1140に出力する処理内容1110が示す処理を実行する。
従って、共有ライブラリ1100が生成され、LD_AUDIT環境変数1120に共有ライブラリ1100を示す識別子が格納された後に、スレッド監視の対象であるプログラムを起動した場合、統計情報1140には、実行されたAPI関数の使用状況が格納される。
統計情報1140は、メモリ420に保持されるデータの集合であり、API関数名1141と使用回数1142とを保持する。API関数名1141は、処理内容1110の処理によって入力されたAPI関数名を含む。使用回数1142は、API関数名1141が示すAPI関数が、実行された回数を含む。
なお、スレッド120は、処理内容1110が示す処理において、統計情報1140に出力するAPI関数名が統計情報1140に既に含まれているか否かを判定する。そして、スレッド120は、統計情報1140に出力するAPI関数名が統計情報1140に既に含まれていた場合、スレッド120によって出力されるAPI関数名をAPI関数名1141に含むエントリの使用回数1142に1を加算する。
また、統計情報1140に出力するAPI関数名が統計情報1140に含まれていない場合、スレッド120は、処理内容1110が示す処理において、統計情報1140に新たなエントリを生成し、新規API関数としてAPI関数名を生成されたエントリに格納する。そして、生成されたエントリの使用回数1142に1を格納する。これによって、統計情報1140は、API関数が実行された回数を、API関数毎に保持できる。
次に、API関数決定プログラム1170は、更新された統計情報1140からスレッド監視処理におけるAPI関数フック群510を決定する。API関数決定プログラム1170は、機器40がメモリ420に保持するプログラムであり、プロセッサ400によって実行される。API関数決定プログラム1170は、API関数決定プログラム1170の処理が可能であれば、別の機能を含むプログラムによって実装されても、複数のプログラムによって実装されてもよい。
ここで、API関数決定プログラム1170は、統計情報1140に含まれるAPI関数名1141をすべてAPI関数フック群510に決定してもよい。しかし、API関数決定プログラム1170がデッドロックを起こすAPI関数を決定した場合、監視スレッド110がスレッド120の状態を正確に判定できなくなる可能性がある。
そこで、第3の実施形態において、機器40はメモリ420にAPI関数フック禁止リスト1130を保持する。API関数フック禁止リスト1130には、開発者または使用者によって、API関数フック群510として決定されてはいけないAPI関数を示す値が格納される。
API関数決定プログラム1170は、API関数フック禁止リスト1130および統計情報1140を参照し、API関数名1141が示すAPI関数のうち、API関数フック禁止リスト1130に含まれていないAPI関数を、API関数フック群510に決定する。例えば、API関数フック禁止リスト1130にcond_wait API関数が格納される場合、API関数決定プログラム1170は、API関数名1141にcond_wait API関数が含まれていても、cond_wait API関数をAPI関数フック群510に決定しない。
第3の実施形態の共有ライブラリ500およびAPI関数フック群510は、第1の実施形態および第2の実施形態の共有ライブラリ500およびAPI関数フック群510と同じである。
API関数フック禁止リスト1130は、開発者または使用者によって生成される。デッドロックを引き起こす可能性があるAPI関数を、開発者または使用者は事前に取得できるため、開発者または使用者が、本実施形態のスレッド監視の対象であるプログラムのソースコードを閲覧できない場合も、開発者または使用者は、API関数フック禁止リスト1130を生成できる。
図10は、本発明の第3の実施形態のAPI関数決定プログラム1170の処理を示すフローチャートである。
図10は、統計情報1140からAPI関数フック群510を決定する処理を示す。
まず、API関数決定プログラム1170は、定期的、または、開発者もしくは使用者等の指示に従って、API関数フック群510を決定する処理を開始する(1200)。
ステップ1200の後、API関数決定プログラム1170は、統計情報1140の一つのエントリからAPI関数Xを抽出する(1210)。なお、ステップ1210におけるAPI関数決定プログラム1170は、API関数フック群510にまだ含まれていない関数であれば、統計情報1140のいかなるAPI関数を抽出してもよい。
ステップ1210の後、API関数決定プログラム1170は、ステップ1210によって統計情報1140からAPI関数Xが抽出されたか否かを判定する(1220)。API関数Xが抽出されない場合、API関数フック群に決定するべきAPI関数がないため、API関数決定プログラム1170は、図10に示す処理を終了する。
ステップ1220において、API関数Xが抽出されたと判定された場合、API関数決定プログラム1170は、API関数XをAPI関数名1141に含む統計情報1140のエントリの使用回数1142を抽出し、抽出された使用回数1142が所定の閾値Tより大きいか否か判定する(1230)。ここで、所定の閾値Tとは統計情報1140に含まれるAPI関数を、API関数フック群510に含めるか否かを判定するための閾値であり、ここでは統計情報1140の各エントリの使用回数1142の値の平均値である。
ステップ1230において、抽出された使用回数1142が所定の閾値T以下であると判定された場合、API関数Xは、監視スレッド110によって監視されるほど、頻繁に実行される関数ではない。このため、API関数決定プログラム1170は、API関数XをAPI関数フック群510に決定しない。そして、API関数決定プログラム1170は、ステップ1210に戻り、API関数Xを抽出しなおす。
ステップ1230において、抽出された使用回数1142が所定の閾値Tよりも大きいと判定された場合、API関数Xは、監視スレッド110によって監視されるべきAPI関数である可能性が高い。このため、API関数決定プログラム1170は、API関数XがAPI関数フック禁止リスト1130に含まれているか否かを判定する(1240)。
ステップ1240において、API関数XがAPI関数フック禁止リスト1130に含まれていると判定された場合、API関数Xは、API関数フック群510として決定されるべきAPI関数ではない。このため、API関数決定プログラム1170は、ステップ1210に戻り、API関数Xを抽出しなおす。
ステップ1240において、API関数XがAPI関数フック禁止リスト1130に含まれていないと判定された場合、API関数決定プログラム1170は、API関数XをAPI関数フック群510に追加する(1250)。そして、新しいAPI関数Xを抽出するため、ステップ1210に戻る。
具体的には、図9に示す統計情報1140において、sleep API関数を示すエントリの使用回数1142は100回を示し、printf API関数の使用回数1142は10回である。このため、使用回数1142の平均値は55であり、ステップ1230における閾値Tは55である。そして、API関数決定プログラム1170は、ステップ1230によってsleep API関数のみを決定し、ステップ1250によってsleep API関数をAPI関数フック群510に追加する。
なお、処理内容1110は、統計情報1140にAPI関数の使用時刻またはAPI関数のスレッドIDなど追加する処理を含んでもよい。そして、API関数決定プログラム1170は、統計情報1140に格納される値に基づいて、監視スレッド110が保持する監視周期と、図6に示すステップ850において監視スレッド110によって用いられる保護回数とを算出してもよい。
例えば、API関数が頻繁に実行される時間帯が、統計情報1140のAPI関数の使用時刻から取得できる場合、API関数決定プログラム1170は、API関数が頻繁に実行される時間帯において監視スレッド110が頻繁に監視情報620を参照するように、監視スレッド110の監視周期を定めてもよい。
また、統計情報1140にAPI関数のスレッドIDが含まれる場合、API関数決定プログラム1170は、スレッド毎にAPI関数の使用状況を考慮してAPI関数フック群510を決定してもよい。
なお、第3の実施形態と、第1の実施形態と、第2の実施形態とを併用し、開発者または使用者が統計情報1140からAPI関数フック群510に格納されるAPI関数を選択してもよい。また本実施形態は、統計情報1140を取得する方法をLD_AUDIT環境変数1120によるAPI関数フックに限定しなくてもよく、プロセスまたはスレッド120によって読み出される変数を介して、API関数フック処理を読み出せれば、いかなる変数を用いてもよい。
第3の実施形態の共有ライブラリ500の生成処理、API関数フックによる生存報告処理、異常動作検出処理、異常検出時の処理については、第1の実施形態または第2の実施形態と同じである。すなわち、API関数決定プログラム1170がWAIT状態になるAPI関数をAPI関数フック群510に含める場合、第3の実施形態の監視スレッド110およびスレッド120は、第2の実施形態と同じ処理を行い、API関数決定プログラム1170がWAIT状態になるAPI関数を含めない場合、第3の実施形態の監視スレッド110およびスレッド120は、第1の実施形態と同じ処理を行う。
第3の実施形態によれば、カーネル100の変更、スレッド監視の対象であるプログラムのソースコードの変更およびリコンパイル、スレッド監視の対象であるプログラムのコンパイル済み実行ファイルへの変更を伴わずに、API関数フック群510を自動的に決定でき、さらに、スレッド監視を自動的に実行することができる。
また、第3の実施形態によれば、開発者または使用者がソースコードを閲覧できない場合も、API関数決定プログラム1170によって、API関数フック群510が自動的に決定される。また、統計情報1140にAPI関数の使用状況を示す値を格納することによって、開発者または使用者の環境に従って、最適なAPI関数フック群510が決定される。
また、第3の実施形態によれば、API関数フック禁止リスト1130を用いることによって、呼ばれる回数が多く、実行速度に影響がある排他制御(例えば、ロック取得の処理またはアンロックの処理など)をAPI関数フック群510に決定しないことができる。このため、第3の実施形態のスレッド監視方法を提供するために、スレッド監視の対象であるプログラムの処理を遅延させることがない。
なお、第3の実施形態における開発者または使用者は、API関数フックを決定するために、スレッド監視の対象となるプログラムを含むソフトウェアを、API関数フック群510を決定するために起動し、さらに、決定されたAPI関数フック群510を読み出すために共有ライブラリ500を起動する必要がある。このため、第3の実施形態における機器40は、スレッド監視の対象となるプログラムを含むソフトウェアを連続して起動するためのプログラムを、メモリ420に保持してもよい。
また、開発者または使用者は、共有ライブラリ1100および処理内容1110の生成処理、LD_AUDIT環境変数1120に共有ライブラリ1100の識別子を設定する処理、および、API関数決定プログラム1170を実行する処理等の第3の実施形態を実行するための設定処理を、機器40が備えるキーボード等の入力装置を介して行ってもよい。
また、第3の実施形態において、開発者または使用者は、前述の第3の実施形態を行うための設定処理を行うプログラムを生成し、他の計算機から機器40へNIF440を介して、生成されたプログラムを送信してもよい。そして、機器40に、送信されたプログラムを実行させてもよい。
また、第3の実施形態において、開発者または使用者は、前述の第3の実施形態を行うための設定処理を行うプログラムを、計算機によって読み取り可能な非一時的記憶媒体によって、機器40に入力してもよい。
本実施形態によれば、スレッド120が、無限ループ、デッドロック、またはロック処理を伴わない停止状態であることによって、正常に動作していない場合に、スレッド120が異常に動作していることを検出することができる。
また、本実施形態によれば、API関数フックによってスレッド120を監視するための生存フラグ140を更新することによって、カーネル100の変更、スレッド監視の対象であるプログラムのソースコードの変更およびリコンパイル、または、スレッド監視の対象であるプログラムのコンパイル済み実行ファイルへの変更を伴わないスレッド監視方法を実現できる。
また、本実施形態によれば、既存のAPI関数の処理に監視情報620を更新する処理が追加されるのみであるため、スレッド監視の対象のプログラムの処理を大きく遅延させることがない。さらに、図11に示すステップ123における監視命令メッセージが不要であるため、プログラムサイズの縮小とプロセッサの処理時間の削減とが可能になる。