システムコール

システムコールの形式

μT-Kernelでは、C言語を標準的な高級言語として使用することにしており、C言語からシステムコールを実行する場合のインタフェース方法を標準化している。

一方、アセンブリ言語のインタフェース方法は実装定義とする。アセンブリ言語でプログラムを作成する場合でも、C言語のインタフェースを利用して呼び出す方法を推奨する。これにより、アセンブリ言語で作成したプログラムも同一CPUであればOSが変わっても移植性が確保できる。

システムコールインタフェースでは、次のような共通原則を設けている。

システムコールインタフェースの実装方法は実装依存とする。例えば、C言語のマクロやインライン関数、インラインアセンブリなどを用いて実装することが考えられる。

システムコールのC言語インタフェースのうち、パケットやポインタを使ってパラメータを渡すものについては、μT-Kernelがポインタ参照先のパラメータを書き換えないことを明示するために、CONSTという修飾子を付けている。

CONSTは、C言語の const 修飾子を意図したものであるが、const 修飾子に未対応のプログラムが混在した場合に、#defineのマクロ機能を使ってコンパイラのチェックを無効化できるように、const と類似した別名を使っている。

具体的なCONSTの使い方は以下のようになる。なお、詳細は開発環境に依存する。

  1. 共通のインクルードファイルに次の記述を含める。

    /* TKERNEL_CHECK_CONST の定義がある場合に const のチェックを有効化 */
    #ifdef TKERNEL_CHECK_CONST
    #define CONST const
    #else
    #define CONST
    #endif
  2. プログラム中の関数定義やシステムコールの定義は、CONSTを用いて記述する。

    例 1. CONSTの記述例

    tk_cre_tsk( CONST T_CTSK *pk_ctsk );
    foo_bar( CONST void *buf );
  3. Makefile 内の指定で const を有効化する。(推奨)

    例 2. const 有効化の例

    CFLAGS += -DTKERNEL_CHECK_CONST

    ※ 上記の指定がない場合は、const のチェックが無効になる。

μT-Kernel 2.0以降では、プログラム中にCONSTを明示し、const のチェックを有効にして運用することを強く推奨する。

注意T-Kernel 2.0との差異
 

T-Kernelではシステムコールインタフェースはライブラリとして実装されることが定められているが、μT-Kernelでは実装依存とする。これは、μT-Kernelでは異なるコンパイラ間での移植性よりも実行効率を優先する選択を可能にするためである。

注意μT-Kernel 1.0との差異
 

T-Kernel 2.0仕様に基づき、システムコールのC言語インタフェースにCONSTを追加し、const 修飾子によるチェックを推奨することとした。ただし、const 修飾子に未対応のプログラムに対する回避策も設けた。

タスク独立部から発行できるシステムコール

次のシステムコールは、タスク独立部およびディスパッチ禁止状態から発行できる。

システムコール名称説明
tk_sta_tsk タスク起動
tk_wup_tsk 他タスクの起床
tk_rel_wai 他タスクの待ち状態解除
tk_sus_tsk 他タスクを強制待ち状態へ移行
tk_sig_sem セマフォ資源返却
tk_set_flg イベントフラグのセット
tk_sig_tev タスクイベントの送信
tk_rot_rdq タスクの優先順位の回転
tk_get_tid 実行状態タスクのタスクID参照
tk_sta_cyc 周期ハンドラの動作開始
tk_stp_cyc 周期ハンドラの動作停止
tk_sta_alm アラームハンドラの動作開始
tk_sta_alm_u アラームハンドラの動作開始(マイクロ秒単位)
tk_stp_alm アラームハンドラの動作停止
tk_ref_tsk タスク状態参照
tk_ref_tsk_u タスク状態参照(マイクロ秒単位)
tk_ref_cyc 周期ハンドラ状態参照
tk_ref_cyc_u 周期ハンドラ状態参照(マイクロ秒単位)
tk_ref_alm アラームハンドラ状態参照
tk_ref_alm_u アラームハンドラ状態参照(マイクロ秒単位)
tk_ref_sys システム状態参照
tk_ret_int 割込みハンドラから復帰(アセンブリ言語で記述された割込みハンドラからのみ発行可能)

上記以外のシステムコールがタスク独立部およびディスパッチ禁止状態から発行できるか否かは実装依存である。

システムコールの呼出制限

システムコールを呼び出すことのできる保護レベルを制限することができる。この場合、指定した保護レベルより低い保護レベルで動作しているタスク(タスク部)からシステムコールを発行した場合に、E_OACV エラーとする。

拡張SVCの呼出は制限されない。

例えば、保護レベル1より低い保護レベルからのシステムコールの呼出を禁止した場合、保護レベル2,3で実行しているタスクからはシステムコールは発行できなくなる。つまり、保護レベル2,3で動作しているタスクは、拡張SVCしか発行できないということになり、サブシステムの機能のみを使ってプログラムすることになる。

これは、μT-KernelをT-Kernel Extensionと組み合わせる場合、T-Kernel Extensionの仕様に基づくタスクからμT-Kernelの機能を直接操作させないために使用する。μT-Kernelをマイクロカーネルとして使用するための機能である。

システムコール呼出制限をする保護レベルは、システム構成情報管理機能により設定する。システム構成情報管理機能については、システム構成情報管理機能μT-Kernel/SMの機能を参照のこと。

パラメータパケット形式の変更

システムコールへ渡すパラメータのいくつかは、パケット形式になっている。このパケット形式のパラメータには、システムコールへ情報を渡す入力パラメータとなるもの(T_CTSKなど)とシステムコールから情報を返される出力パラメータとなるもの(T_RTSKなど)がある。

これらパケット形式のパラメータには、実装独自の情報を追加することができる。ただし、標準仕様で定義されている情報の後ろに追加しなければならない。パラメータの削除については、サービスプロファイルで無効に指定されたものに限って許容され、それ以外のパラメータを削除することは許容されない。なお、標準仕様で定義されているデータの型および順序を変更してはならない。

システムコールへの入力パラメータとなるパケット(T_CTSKなど)では、実装独自で追加された情報が未初期化(メモリの内容が不定)のまま、システムコールを呼び出した場合でも正常に動作するようにしなければならない。

通常は、追加した情報に有効な値が入っていることを示すフラグを標準仕様に含まれている属性フラグの実装独自領域に定義する。そのフラグがセットされている(1)場合にのみ追加した情報を使用し、セットされていない(0)場合にはその追加情報は未初期化(メモリの内容が不定)であるとして、デフォルト値を適用する。

これは、標準仕様の範囲内で作成されたプログラムを、再コンパイルのみで実装独自の機能拡張を行われたOS上で動作させるための規定である。

注意T-Kernel 2.0との差異
 

サービスプロファイルで無効に指定されたパラメータに限り、パケット中のパラメータの削除を認める変更を行った。

注意μT-Kernel 1.0との差異
 

サービスプロファイルで無効に指定されたパラメータに限り、パケット中のパラメータの削除を認める変更を行った。

注意移植ガイドライン
 

サービスプロファイルで無効に指定されたパラメータを削除することが認められたため、パラメータパケットの初期化の際には注意が必要である。例えば、T_CTSK構造体に対して以下のような初期化を行うことは移植性の観点から推奨されない。

T_CTSK  ctsk = {
        NULL,
        TA_HLNG|TA_RNG0|TA_USERBUF,
        task,
        10,
        2048,
        "",
        buf
};

代わりに、ISO/IEC 9899:1999で規定された構文を用いて、以下のように初期化を行うことが推奨される。

T_CTSK  ctsk = {
        .exinf   = NULL,
        .tskatr  = TA_HLNG|TA_RNG0|TA_USERBUF,
        .task    = task,
        .itskpri = 10,
        .stksz   = 2048,
        .bufptr  = buf
};

機能コード

機能コードは、システムコールを識別するために、各システムコールに割り付けられる番号である。

システムコールの機能コードは特に定めない。すべて実装定義とする。

拡張SVCの機能コードについては、tk_def_ssy を参照。

エラーコード

システムコールの戻値は原則として符号付きの整数で、エラーが発生した場合には負の値のエラーコード、処理を正常に終了した場合は E_OK(=0)または正の値とする。正常終了した場合の戻値の意味はシステムコール毎に規定する。この原則の例外として、呼び出されるとリターンすることのないシステムコールがある。リターンすることのないシステムコールは、C言語インタフェースでは戻値を持たないもの(すなわちvoid型の関数)として宣言する。

エラーコードは、メインエラーコードとサブエラーコードで構成される。エラーコードの下位16ビットがサブエラーコード、残りの上位ビットがメインエラーコードとなる。メインエラーコードは、検出の必要性や発生状況などにより、エラークラスに分類される。

#define MERCD(er)       ( (ER)(er) >> 16 )    /* メインエラーコード */
#define SERCD(er)       ( (H)(er) )           /* サブエラーコード */
#define ERCD(mer, ser)  ( (ER)(mer) << 16 | (ER)(UH)(ser) )

ただし、ER型が16ビットの環境ではサブエラーコードを含めず、メインエラーコードをそのままエラーコードとしても良い。この場合、SERCDマクロを定義してはいけない。

#define MERCD(er)       ( (ER)(er) )    /* メインエラーコード */
#define ERCD(mer, ser)  ( (ER)(mer) )

注意関連するサービスプロファイル
 

以下のサービスプロファイルが有効に設定されている場合に限り、エラーコードにサブエラーコードが含まれ、SERCDマクロがサポートされる。

TK_SUPPORT_SERCD サブエラーコードをサポート

タイムアウト

待ち状態に入る可能性のあるシステムコールには、タイムアウトの機能を持たせる。タイムアウトは、指定された時間が経過しても処理が完了しない場合に、処理をキャンセルしてシステムコールからリターンするものである(この時、システムコールは E_TMOUT エラーを返す)。

そのため、「システムコールがエラーコードを返した場合には、システムコールを呼び出したことによる副作用はない」という原則より、タイムアウトした場合には、システムコールを呼び出したことで、システムの状態は変化していないのが原則である。ただし、システムコールの機能上、処理のキャンセル時に元の状態に戻せない場合は例外とし、システムコールの説明でその旨を明示する。

タイムアウト時間を0に設定すると、システムコールの中で待ち状態に入るべき状況になっても、待ち状態には入らない。そのため、タイムアウト時間を0としたシステムコール呼出では、待ち状態に入る可能性がない。タイムアウト時間を0としたシステムコール呼出を、ポーリングと呼ぶ。すなわち、ポーリングを行うシステムコールでは、待ち状態に入る可能性がない。

各システムコールの説明では、タイムアウトがない(言い換えると、永久待ちの)場合の振舞いを説明するのを原則とする。システムコールの説明で「待ち状態に入る」ないしは「待ち状態に移行させる」と記述されている場合でも、タイムアウト時間を指定した場合には、指定時間経過後に待ち状態が解除され、メインエラーコードを E_TMOUT としてシステムコールからリターンする。また、ポーリングの場合には、待ち状態に入らずにメインエラーコードを E_TMOUT としてシステムコールからリターンする。

タイムアウト指定(TMO型およびTMO_U型)は、正の値でタイムアウト時間、TMO_POL(=0)でポーリング、TMO_FEVR(=-1)で永久待ちを指定する。タイムアウト時間が指定された場合、タイムアウトの処理は、システムコールが呼び出されてから、指定された以上の時間が経過した後に行うことを保証しなければならない。

注意補足事項
 

ポーリングを行うシステムコールでは待ち状態に入らないため、それを呼び出したタスクの優先順位は変化しない。

一般的な実装においては、タイムアウト時間に1が指定されると、システムコールが呼び出されてから2回めのタイマ割込み(「タイムティック」と呼ぶ場合がある)でタイムアウト処理を行う。タイムアウト時間に0を指定することはできないため(0は TMO_POL に割り付けられている)、このような実装では、システムコールが呼び出された後の最初のタイマ割込みでタイムアウトすることはない。

相対時間とシステム時刻

イベントの発生する時刻を、システムコールを呼び出した時刻などからの相対値で指定する場合には、相対時間(RELTIM型またはRELTIM_U型)を用いる。相対時間を用いてイベントの発生時刻が指定された場合、イベントの処理は、基準となる時刻から指定された以上の時間が経過した後に行うことを保証しなければならない。イベントの発生間隔など、イベントの発生する時刻以外を指定する場合にも、相対時間(RELTIM型またはRELTIM_U型)を用いる。その場合、指定された相対時間の解釈方法は、それぞれの場合毎に定める。時刻を絶対値で指定する場合には、システム時刻(SYSTIM型またはSYSTIM_U型)を用いる。μT-Kernelには現在のシステム時刻を設定する機能が用意されているが、この機能を用いてシステム時刻を変更した場合にも、相対時間を用いて指定されたイベントが発生する実世界の時刻(これを実時刻と呼ぶ)は変化しない。言い換えると、相対時間を用いて指定されたイベントが発生するシステム時刻は変化することになる。

SYSTIM システム時刻

基準時間1ミリ秒、64ビットの符号付整数

typedef struct systim {
        W       hi;             /* 上位32ビット */
        UW      lo;             /* 下位32ビット */
} SYSTIM;
SYSTIM_U システム時刻

基準時間1マイクロ秒、64ビットの符号付整数

typedef D       SYSTIM_U;       /* 64ビット */
RELTIM 相対時間

基準時間1ミリ秒、32ビットの符号なし整数(UW)

typedef UW      RELTIM;
RELTIM_U 相対時間

基準時間1マイクロ秒、64ビットの符号なし整数(UD)

typedef UD      RELTIM_U;       /* 64ビットでマイクロ秒単位の相対時間 */
TMO タイムアウト時間

基準時間1ミリ秒、32ビットの符号付整数(W)

typedef W       TMO;

TMO_FEVR=(-1)で永久待ちを指定できる。

TMO_U タイムアウト時間

基準時間1マイクロ秒、64ビットの符号付整数(D)

typedef D       TMO_U;          /* 64ビットでマイクロ秒単位のタイムアウト */

TMO_FEVR=(-1)で永久待ちを指定できる。

注意関連するサービスプロファイル
 

マイクロ秒単位の時間および時刻に関連する型 TMO_U, RELTIM_U, SYSTIM_U は、以下のサービスプロファイルが有効に設定されている場合に限り利用可能であることが保証される。

TK_SUPPORT_USEC マイクロ秒命令をサポート

注意補足事項
 

RELTIM, RELTIM_U, TMO, TMO_Uで指定された時間は、指定された時間以上経過した後にタイムアウト等が起こることを保証しなければならない。例えば、タイマ割込み間隔が1ミリ秒で、タイムアウト時間として1ミリ秒が指定された場合、システムコール呼出後の2回目のタイマ割込みでタイムアウトする。(1回目のタイマ割込みでは1ミリ秒未満である。)