タスク例外処理機能は、タスクに発生した例外事象に対する処理を、タスクのコンテキストで行うための機能である。
タスク例外ハンドラが起動されるのは、次の条件がすべて揃った時である。
tk_def_tex によるタスク例外ハンドラの登録
tk_ena_tex によるタスク例外の許可
tk_ras_tex によるタスク例外の発生
タスク例外ハンドラは、タスク例外が発生したタスクのコンテキストで、かつタスク生成時に指定した保護レベルで、そのタスクの一部として実行される。また、タスク例外ハンドラ内では、タスク例外に関する状態を除き、通常のタスク部の実行中と同じ状態であり、使用できるシステムコールも同等である。
タスク例外ハンドラは、対象タスクがタスク部を実行しているときにのみ起動される。対象タスクがタスク部以外を実行中のときにタスク例外が発生した場合は、タスク部に戻ってからタスク例外ハンドラが起動される。準タスク部(拡張SVC)を実行中にタスク例外が発生した場合は、拡張SVCの処理が中止されタスク部へ戻ってくる。その際、拡張SVCを中止するために必要な処理(拡張SVCに対する「ブレーク処理」と呼ぶ)があれば、それを実行してから、拡張SVCの要求元のタスクに戻る。ブレーク処理は、サブシステム管理機能のブレーク関数によって実行される。
発生したタスク例外要求は、タスク例外ハンドラが呼び出された(タスク例外ハンドラが実行を開始した)時点でクリアされる。
タスク例外は、0~(UINT型のビット幅 - 1)のタスク例外コードにより指定される。例えば、UINTが16ビットの環境では、0〜15の例外コードが利用可能である。このうち、0が最も優先度が高く(UINT型のビット幅 - 1)が低い。また、タスク例外コード0は特殊な扱いとなる。
タスク例外ハンドラはネストして実行されない。タスク例外ハンドラの実行中に発生したタスク例外はペンディングされる。(タスク例外コード0の場合を除く)
タスク例外ハンドラからリターンすることで、タスク例外によって割り込まれた位置に復帰する。
タスク例外ハンドラからリターンせずに、longjmp()
などによりタスク内の任意の位置にジャンプすることもできる。
タスク例外コード1~(UINT型のビット幅 - 1)のタスク例外ハンドラを実行中でもネストして実行される。タスク例外コード0のタスク例外ハンドラの実行中はネストされない。
ユーザスタックポインタをタスク起動時の初期値に設定してから、タスク例外ハンドラが実行される。ただし、ユーザスタックとシステムスタックが分離されていないシステムでは、スタックポインタは初期値に戻されない。
タスク例外ハンドラから復帰することは出来ない。必ず tk_ext_tsk または tk_exd_tsk によってタスクを終了しなければならない。
移植ガイドライン | |
---|---|
利用可能なタスク例外コードはUINT型のビット幅に依存するため注意が必要である。たとえば16ビット環境ではタスク例外コードの範囲が0〜15に限られる。 |
pk_dtex
の内容
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
tskid
で指定したタスクに対するタスク例外ハンドラを定義する。タスク例外ハンドラはタスクに対して1つのみ定義可能で、すでに定義されていた場合は、後から定義した関数が有効となる。pk_dtex
=NULL の時は定義を解除する。
タスク例外ハンドラを定義または解除すると、ペンディングされているタスク例外要求はクリアされ、すべてのタスク例外は禁止状態となる。
texatr
は、下位側がシステム属性を表し、上位側が実装独自属性を表す。texatr
のシステム属性には、現在のバージョンでは割当てがなく、システム属性は使われていない。
タスク例外ハンドラは、下記のような形式になる。
void texhdr( INT texcd ) { /* タスク例外の処理 */ /* タスク例外ハンドラの終了 */ if ( texcd == 0 ) { tk_ext_tsk() または tk_exd_tsk(); } else { tk_end_tex(); return または longjmp(); } }
タスク例外ハンドラは、TA_ASM 属性相当のみで高級言語対応ルーチンを経由しての呼出は行われない。したがって、タスク例外ハンドラのエントリー部分はアセンブリ言語で作成する必要がある。カーネル提供者は、上記のC言語のタスク例外ハンドラを呼び出すためのエントリールーチンのアセンブリ言語のソースコードを提供しなければならない。つまり、高級言語対応ルーチンに相当するソースコードを提供しなければならない。
タスク生成時の保護レベルが TA_RNG0 のタスクに対して、タスク例外を使用することはできない。
タスク生成時にはタスク例外ハンドラは定義されておらず、タスク例外も禁止されている。
タスクが休止状態(DORMANT)に戻る時には自動的にタスク例外ハンドラは解除され、タスク例外は禁止される。また、ペンディングされていたタスク例外はクリアされる。ただし、休止状態(DORMANT)であるときに、タスク例外ハンドラを定義することはできる。
タスク例外は、tk_ras_tex によって発生するソフトウェア的なもので、CPUの例外と直接の関連はない。
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
tskid
のタスクへのタスク例外の発生を許可する。
texptn
は、タスク例外コードを1<<タスク例外コードのビット値として、論理和(OR)した値である。
tk_ena_tex は、texptn
で指定したタスク例外を許可する。 現在のタスク例外の許可状態を texmask
とすると次のようになる。
許可:texmask |= texptn |
texptn
の全ビットを0とした場合は、texmask
に対して何の操作も行わないことになる。ただし、この場合でもエラーとはならない。
タスク例外ハンドラが定義されていないタスクのタスク例外を許可することはできない。
休止状態(DORMANT)のタスクに対しても適用される。
指定可能なタスク例外コードはUINT型のビット幅に依存するため注意が必要である。たとえば16ビット環境ではタスク例外コードが0〜15に限られる。
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
tskid
のタスクへのタスク例外の発生を禁止する。
texptn
は、タスク例外コードを1<<タスク例外コードのビット値として、論理和(OR)した値である。
tk_dis_tex は、texptn
で指定したタスク例外を禁止する。現在のタスク例外の許可状態を texmask
とすると次のようになる。
禁止:texmask &= ~texptn |
texptn
の全ビットを0とした場合は、texmask
に対して何の操作も行わないことになる。ただし、この場合でもエラーとはならない。
禁止されているタスク例外は無視され、ペンディングもされない。ペンディングされているタスク例外がある状態で、そのタスク例外が禁止された場合は、タスク例外要求が捨てられる(ペンディング状態がクリアされる)。
休止状態(DORMANT)のタスクに対しても適用される。
指定可能なタスク例外コードはUINT型のビット幅に依存するため注意が必要である。たとえば16ビット環境ではタスク例外コードが0〜15に限られる。
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
tskid
のタスクに対して texcd
のタスク例外を発生させる。ただし、tskid
のタスクにおいて texcd
のタスク例外が許可されていない場合は、発生させたタスク例外は無視され、ペンディングもされない。この場合でも、本システムコールには E_OK が返される。
tskid
のタスクがタスク例外ハンドラの実行中であれば、タスク例外はペンディングされる。ペンディングされる場合、対象タスクが拡張SVCの実行中であっても、その拡張SVCに対するブレーク処理(ブレーク関数)は実行されない。
ただし、texcd
=0の場合は、対象タスクが例外ハンドラを実行中であってもペンディングされない。対象タスクが、タスク例外コード1~(UINT型のビット幅 - 1)の例外に対するタスク例外ハンドラの実行中であればタスク例外は受け付けられ、拡張SVC実行中であれば、その拡張SVCに対するブレーク処理(ブレーク関数)が実行される。対象タスクが、タスク例外コード0の例外に対するタスク例外ハンドラを実行中の場合は、タスク例外の発生は無視される。
tskid
=TSK_SELF=0によって自タスクの指定を行うことができる。
タスク独立部から発行することはできない。(E_CTX)
対象タスクが拡張SVCを実行中の場合には、その拡張SVCに対応するブレーク処理(ブレーク関数)が、tk_ras_tex の発行タスクの準タスク部として実行される。すなわち、ブレーク処理の実行されるコンテキストは、tk_ras_tex の発行タスクを要求タスクとする準タスク部である。
したがって、このような場合、ブレーク処理の実行が終わるまで tk_ras_tex から戻ってこない。このため、タスク独立部から tk_ras_tex を発行することはできない仕様になっている。
また、ブレーク処理実行中に tk_ras_tex を呼び出したタスクに発生したタスク例外は、ブレーク処理(ブレーク関数)の終了まで保留される。
指定可能なタスク例外コードはUINT型のビット幅に依存するため注意が必要である。たとえば16ビット環境ではタスク例外コードが0〜15に限られる。
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
タスク例外ハンドラを終了し、新たなタスク例外ハンドラの呼出を許可する。ペンディングされているタスク例外がある場合は、その内の最も優先度の高いタスク例外コードを戻値に返す。ペンディングされているタスク例外がなければ0を返す。
enatex
=FALSE の場合、ペンディングされているタスク例外があると新たなタスク例外ハンドラの呼出は許可されない。この場合、tk_end_tex から戻った時点で、戻値に返された texcd
の例外ハンドラを実行している状態になっている。ペンディングされているタスク例外がない場合は新たなタスク例外ハンドラの呼出が許可される。
enatex
=TRUE の場合は、ペンディングされているタスク例外の有無に関係なく、新たなタスク例外ハンドラの呼出を許可する。ペンディングされているタスク例外があっても、タスク例外ハンドラを終了した状態になる。
タスク例外ハンドラの終了は tk_end_tex を呼び出すこと以外にはない。タスク例外ハンドラが起動されてから tk_end_tex を呼び出すまでがタスク例外ハンドラの実行中となる。tk_end_tex を呼び出さずにタスク例外ハンドラからリターンしたとしても、リターン先はまだタスク例外ハンドラの実行中となる。同様に、tk_end_tex を呼び出さずに longjmp
によりタスク例外ハンドラから抜けたとしても、そのジャンプ先はタスク例外ハンドラの実行中である。
タスク例外がペンディングされている状態で tk_end_tex を呼び出すことにより、ペンディングされていたタスク例外が新たに受け付けられる。この時、tk_end_tex を拡張SVCハンドラ内から呼び出した場合でも、tk_end_tex を呼び出した拡張SVCハンドラに対するブレーク処理(ブレーク関数)は実行されない。拡張SVCをネストして呼び出していた場合は、拡張SVCのネストが1段浅くなるときに戻先の拡張SVCに対応するブレーク処理(ブレーク関数)が実行される。タスク例外ハンドラが呼び出されるのは、タスク部に戻ってからとなる。
タスク例外コード0の場合、タスク例外ハンドラを終了することはできないため、tk_end_tex を発行することはできない。必ず tk_ext_tsk または tk_exd_tsk でタスクを終了しなければならない。タスク例外コード0を処理中に tk_end_tex を発行した場合の動作は不定(実装依存)である。
タスク例外ハンドラ以外から発行することはできない。タスク例外ハンドラ以外から発行した場合の動作は不定(実装依存)である。
tk_end_tex(TRUE) とすると、ペンディングされたタスク例外がある場合、tk_end_tex の直後にさらにタスク例外ハンドラが呼び出されることになる。そのため、スタックが戻されないままにタスク例外ハンドラが呼び出されることとなり、スタックオーバーフローの可能性がある。
通常は tk_end_tex(FALSE)を利用し、次のようにタスク例外が残っている間繰り返し処理するようにするとよい。
void texhdr( INT texcd ) { if ( texcd == 0 ){ /* タスク例外0用の処理 */ tk_exd_tsk(); } do { /* タスク例外1~(UINT型のビット幅 - 1)用の処理 */ } while ( (texcd = tk_end_tex(FALSE)) > 0 ); }
厳密には、tk_end_tex で0が返されループを終了してから texhdr
を抜けるまでの間にタスク例外が発生した場合には、スタックが戻されずに texhdr
に再入する可能性はある。しかし、タスク例外はソフトウェア的なものであり、タスクの実行と無関係に発生することは通常ないため、実用上は問題ないと思われる。
指定可能なタスク例外コードはUINT型のビット幅に依存するため注意が必要である。たとえば16ビット環境ではタスク例外コードが0〜15に限られる。
pk_rtex
の内容
以下のサービスプロファイルが有効に設定されている場合に限り、本システムコールはサポートされる。
tskid
で示された対象タスクのタスク例外の状態を参照する。
pendtex
は現在発生しているタスク例外を示す。タスク例外の発生からタスク例外ハンドラが呼び出されるまでの間、pendtex
に示される。
texmask
は許可されているタスク例外を示す。
pendtex
, texmask
とも、1<<タスク例外コードのビット値として表した値である。
tskid
=TSK_SELF=0によって自タスクの指定を行うことができる。ただし、タスク独立部から発行したシステムコールで tskid
=TSK_SELF=0を指定した場合には、E_ID のエラーとなる。