
		TOPPERS/ASPカーネル
		設計メモ

		対応バージョン: Release 1.4.0
		最終更新: 2009年3月6日（作成中）

このドキュメントは，TOPPERS/ASPカーネルの設計メモである．作成中のもので
あり，網羅的ではない．

----------------------------------------------------------------------
 TOPPERS/ASP Kernel
     Toyohashi Open Platform for Embedded Real-Time Systems/
     Advanced Standard Profile Kernel

 Copyright (C) 2005-2009 by Embedded and Real-Time Systems Laboratory
             Graduate School of Information Science, Nagoya Univ., JAPAN
 
 上記著作権者は，以下の(1)〜(4)の条件を満たす場合に限り，本ソフトウェ
 ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
 変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
 (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
     権表示，この利用条件および下記の無保証規定が，そのままの形でソー
     スコード中に含まれていること．
 (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
     用できる形で再配布する場合には，再配布に伴うドキュメント（利用
     者マニュアルなど）に，上記の著作権表示，この利用条件および下記
     の無保証規定を掲載すること．
 (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
     用できない形で再配布する場合には，次のいずれかの条件を満たすこ
     と．
   (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
       作権表示，この利用条件および下記の無保証規定を掲載すること．
   (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
       報告すること．
 (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
     害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
     また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
     由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
     免責すること．
 
 本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
 に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
 アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
 の責任を負わない．
 
 @(#) $Id: design.txt 1546 2009-05-08 10:05:22Z ertl-hiro $
----------------------------------------------------------------------

○目次

・TOPPERS/ASPカーネルの実装設計方針
・CHECKマクロとgoto文の使用
・ext_tsk，ext_kerの返り値
・カーネルのデータ構造に対するvolatile宣言について
・型キャストに伴う警告メッセージ
・優先度データキュー機能
・性能評価用システム時刻参照機能
・call_texrtnからdispatchを呼び出す処理について
・タスク例外処理禁止フラグをenatexで実装している理由


○TOPPERS/ASPカーネルの実装設計方針

TOPPERS/ASPカーネル（以下，ASPカーネル）は，TOPPERS新世代カーネルの基盤
となるリアルタイムカーネルである．TOPPERS新世代カーネル仕様の設計方針と，
ASPカーネルの適用対象領域と設計方針については，TOPPERS新世代カーネル統
合仕様書に述べられている．

以下では，ASPカーネルの実装設計方針について述べるが，仕様設計方針とも関
連しており，明確に分離できない部分もある．

TOPPERS/ASPカーネルの実装設計を行うにあたり，次の方針を設定する．

(1) ソースコードの読みやすさ・改造しやすさを重視する

ソースコードが読みやすいことは，オープンソースソフトウェアの品質を向上
させる上で最も重要な特性である．ソースコードを理解している技術者が増え
ることで，問題を早期に発見することができ，サポート体制も充実させること
ができる．また，ソースコードが読みやすいことは，シンプルな設計がされて
いることも意味しており，信頼性向上にもつながる．さらに，技術者教育のた
めの教材とする観点からも，ソースコードが読みやすいことは重要となる．

改造しやすいことは，システム毎の要求にあわせたチューニングが行いやすい
ことを意味しており，擦り合わせ型の開発を支援する性質である．また，ASPカー
ネルを基盤としてTOPPERS新世代カーネルシリーズを開発していく上でも，改造
しやすいことは必須の条件である．

(2) 新しいターゲットシステムへのポーティングが容易な構造とする

組込みシステムには多様なハードウェアが用いられるため，それらに容易にポー
ティングできることは重要な性質である．そのために，実行性能に配慮しつつ
ハードウェアを抽象化し，ターゲットシステムに依存する部分と依存しない部
分を明確に分離する．また，開発環境（コンパイラなど）に依存する部分も明
確に分離する．

(3) 検証が容易な構造とする

信頼性を確保するために，検証が容易な構造とする．

具体的には，サービスコールのほとんど全体を割込み禁止で実行することとし，
サービスコールの処理途中で割込みを許可しない．この構造は，読みやすく改
造しやすいソースコードにするためにも有効である．これにより割込み応答性
が犠牲になるが，それによって問題を生じるアプリケーションは少数であり，
やむをえないものと考える．

また，条件コンパイル等によりコンフィギュレーションできる箇所を増やすと，
細かな最適化ができる一方で，検証すべき組合せが増えることから，コンフィ
ギュレーションできる箇所は必要最低限とする．

(4) 実行性能とメモリ使用量に配慮する

上記の方針を満たした上で，高い実行性能と小さいメモリ使用量を達成できる
ような実装を行う．実行性能を向上させる際には，平均性能の向上よりも，最
悪時性能の向上を重視する．

ソースコードの読みやすさを重視すると言っても，実行性能の悪いアルゴリズ
ムを安易に採用することはせず，高い実行性能を達成できるアルゴリズムを用
いる．ただし，新しいターゲットシステムへのポーティングを容易にするため
に大部分をC言語で実装しており，すべてをアセンブリ言語で記述した場合に比
べて実行性能が落ちるのはやむをえない．

メモリ使用量については，RAMの使用量を削減することに重点を置いた設計を行
うが，上記の方針および実行性能とのトレードオフを考慮し，ぎりぎりまでの
削減は行わない．

(5) スケーラビリティに配慮する

様々な規模のシステムに適用できるスケーラビリティをもった構造とする．特
に，小規模なシステムに適用する際に，使用しない機能をカーネルが持ってい
ることによるメモリ使用量の増加が最小限になるように配慮する．

具体的には，アプリケーションとカーネルを1つのロードモジュールにリンクす
る方法（1リンクモデル）を想定し，カーネルを関数単位でライブラリ化して，
使用する関数のみがリンクされる構造とする．これは一種のコンフィギュレー
ションであるが，この方法は，条件コンパイルによるコンフィギュレーション
とは違い，検証工数に与える影響が小さい．

また，固定的に使用するRAM領域を減らし，スタックに置ける情報はできる限り
スタック上に置く．


○CHECKマクロとgoto文の使用

ASPカーネルの実装においては，サービスコールの静的なエラーをチェックする
ために，名称が"CHECK_"で始まる一連のマクロ（これらを，CHECKマクロと総称
する）を用いている．

CHECKマクロの定義中にはgoto文を含んでいるが，MISRA-Cなどのコーディング
ルールではgoto文の使用を禁止しており，goto文を使うべきではないという意
見も多い．また，マクロの定義中にgoto文を使用することが問題であるという
意見もある．

ここでは，定義中にgoto文を含むCHECKマクロを用いる設計意図とそれを使用し
てよい条件，CHECKマクロの使用によりソフトウェアの信頼性に問題が生じるこ
とがないことを論証する．

なお，ASPカーネルのカーネル本体の実装では，CHECKマクロ以外にgoto文を用
いている箇所はない（一部のシステムサービスでは，これ以外の方法でgoto文
を用いている）．

●CHECKマクロの定義とその使用法

kernel/check.hには，25個のCHECKマクロが定義されているが，いずれも次のパ
ターンで定義されている．ここでXXXXXには，チェックしたいエラーの種類を表
す文字列が入る．

----------------------------------------
#define CHECK_XXXXX(<……>) {				\
	if (<エラー条件>) {						\
		ercd = <エラーコード>;				\
		goto error_exit;					\
	}										\
}
----------------------------------------

これらのCHECKマクロは，多くのサービスコールの処理関数中で，次のように使
用されている．

----------------------------------------
ER
<サービスコール名>(……)
{
	<ローカル変数の宣言>
	ER		ercd;

	LOG_XXX_YYY_ENTER(……);
	CHECK_XXXXX(……);
	CHECK_YYYYY(……);

	<サービスコール処理本体>

  error_exit:
	LOG_XXX_YYY_LEAVE(……);
	return(ercd);
}
----------------------------------------

この例では，CHECKマクロを2つ使用しているが，1つのみ使用している場合もあ
れば，3つ以上使用している場合もある．また，複数のCHECKマクロの間に，ロー
カル変数への代入文が入る場合もある（例えば，ter_tskの処理関数）．

●設計意図

CHECKマクロを使用する意図は，ほとんどのサービスコールで必要な静的エラー
のチェックコードをパターン化し，ソースコードの簡潔さを保つことで読みや
すさを向上させるとともに，記述ミスの可能性を減らすことである．

ちなみに，CHECKマクロを使用しない場合，上に示したサービスコールの処理関
数は，次のように記述することになる．

----------------------------------------
ER
<サービスコール名>(……)
{
	<ローカル変数の宣言>
	ER		ercd;

	LOG_XXX_YYY_ENTER(……);
	if (<XXXXXのエラー条件>) {
		ercd = <XXXXXのエラーコード>;
	}
	else {
		if (<YYYYYのエラー条件>) {
			ercd = <YYYYYのエラーコード>;
		}
		else {

			<サービスコール処理本体>

		}
	}
	LOG_XXX_YYY_LEAVE(……);
	return(ercd);
}
----------------------------------------

CHECKマクロの内容を知っているという前提の下では，元のソースコードの方が
読みやすいのは明らかである．

なお，このようなCHECKマクロの定義には，goto文の使用が不可避である．

●CHECKマクロを使用してよい条件

CHECKマクロは，次の条件を満たすように使用しなければならない．

(1) CHECKマクロは，サービスコール処理関数の先頭部分で，サービスコール入
　　口のログを出した後，クリティカルセクションに入る前までに，処理関数
　　のトップレベルで用いる．

(2) サービスコール処理関数の末尾部分で，クリティカルセクションを抜けた
　　後，サービスコール出口のログを出す前に，処理関数のトップレベルに，
　　error_exitラベルを置く．

●問題を生じることがない根拠

このような方法でgoto文を使用しても，ソフトウェアの信頼性に問題が生じる
ことがないことを主張するには，そもそも，MISRA-Cなどのコーディングルール
でgoto文の使用を禁止している根拠，言い換えると，goto文の使用によりソフ
トウェアの信頼性に問題が生じる可能性のある理由を明らかにする必要がある．

MISRA-Cのドキュメントでは，goto文の使用を禁止する根拠についてあまり明確
になっておらず，ここではその根拠を次のように推測する．

・処理の流れが複雑になり，プログラムの意図が読みにくくなる（いわゆる，
　スパゲッティプログラムになる）．

CHECKマクロの場合には，goto文をエラー発生時の強制脱出に用いており，ラベ
ルもerror_exitとするなど，プログラムの意図は明らかである．一方，このよ
うにgoto文をエラー時の強制脱出に用いる場合には，次の点もgoto文の使用を
禁止する根拠になりうる．

・goto文で強制脱出することにより，脱出時に行わなければならない後処理が
　飛ばされるおそれがある．

ただしこの点についても，CHECKマクロを上記の使用条件を満たして使う限りは，
脱出時に行わなければならない後処理はなく，CHECKマクロの使用によりソフト
ウェアの信頼性に問題が生じることはない．

問題を生じることがないことを論証するもう1つ方法は，コーディングルールに
合致しないプログラムが，コーディングルールに合致したプログラムと等価で
あることを示す方法である．

すでに「設計意図」の節で述べたように，CHECKマクロを使用したプログラムは，
goto文を使用しない等価なプログラムに書き換えることができるが，より一般
的には，次のことが言える．

else部を持たないif文のthen部の最後に，if文より下（前方）にあり，if文と
同じブロック内の同じ階層のラベルへ分岐するgoto文がある場合には，if文と
ラベルの間の文をelse部にすることにより，goto文を使わない等価なプログラ
ムに書き換えることができる．

例として，goto文を使った次のプログラムを考える．

----------------------------------------
	{
		/* if文の前の文 */
		if (....) {
			/* then部の文 */
			goto <ラベル>;
		}
		/* if文とラベルの間の文 */
	  <ラベル>:
		/* ラベルより後ろの文 */
	}
----------------------------------------

このプログラムは，goto文を使わない次のプログラムと等価である．

----------------------------------------
	{
		/* if文の前の文 */
		if (....) {
			/* then部の文 */
		}
		else {
			/* if文とラベルの間の文 */
		}
		/* ラベルより後ろの文 */
	}
----------------------------------------

この条件に合致するgoto文が複数ある場合には，下にあるgoto文から順に上記
の方法によって書き換えることで，goto文を使わない等価なプログラムに書き
換えることができる．

CHECKマクロの使用方法は，上記のgoto文の使用方法に合致するため，goto文を
使用しない等価なプログラムに書き換えることができる．よって，このCHECKマ
クロにより問題を生じることはない．


○ext_tsk，ext_kerの返り値

μITRON4.0仕様では，ext_tskはリターンすることのないサービスコールとなっ
ているが，TOPPERS新世代カーネルにおいては，このサービスコールの返り値を
ER型に変更し，非タスクコンテキストから呼ばれた場合には，E_CTXエラーを返
り値としてリターンすることとする．

この仕様に対するいくつかの対案を検討したが，以下の理由で採用しない．

・JSPカーネルのように，危険の可能性を検出しながら実行を継続する方法は，
　信頼性・安全性を重視するシステムでは望ましくない．信頼性・安全性を重
　視するシステムでは，危険の可能性を検出したら，早期にリカバリをすべき
　である．

・ASPカーネルの当初案のカーネルをダウンさせる方法は，アプリケーション側
　で回復する余地をなくすという意味で望ましくない．

・過去の互換性を保つために，型をvoidとしたまま，非タスクコンテキストか
　ら呼ばれた場合にはリターンするとする方法は，カーネルの仕様変更に気づ
　きにくくなるという意味で望ましくない．また，他のエラーコード（例えば
　E_NOSPT）を返す余地をなくしている．

・一種のCPU例外を呼び出すことにする方法は，カーネル仕様全体の整合性を考
　えて採用しなかった．ここで一種のCPU例外を導入するよりも，サービスコー
　ルがエラーを返した場合に呼ばれるOSEK/VDX OS仕様のエラーフックに相当す
　る機能を導入した方が有用性が高いと思われるためである．

この変更により，さらに，CPUロック状態やディスパッチ禁止状態でext_tskが
呼ばれた場合にもエラーリターンする方法が考えられるが，タスクのメインルー
チンからのリターンとext_tskが等価にならないため，採用しない．また，他の
処理単位からのリターン方法と整合させる意味もある（例えば，割込みハンド
ラからCPUロック状態のままリターンした場合の扱い）．

これにあわせて，ext_kerについても，返り値をER型に変更する．ASPカーネル
では，ext_kerがエラーを返すことはないが，HRPカーネルでは，E_OACVエラー
を返す場合がある．

なお，μITRON4.0仕様では，exd_tskもリターンすることのないサービスコール
となっているが，TOPPERS新世代カーネルでは，exd_tskはサポートしていない．


○カーネルのデータ構造に対するvolatile宣言について（クリティカルセクショ
ンの出入処理の実現に関する制約）

カーネル内のデータ構造は，並行実行される他の処理単位（割込みハンドラや
タスク）からもアクセスされる可能性があるため，volatile宣言が必要ではな
いかと考えられる．実際，クリティカルセクション内でカーネル変数を読むコー
ドが，コンパイラの最適化によりクリティカルセクション外に移動され，それ
が原因となった問題事例も報告されている．

カーネル内のすべてのデータ構造にvolatile宣言をつける方法は，安全ではあ
るが，最適化が抑止されるために，カーネルのサイズや性能には悪影響を与え
る．そこでASPカーネルでは，次の方法でvolatile宣言の必要性をなくすことと
する．

ASPカーネルにおいては，並行実行される他の処理単位から書き換えられる可能
性のあるデータ構造は，すべて，CPUロック状態または全割込みロック状態によ
るクリティカルセクション内でアクセスしている．クリティカルセクション内
でのデータ構造のアクセスが，コンパイラの最適化によりクリティカルセクショ
ン外に移動されないようにするには，コンパイラに対して，クリティカルセク
ションの出入処理により，メモリ上のデータ構造が書き変わる可能性があるこ
とを知らせればよい．

具体的には，クリティカルセクションの出入処理を関数によって実現すれば，
このような最適化を抑止することができる．しかし，ASPカーネルの多くのター
ゲット依存部において，クリティカルセクションの出入処理はマクロやインラ
イン関数により実装されており，上のような最適化を抑止できない．

そこで，クリティカルセクションの出入処理を実現する場合には，メモリ上の
データ構造が書き変わる可能性があることを，何らかの方法でコンパイラに知
らせなければならないという制約を設ける．GNU開発環境では，次のいずれかの
方法でこの制約を満たすことができる．

(a) クリティカルセクションの出入処理の全体または出入処理の本質的な部分
	（具体的には，割込み禁止／許可する処理）を（インラインでない）通常
	の関数により実現する．

(b) クリティカルセクションの出入処理の本質的な部分をインラインアセンブ
	ラによって実現している場合には，そのインラインアセンブラのclobber変
	数リストに"memory"を追加する．

(c) クリティカルセクションの出入処理の本質的な部分が，マクロやインライ
	ン関数呼出しで実現している場合には，クリティカルセクションに入る処
	理の最後と出る処理の先頭に，Asm("":::"memory")という記述を入れる．

なお，この制約が適用されるクリティカルセクションの出入処理は，以下のも
のである．

	SIL_LOC_INT
	SIL_UNL_INT
	t_lock_cpu, i_lock_cpu, x_lock_cpu
	t_unlock_cpu, i_unlock_cpu, x_unlock_cpu


○型キャストに伴う警告メッセージ

GCCで-O2オプションをつけてコンパイルした場合に，カーネルのソースコード
中の数箇所で，次の警告メッセージが出る（GCCのバージョンにもよる）．

warning: dereferencing type-punned pointer will break strict-aliasing rules

これは，GCCに-O2オプションをつけると，コンパイラがC言語のstrict
aliasing ruleを前提とするためである．コンパイラにstrict aliasing ruleを
適用させないためには，GCCのオプションに-fno-strict-aliasingを指定すれば
よい．これにより，警告メッセージは抑止されるが，strict aliasing ruleを
前提とした最適化は行われなくなる．

ASPカーネルに実装においては，strict aliasing ruleを前提とした最適化を行っ
てもよく，この警告メッセージを無視しても差し支えない．以下では，この警
告メッセージを無視しても差し支えない理由を述べる．

警告メッセージが出る例として，semaphore.c中の次の行について検討する．

	wobj_make_wait((WOBJCB *) p_semcb, (WINFO_WOBJ *) &winfo_sem);

この警告メッセージの原因は，直接的には，&winfo_semを(WINFO_WOBJ *)にキャ
ストしていることであるが，本質的な原因は，このコードがC言語のstrict
aliasing ruleに従わない代入文の原因になる可能性があり，このルールに依存
した最適化が誤った結果を引き起こす可能性があることである．

C言語のstrict aliasing ruleは，互換性のない異なる型を通して，オーバラッ
プするメモリ領域をアクセスする代入文を使用してはならないというものであ
る（使用した場合の振舞いは未定義になる）．このケースでは，(WINFO_SEM
*)型のポインタ経由と(WINFO_WOBJ *)型のポインタ経由で，オーバラップする
メモリ領域をアクセスする代入文を使用してはならないことになる．また，警
告メッセージの原因になってはいないが，(SEMCB *)型のポインタ経由と
(WOBJCB *)型のポインタ経由で，オーバラップするメモリ領域をアクセスする
代入文を使用してはならない．

ASPカーネルの実装においては，semaphore.c中の関数においては，(SEMCB *)型
および(WINFO_SEM *)型のポインタを使用しており，(WOBJCB *)型および
(WINFO_WOBJ *)型のポインタ経由でメモリ領域をアクセスすることはない．一
方，そこから呼び出されるwait.c中の関数においては，(WOBJCB *)型および
(WINFO_WOBJ *)型のポインタを使用しており，(SEMCB *)型および(WINFO_SEM
*)型のポインタ経由でメモリ領域をアクセスすることはない．

strict aliasing ruleに従わない代入文の問題点は，このルールに依存した最
適化が誤った結果を引き起こす可能性があることであるが，異なるコンパイル
単位をまたいで最適化が行われることはないため，これにより問題が起こるこ
とはないと言うことができる．

同じ議論は，他のソースファイル（eventflag.c，dataqueue.c，pridataq.c，
mailbox.c，mempfix.c）中の警告メッセージについても，そのまま当てはまる．


○優先度データキュー機能

●導入の経緯

●API仕様

CRE_PDQ(ID pdqid, { ATR pdqatr, uint_t pdqcnt, PRI maxdpri, void *pdqmb });
ER snd_pdq(ID pdqid, intptr_t data, PRI datapri);
ER psnd_pdq(ID pdqid, intptr_t data, PRI datapri);
ER ipsnd_pdq(ID pdqid, intptr_t data, PRI datapri);
ER tsnd_pdq(ID pdqid, intptr_t data, PRI datapri, TMO tmout);
ER rcv_pdq(ID pdqid, intptr_t *p_data, PRI *p_datapri);
ER prcv_pdq(ID pdqid, intptr_t *p_data, PRI *p_datapri);
ER trcv_pdq(ID pdqid, intptr_t *p_data, PRI *p_datapri, TMO tmout);
ER ini_pdq(ID pdqid);
ER ref_pdq(ID pdqid, T_RPDQ *pk_rpdq);

●実装

＜未完成＞


○性能評価用システム時刻参照機能

●必要性と使途

ASPカーネルには，ASPカーネル上で動作するタスクやASPカーネル自身の性能を
計測するために，システム時刻より精度の高い性能評価用システム時刻を読み
出す機能をサポートする．性能評価用システム時刻は，マイクロ秒単位で表現
されるが，実際の精度はターゲット依存である．

この機能を用いてあるプログラムの実行時間を計測するには，その実行直前と
実行直後に性能評価用システム時刻を読み出し，その差を求める．そのため，
性能評価用システム時刻は常に相対値を使用し，性能評価用システム時刻の絶
対値を使用することは想定していない．

●API仕様

性能評価用システム時刻参照機能では，次のデータ型を用いる．

	SYSUTM		性能評価用システム時刻（符号無し整数，単位はマイクロ秒，
				32ビット以上）

SYSUTM型は，ターゲット非依存部においてulong_t型（すなわち，unsigned
long型）に定義されており，そのサイズは，32ビット以上で，ターゲット定義
である．

性能評価用システム時刻がSYSUTM型で表現できる範囲を超えた（つまり，オー
バフローした）場合，性能評価用システム時刻は0に戻る．評価対象プログラム
の実行前後の性能評価用システム時刻の差を求める場合には，計測する時間が
SYSUTM型で表現できる範囲である限り，0に戻ることを特別に考慮する必要はな
い．

SYSUTM型が32ビットの場合，性能評価用システム時刻は約71分でオーバフロー
する．そのため，この機能を71分を越える時間の測定に使った場合の動作は保
証されない．

性能評価用システム時刻参照機能のためのサービスコールの仕様については，
「TOPPERS新世代カーネル統合仕様書」の「4.6.1 システム時刻管理」の節を参
照すること．

●実装

時刻をマイクロ秒単位で取得するために，周期的なタイムティックを供給する
タイマの現在値（タイマはカウントアップするものと仮定する）を読み出し，
それをマイクロ秒単位に換算した値に，現在のシステム時刻（ミリ秒単位で表
現される）を1000倍した値を加えたものを性能評価用システム時刻とする．現
在のシステム時刻を1000倍する際に，オーバフローが発生する可能性があるが，
無視してかまわない．

ただし，システム時刻の現在値とタイマの現在値を一貫した状態で読み出すの
は容易ではない．両方の値を順に読み出すと，読出しの間にタイマがオーバフ
ローして割込み要求が発生した場合に，片方はオーバフロー前の値，もう片方
はオーバフロー後の値を読んでしまい，誤った性能評価用システム時刻を取得
してしまう．

この問題を解決する方法はいくつか考えられるが，どの方法を採用するの決定
にあたり，次の要求事項を設定した．

(1) 多くのターゲットシステムで実現できること．

(2) サービスコールの実行時間が可能な限り一定となること．言い換えると，
    条件によってサービスコールの実行時間が大きく変動しないこと．

(3) サービスコール中の可能な限り同じタイミングの時刻を返すこと．言い換
    えると，条件によって時刻を読み取るタイミングが変動しないこと．

(4) 調整する必要のあるパラメータを最小限とすること．

これらの要求事項を満たす方法として，次の方法を用いることにした．

まず，NMIを除くすべての割込みを禁止した状態で，システム時刻の現在値，タ
イマの現在値（1回目），タイマ割込み要求の有無，タイマの現在値（2回目）
を，この順で読み出す．割込みを禁止しているため，この間にシステム時刻の
現在値が変化することはなく，システム時刻の現在値を読み出す順番はどこで
もよい．また，タイマの現在値の2回目の読出しは，タイマ割込み要求があった
場合にのみ必要となるが，(2)の要求から，タイマ割込み要求の有無によらず読
み出すこととする．

これらの値を読み出した後，割込み禁止を解除し，次の処理を行う．まず，タ
イマ割込み要求がなかった場合には，システム時刻の現在値と，1回目に読んだ
タイマの現在値は一貫した値であることが保証できるため，これらの値から性
能評価用システム時刻の現在値を求める．

次にタイマ割込み要求があった場合には，1回目に読んだタイマの現在値が，タ
イマ割込み要求発生前の値（オーバフロー前の値）である場合と，発生後の値
（オーバフロー後の値）である場合の両方の可能性が考えられる．このどちら
の場合であったかを，2回目に読んだタイマの現在値を使って，次のように決定
する．2回目の値は，タイマ割込み要求発生後の値（オーバフロー後の値）であ
ることが保証できるため，1回目の値が2回目の値よりも大きい場合には，その
間にオーバフローがあったものと推測できる．つまり，1回目の値はオーバフロー
前の値ということになり，システム時刻の現在値と一貫した値であるとして性
能評価用システム時刻の現在値を求める．逆に，1回目の値が2回目の値と同じ
かそれより小さい場合には，1回目の値はオーバフロー後の値であると推測でき
る．この場合には，次のタイムティックのシステム時刻を求め，その値と1回目
の値が一貫した値であるとして性能評価用システム時刻の現在値を求める．

ここで，タイマ割込み要求があった場合には，2回目に読んだタイマの現在値を
用いる方法が考えられるが，(3)の要求を満たさなくなるために採用しなかった．
また，JSPカーネルと同様の方法は，(4)の要求を満たさないために採用しなかっ
た．

上で「推測できる」としたのは，この推測が成り立たなくなるケースがあるた
めである．この推測が成り立たなくなるケースは，次の2つの場合に分けて分析
することができる．

(a) 1回目の値がオーバフロー後の値であるにもかかわらず，1回目の値が2回目
    の値よりも大きくなる場合

このようなケースは，タイマ割込みが要求されているにもかかわらずサービス
されない状態が長時間続くか，タイマの現在値を1回目に読んでから2回目に読
むまでの間に長い時間がかかった結果，その間に（再度）オーバフローが発生
した場合に起こる．つまり，タイマ割込みがサービスされない時間が，タイム
ティックの周期よりも長くなった場合である．このような場合には，システム
時刻の更新も正しく行われなくなる．

(b) 1回目の値がオーバフロー前の値であるにもかかわらず，1回目の値が2回目
    の値と同じかそれよりも小さくなる場合

このようなケースは，タイマの現在値を1回目に読んでから2回目に読むまでの
間に，タイマがほぼ1周分カウントアップした場合に起こる．この場合も，タイ
マ割込みが禁止されている時間が，タイムティックの周期よりも長かったこと
になり，システム時刻の更新が正しく行えなくなる．

いずれのケースも，タイマ割込みが長時間禁止されている，タイマ割込みより
も優先度の高い割込み処理が長時間続けて実行された，シミュレーション環境
においてシミュレータのプロセスが長時間スケジュールされなかったなどの理
由で，システム時刻の更新が正しく行えない状況に相当する．そこでこの状況
を，サービスコール使用上の注意事項に盛り込む．

実際のコードにおいては，システム時刻の現在値は変数に保持されていないた
め（上位桁はcurrent_timeに保持されているが，下位桁を保持する変数がな
い），次のタイムティックのシステム時刻を用いて計算している．そのため，
タイマの現在値がオーバフロー後の値であると判断した場合を除いては，タイ
ムティックの周期時間を，求めた性能評価用システム時刻から減算する．この
処理により，サービスコールの実行時間が変動することになるが，if文の内容
が（コンパイラの最適化を仮定すると）定数値の減算1回なので，変動はわずか
である．

このサービスコールは，任意の状態から呼び出すことができるため，SILの全割
込みロック機能を用いて，サービスコール内部のクリティカルセクションを実
現する．


○call_texrtnからdispatchを呼び出す処理について

dispatch_rから（ターゲットによってはcalltexを経由して）call_texrtnを呼
び出し，call_texrtnからdispatchを呼び出すため，この2つの関数は相互再帰
呼出しをしている．ここでは，この実装で支障のない理由を説明する．

call_texrtnからdispatchを呼び出すのは，ディスパッチが保留されていない状
態で呼び出されたタスク例外処理ルーチンが，その実行中にディスパッチ保留
状態に遷移し，さらにタスクディスパッチを必要とする処理を行い，ディスパッ
チ保留状態を解除しないままリターンした場合である．この場合，call_texrtn
の中でディスパッチ保留状態を解除した後に，dispatchを呼び出してタスクディ
スパッチを行う．つまり，call_texrtnからdispatchを呼び出す処理は，タスク
例外処理ルーチンの中でディスパッチ保留状態を解除すべきであったのを，解
除せずにリターンした場合を救済するためのものである．以下，この振舞いを
「救済ケース」と呼ぶ．

そこで，比較のために，タスク例外処理ルーチンの中で，正しくディスパッチ
保留状態を解除してからリターンした場合の振舞いを考える．この場合には，
ディスパッチ保留状態を解除するサービスコール（ena_dsp，chg_ipm）の中で，
dispatchが呼び出されてタスクディスパッチが起こる．以下，この振舞いを
「正常ケース」と呼ぶ．

正常ケースと救済ケースを比較すると，call_texrtn→タスク例外処理ルーチン
→サービスコール→dispatchの順でdispatchが呼び出されるか，call_texrtnか
ら直接dispatchが呼び出されるかの違いということになり，救済ケースの方が
スタックの使用量は少ない．つまり，正常ケースの動きを想定してスタック領
域が用意してあれば，救済ケースでも問題なく動作することになる．

ここで，正常ケースと救済ケースで，上記以外に違いがないことが重要である．
具体的には，call_texrtnの中で，タスク例外処理許可状態にする（p_runtsk
->enatexをtrueにする）前に，dispatchを呼び出すことが重要である．タスク
例外処理許可状態にした後にdispatchを呼び出すと，出口のdispatch_rで，再
びタスク例外処理ルーチンを実行してしまう可能性があり，救済ケースの方が
スタックの使用量が増えてしまう．


○タスク例外処理禁止フラグをenatexで実装している理由

タスク例外処理禁止フラグは，TCB中のenatexフィールド（タスク例外処理許可
状態であることを示す）の形で保持している．このフィールドをdistexとせず
enatexとしたのは，JSPカーネルにおいてタスクディスパッチ禁止フラグを
enadspの形で保持したのと整合させたためである．

ASPカーネルでは，enadspはdisdspに変更になったことから，enatexもdistexに
変更した方が良かったと思われる．

以上
