SIGNALQQ の使用と SIGNALQQ の動作内容

簡単な例外処理要求に対して,SIGNALQQ で確立するハンドラがその要求を満たす場合があります。この節では,SIGNALQQ でのシグナル処理方法と GETEXCEPTIONPTRSQQ の動作内容について説明します。

Microsoft Visual C++ が提供している C 実行時ソースを参照してます。Visual C++ を持っていなくても,この節を参照するのは有用です。以下のトピックについて説明しています。

C スタイルのシグナル処理の概要

多くの Fortran アプリケーションは,C スタイルのシグナル処理が例外を処理する一般的な方法として使われていた U*X システムで開発されていました。Windows に移植する場合,これらのアプリケーションは C シグナル・インタフェースを継続して使用することができます。SIGNALQQ は,純粋な Fortran または Fortran と C コードが混在したものを使用するどのようなアプリケーション形式でも動作します。これは,たとえば,VB-VF アプリケーションではうまく動作しません。

SIGNALQQ は,C 実行時 signal() 関数への Fortran ジャケット関数です。SIGNALQQ を呼び出すと,実際には,C 実行時システムで特定のシグナルに対して自分のシグナル・ハンドラ (または動作) を登録することになります。C 実行時システムは,単に,内部例外動作テーブル,または希望するシグナルをハンドラに関連付ける変数にハンドラ (または動作) を保存します。オペレーティング・システムは,この関連付けについて知りません。

Visual C++ を持っている場合,...\MICROSOFT VISUAL STUDIO\VC98\CRT\WINSIG.C 中の C 実行時シグナル・ルーチンのコードを参照することができ,テーブルがどのように管理されているかを調べることができます。テーブル自身は,同じフォルダにあるソース・ファイル WINXFLTR.C に定義され,初期化されています。シグナルが発生すると,特定のシグナルに対して登録されたハンドラがあるかどうかを調べるために,C 実行時システムは内部テーブルを検証します。ハンドラを割り当てていると,自分のルーチンが呼び出されます。

シグナルは SEH

シグナルが発生した時に自分のハンドラを呼び出すのは C 実行時システムであって,オペレーティング・システムではないことに注意してください。それでは,C 実行時システムはどのようにして発行される例外を受け取るのでしょうか?実行形式ファイルのエントリ・ポイントが,アプリケーション・タイプに依存して mainCRTStartupWinMainCRTStartup のどちらかであることを思い出してください。「Visual Fortran アプリケーションの構造」をもう一度見直して,これらのエントリ・ポイント (または C 実行時ソースのソース・ファイル Crt0.c を参照) を参照してください。それらは,main() または WinMain() への呼び出しを Try/Except コンストラクトでラップし,__except コンストラクトに関連したフィルタ式が関数 _XcptFilter を呼び出すことに注意してください。_XcptFilter は,例外情報をオペレーティングシステムに提供する 2 つの引数を渡されます。

例外が発生すると,オペレーティング・システムは,例外フィルタの一覧を参照し,Try/Except コンストラクトの最も内側にネストした場所から EXCEPTION_CONTINUE_SEARCH を返さない例外フィルタを見つけるまで例外フィルタ式を評価します。アプリケーション・タイプが Fortran 実行時システムからの mainmain に関連した except コンストラクトを含む場合,Fortran 実行時フィルタは C 実行時フィルタの前に評価されます。Fortran フィルタ式は,SIGNALQQ で自分のハンドラが確立されているかどうかを調べるために評価されます。そのようなハンドラがあることがわかると,または,環境変数 FOR_IGNORE_EXCEPTIONS が設定されていると,C 実行時例外フィルタが例外を処理し,自分のハンドラを見つけることができるようにするための EXCEPTION_CONTINUE_SEARCH を返します。自分自身のハンドラを確立していないか,環境変数を設定していない場合,Fortran 実行時システムは基本例外処理を実行時します。

C フィルタ関数 _XcptFilter は,オペレーティング・システムからの例外コードとオペレーティング・システム例外から C シグナル・コードへのマッピングとを比較します。テーブルで一致したものを見つけると,シグナル・コードに対応するテーブル中の例外動作エントリを使用します。これは,自分の SIGNALQQ ハンドラが要求したシグナル・コードに対する動作として記録されるものと同じテーブルです。自分のハンドラを確立すると,それは _XcptFilter から呼び出されます。自分のハンドラが呼び出される前に,_XcptFilter は例外動作テーブルのシグナルに対する指定された動作を SIG_DFL にリセットします。例外から処理を継続し,シグナルの次の発生場所で自分のハンドラを呼び出したい場合,そのシグナルに対する動作として自分のハンドラを再確立するために,SIGNALQQ を再び呼び出さなければなりません。自分のハンドラ・ルーチンが実行を終了し,_XcptFilter に戻ると,値 EXCEPTION_CONTINUE_EXECUTION_XcptFilter によってオペレーティング・システムに返されます。オペレーティング・システムは,例外の発生した点で実行を再開します。実行を継続したくない場合,ハンドラはアプリケーションをシャットダウンするための適切な動作を取らなければなりません。

すべてのオペレーティング・システム例外コードが C シグナル・コードにマップされているわけではありません。もしあれば,WINXFLTR.C ソース・ファイルでマップを参照することができます。以下に WINXFLTR.C ソース・ファイル (Visual C++ バージョン 6.0) のマップを示します。

オペレーティング・システム例外コードC シグナル番号
STATUS_ACCESS_VIOLATIONSIGSEGV
STATUS_ILLEGAL_INSTRUCTIONSIGILL
STATUS_PRIVILEGED_INSTRUCTIONSIGILL
STATUS_FLOAT_DENORMAL_OPERANDSIGFPE
STATUS_FLOAT_DIVIDE_BY_ZEROSIGFPE
STATUS_FLOAT_INEXACT_RESULTSIGFPE
STATUS_FLOAT_INVALID_OPERATIONSIGFPE
STATUS_FLOAT_OVERFLOWSIGFPE
STATUS_FLOAT_STACK_CHECKSIGFPE
STATUS_FLOAT_UNDERFLOWSIGFPE

GETEXCEPTIONPTRSQQ の動作内容

C 実行時例外フィルタ関数 _XcptFilterSIGNALQQ で確立した自分のハンドラを呼び出す時,ハンドラに渡される唯一の引数は C シグナル番号です。C 実行時システムはまた,オペレーティング・システムが提供する例外情報へのポインタも保存します。ポインタは _pxcptinfoptrs という名前で,Fortran 実行時ルーチン GETEXCEPTIONPTRSQQ で取り出すことができます。_pxcptinfoptrs の定義は,C ヘッダ・ファイル signal.h を参照してください。

GETEXCEPTIONPTRSQQ が返す値は,TRACEBACKQQ を使ってトレースバックを生成するために自分のハンドラ・ルーチンで使用することができます。GETEXCEPTIONPTRSQQ は,_pxcptinfoptrs を返します。このポインタは,C 実行時フィルタ関数 _XcptFilter の評価で実行されている間のみ有効です。これは,例外情報がプログラム・スタック上にあり,他のコンテキストの GETEXCEPTIONPTRSQQ を使用できないためです。

GETEXCEPTIONPTRSQQ を使用した例として,Visual Fortran サンプル・プログラムの ...\SAMPLES\EXCEPTIONHANDLING\GETEPTRS を参照してください。