Previous: , Up: Writing Dynamic Modules   [Contents][Index]


E.8.5 モジュールでの非ローカル脱出

Emacs Lispは非ローカル脱出(nonlocal exits)をサポートしており、これによりプログラムの制御はプログラムのあるポイントから別の離れたポイントに転送されます。Nonlocal Exitsを参照してください。したがってモジュールから呼び出されたLisp関数はsignalthrowを呼び出して非ローカルにexitするかもしれず、そのような非ローカル脱出をモジュール関数は正しくハンドルしなければなりません。このようなハンドリングはCプログラムがリソースを自動的に解放せず、このような場合には別のクリーンアップを行うために必要になります。モジュールコードは自身でこれを行わなければなりません。そのための機能をモジュールAPIは提供しており、このサブセクションではそれを説明します。これらは一般的にはEmacs 25以降で利用可能です。これ以降のリリースで利用可能になったものについては、APIに含まれるようになった最初のEmacsのバージョンを付記します。

モジュール関数から呼び出されたLispコードがエラーをシグナルしたりthrowを行う際には、非ローカル脱出はtrapされて保留中のexitと関連するデータは環境内に格納されます。環境内で非ローカル脱出が保留中の際には、環境へのポインターで呼び出されたすべてのモジュールAPI関数は何も処理を行わずに即座にリターンします(関数non_local_exit_checknon_local_exit_getnon_local_exit_clearはこのルールの例外)。モジュール関数が何も行わずにEmacsにリターンすれば、保留中の非ローカル脱出にたいしてEmacsがエラーをシグナルしたり、対応するcatchへのthrowという対処を行うでしょう。

したがって特別なことな何も行わずに、何事もなかったかのようにコードの残りを実行するのが、モジュール関数での非ローカル脱出にけるもっともシンプルな“ハンドリング”です。しかしこれは2つのクラスの問題を引き起こすかもしれません:

したがってモジュール関数は以下に説明する関数を使用して、非ローカル脱出のコンディションのチェックとリカバリングを行うことを推奨します。

Function: enum emacs_funcall_exit non_local_exit_check (emacs_env *env)

この関数はenvに格納された非ローカル脱出のコンディションをリターンする。可能な値は:

emacs_funcall_exit_return

最後のAPI関数は正常にexitした。

emacs_funcall_exit_signal

最後のAPI関数はエラーをシグナルした。

emacs_funcall_exit_throw

最後のAPI関数はthrowを通じてexitした。

Function: emacs_funcall_exit non_local_exit_get (emacs_env *env, emacs_value *symbol, emacs_value *data)

この関数はnon_local_exit_checkが行うようにenvに格納された非ローカル脱出の種別をリターンするが、もしあれば非ローカル脱出に関する完全な情報もリターンする。リターン値がemacs_funcall_exit_signalなら関数は*symbolにエラーシンボル、*dataにエラーデータを格納する(Signaling Errorsを参照)。リターン値がemacs_funcall_exit_throwなら関数は*symbolcatchされたたタグシンボル、*datathrowされた値を格納する。リターン値がemacs_funcall_exit_returnなら関数はこれらの引数が指すメンモリー内に何も格納しない。

何らかのリソースの割り当て前や解放を要するリソースの割り当て後、あるいは失敗がそれ以上の処理が不可能もしくは実行不能を意味するような場合のように、非ローカル脱出が問題になるようならチェックするべきです。

モジュール関数が保留中の非ローカル脱出を一度検知すれば、(必要なローカルクリーンアップの実施後に)Emacsにリターンしたり、非ローカル脱出からのリカバリーを試みることができます。以下のAPI関数はこれらのタスクの助けとなるでしょう。

Function: void non_local_exit_clear (emacs_env *env)

この関数は保留中の非ローカル脱出のコンディションとenv由来のデータをクリアーする。これの呼び出し後にはモジュールAPI関数は通常どおり機能するだろう。モジュール関数が呼び出したLisp関数の非ローカル脱出からリカバーして継続可能な場合、あるいは以下の2つの関数のいずれか(非ローカル脱出が保留中の際に他のAPI関数に意図した動作を行わせたい場合にはそれらのAPI関数も)を呼び出す前にもこの関数を使用すること

Function: void non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value)

この関数はtagで表されるLispのcatchシンボルにリターン値としてvalueを渡してthrowを行う。モジュール関数は一般的にはこの関数の呼び出し後は即座にリターンすること。この関数は呼び出されたAPI関数やLisp関数のいずれかから非ローカル脱出を再throwしたい際の1つの手段である。

Function: void non_local_exit_signal (emacs_env *env, emacs_value error, emacs_value data)

この関数はerrorで表されるエラーを、指定したエラーデータdataとともにシグナルする。モジュール関数はこの関数の呼び出し後は即座にリターンすること。この関数はたとえばモジュール関数からEmacsにエラーをシグナルする際に有用かもしれない。