OSDN Git Service

Sメーター周りを修正
[trx-305dsp/dsp.git] / trx305 / kernel / doc / c++.txt
1
2         = TOPPERS/JSPカーネル ユーザズマニュアル =
3                     (C++バインディング)
4
5         (Release 1.4.1 対応,最終更新: 16-Sep-2004)
6
7 ------------------------------------------------------------------------
8  TOPPERS/JSP Kernel
9      Toyohashi Open Platform for Embedded Real-Time Systems/
10      Just Standard Profile Kernel
11
12  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
13                              Toyohashi Univ. of Technology, JAPAN
14  Copyright (C) 2003-2004 by Takagi Nobuhisa
15
16  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
17  によって公表されている GNU General Public License の Version 2 に記
18  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
19  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
20  利用と呼ぶ)することを無償で許諾する.
21  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
22      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
23      スコード中に含まれていること.
24  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
25      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
26      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
27      の無保証規定を掲載すること.
28  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
29      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
30      と.
31    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
32        作権表示,この利用条件および下記の無保証規定を掲載すること.
33    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
34        報告すること.
35  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
36      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
37
38  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
39  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
40  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
41  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
42 ------------------------------------------------------------------------
43
44 1.C++バインディングの概要
45
46 1.1 目的
47
48 TOPPERS/JSPカーネルは、本来C言語APIを提供するものであり、そのままでは
49 C++を用いたアプリケーション開発を行う上で支障がある。
50 C++バインディングは、TOPPERS/JSPカーネルが提供するサービスコールをC++
51 から呼出すことを可能にし、かつTOPPERS/JSPカーネル上で標準C++の機能を
52 利用できるようにするものである。
53
54 1.2 開発環境と実行環境
55
56 C++バインディングでは、GCC等のGNU開発環境を使用する。なお、Windows上
57 のシミュレーション環境(Visual C++)でC++を使用する際は、C++バインデ
58 ィングの機能を必要としない。
59
60 現在、C++バインディングがサポートする実行環境は、MS7727CP01(SH3)およ
61 びAKI-H8/3069Fである。他の実行環境で使用するには、ターゲット依存部の
62 Makefile.configおよびリンカスクリプトの修正が必要となる。
63 また、Linux上のシミュレーション環境では使用することができない。
64
65 1.3 C++バインディングの機能の概要
66
67 標準C++の機能のうち、実行環境に依存する部分について、TOPPERS/JSPカー
68 ネルに対応させている。具体的には、非ローカルオブジェクトの初期化処理、
69 終了処理、グローバルなnew演算子とdelete演算子、例外処理、およびフリー
70 スタンディング環境における標準ライブラリ関数である。
71
72 GCC自体が未サポートの機能(export、ユニバーサル文字名等)を補完するも
73 のではない。
74
75 1.4 C++バインディングの使用方法
76
77 TOPPERS/JSPカーネルでC++バインディングを使用するには、コンフィギュレ
78 ーションファイル(.cfg)から、jsp/systask/cxxrt.cfgをインクルードする
79 だけでよい。(静的APIのINCLUDEではなく、プロプロセッサ指令の#include
80 を使用すること)
81
82 TOPPERS/JSPカーネルのconfigureを使用する場合、C++を使うには"-l c++"
83 オプションを付加する必要がある。
84
85
86 2.C++バインディングの機能
87
88 2.1 非ローカルオブジェクトの初期化処理
89
90 関数の外部で宣言されたオブジェクト(特定の名前空間やクラスの静的デー
91 タメンバを含む)のコンストラクタを、起動時に呼出す機能を提供する。
92
93 非ローカルオブジェクトのコンストラクタは、kernel_start関数の呼出しよ
94 り前に実行され、syslogの機能を使用することはできない。
95 また、コンストラクタの内部では、vsns_iniを除くサービスコールを呼出す
96 ことはできない。
97
98 関数の内部で宣言されたオブジェクトは、起動時ではなく、宣言された箇所
99 に最初に実行パスが差し掛かったときにコンストラクタが呼出されるため、
100 起動時の初期化処理には含まれない。
101 そうしたコンストラクタの呼出しはマルチタスクに対応しないため、ユーザ
102 は必要に応じて排他制御を独自に行う必要がある。
103
104 2.2 終了処理
105
106 静的なオブジェクト(関数内で宣言されたものを含む)のデストラクタは、
107 std::exit関数の中から呼出される。明示的にstd::exit関数を呼出さない限
108 り、全タスクが終了したとしてもデストラクタが呼出されることはない。
109 なお、kernel_exit関数を呼出した場合も、std::exit関数を呼出した場合と
110 同様に、静的なオブジェクトのデストラクタは呼出される。
111
112 終了時の動作順序は、静的APIのVATT_TERで登録した終了処理ルーチンが呼出
113 された後、std::atexit関数で登録した終了時関数が呼出され、最後にデスト
114 ラクタが呼出される。
115 デフォルトの標準ストリーム(stdin, stdout, stderr)をサポートする場合、
116 それらのクローズ処理はデストラクタの呼出し後に行わなければならない。
117 (ユーザの手でカスタマイズする必要がある)
118
119 2.3 グローバルなnew演算子とdelete演算子
120
121 TOPPERS/JSPカーネルのマルチタスク環境および非マルチタスク環境(初期化
122 または終了処理時)で動作するnewおよびdelete演算子を提供する。
123 GCCはグローバルなnewおよびdelete演算子をstd::mallocおよびstd:free関数
124 を用いて実装しているため、NEWLIBのmallocおよびfree関数に排他制御を追
125 加することで実現している。
126
127 C++バインディングは、C++のフリースタンディング環境を対象としているが、
128 上記の理由により、本来フリースタンディング環境ではサポートされない、
129 std::mallocおよびstd::free関数も結果的にサポートしている。
130 おそらくはstd::callocおよびstd::realloc関数も動作すると思われるが、検
131 証は行っていない。
132
133 標準C++のグローバルなnewおよびdelete演算子には、例外をスローすること
134 がない、const std::nothrow_t&を引数にとる配置構文型のものもあるが、通
135 常のもの同様に使用することができる。
136
137 2.4 例外処理
138
139 C++の言語機能である例外処理機能(try、catchおよびthrow)を提供する。
140 例外処理はコンパイラの実装に密接に絡むため、コンパイラ自体にパッチが
141 必要になる。
142
143 例外処理は、tryおよびcatchの位置と、throwからcatchまでの間に存在する
144 ローカルオブジェクトのデストラクタを管理する必要がある。したがって、
145 コンパイラにとって未知の方法でコンテキストが切り替わった場合には、例
146 外処理用の管理情報も切り替える必要が生じる。
147 C++バインディングは、マルチタスク環境および非マルチタスク環境(初期化
148 または終了処理時)で、コンテキストに応じて管理情報を切り替える機能や
149 同期機能を実現している。
150
151 GCCでは、コンパイル時に-fno-exceptionsオプションを指定することで、例
152 外処理を無効にすることができるが、これはオプションを指定した翻訳単位
153 に対してのみ通用することであり、ライブラリ等は、通常通り、例外処理が
154 使える場合と同様に振舞うことになる。したがって、new、dynamic_cast、
155 あるいはtypeid演算子が失敗した場合等には、予期せぬ誤動作につながる危
156 険性があるため、必ずしも推奨しない。
157
158 2.5 標準ライブラリ関数
159
160 フリースタンディング環境のC++では、終了処理に関する標準ライブラリ関数
161 として、std::abort、std::atexit、およびstd::exit関数がサポートされる。
162 C++バインディングでも、これら3種類の関数を提供している。
163
164 (1) std::abort
165
166 std::abort関数は、静的APIのVATT_TERで登録された終了処理ルーチンや、
167 std::atexit関数で登録された終了時関数、オブジェクトのデストラクタを呼
168 出すことなく、システムを異常終了する。
169 システムの終了処理は、マルチタスク動作中はターゲット依存部で定義され
170 るkernel_abort関数に従い、非マルチタスク動作中(初期化または終了処理時)
171 はNEWLIBの_exit関数に従う。
172
173 C++バインディングでは、関数へのポインタvoid (*_atabort)(void)が0以外
174 に定義されている場合、実際の終了処理より前にそれを呼出すようになって
175 いる。
176 ホスト環境のstd::abortは、実際の終了処理の前にstd::raise(SIGABRT);を
177 呼出すが、_atabortを適切に設定することで同様の機能をエミュレートする
178 ことができる。
179
180 (2) std::atexit
181
182 std::atexit関数は、std::exitまたはkernel_exit関数から呼出される終了時
183 関数を登録する。std::atexit関数で登録した関数は、std::abort関数で終了
184 した場合や、vsns_iniがTRUEを返す期間にstd::exit関数を用いた場合には、
185 呼出されることがない。
186
187 静的なオブジェクトのデストラクタは、実際にはstd::atexit関数を用いるこ
188 とで実現している。ただし、デストラクタの呼出しは、std::atexit関数で登
189 録されたその他のいかなる終了時関数よりも後に呼出される。
190
191 std::atexit関数で登録できる終了時関数は、(デストラクタの登録を除いて)
192 32個までである。
193
194 (3) std::exit
195
196 std::exit関数は、C++の標準的な終了処理を行う。詳細な動作は、2.2 終了
197 処理を参照のこと。
198
199 std::exit関数を用いて終了した場合、ローカルオブジェクトのデストラクタ
200 が呼出されることはない。
201
202
203 3.C++実行環境としてのTOPPERS/JSPカーネル
204
205 3.1 BOOL型
206
207 標準C++には、論理型であるbool型と、論理値であるtrueおよびfalseが存在
208 する。しかし、TOPPERS/JSPカーネルがC言語で実装されているため、言語間
209 の互換性をとる意味でもBOOL型にはint型を使用する必要がある。
210 カーネルのコンパイルにC99を用いた場合でも、_Bool型とbool型の間には、
211 厳密な互換性があるとは言いがたいため、やはりint型を使用した方が無難で
212 ある。
213
214 3.2 タスクからの例外リーク
215
216 タスクのエントリ関数からキャッチされない例外がリークした場合の動作は
217 未定義である。
218
219 3.3 ATT_INIとVATT_TER
220
221 静的APIのATT_INIおよびVATT_TERで登録された関数から例外がリークした場
222 合の動作は未定義である。
223
224 3.4 非タスクコンテキストとタスク例外処理ルーチン
225
226 非タスクコンテキストとタスク例外処理ルーチンでは、例外処理、newおよび
227 delete演算子を使用することができない。参照型に対するdynamic_castや、
228 仮想関数を持つクラスへの参照やポインタに対するtypeidも、例外が発生す
229 る可能性があるため、使用することができない。また、標準ライブラリ関数
230 を呼出すこともできない。
231
232 なお、タスク例外許可状態で自タスクに対するras_texによって呼出されたタ
233 スク例外処理ルーチンに限り、上記の制約は受けない。ただし、タスク例外
234 処理ルーチンから例外をリークした場合の動作は未定義である。
235
236 3.5 サービスコールの例外指定
237
238 TOPPERS/JSPカーネルが提供する全サービスコールは例外をスローすることが
239 ないため、例外指定throw()が付加される。
240 これにより、例外処理のためのテーブルが生成されることを最小限に抑えら
241 れる場合があり、主として空間効率の向上が期待できる。
242
243
244 4.開発環境の構築
245
246 C++開発環境の構築は、基本的には「GNU開発環境構築マニュアル」の内容に
247 従うが、一部異なる点があるので、相違点を中心に解説する。
248 なお、動作確認には、ホスト環境としてはCygwin 1.3.22を使用した。
249
250 4.1 必要なソフトウェア
251
252 C++開発環境を構築するには、GCC-COREおよびG++、またはGCCが必要になる。
253 また、NEWLIBは必須である。
254
255     GNU開発環境
256        BINUTILS(アセンブラ,リンカなど)
257        GCC(C/C++コンパイラ)
258        GDB(デバッガ)
259     NEWLIB(標準Cライブラリ)
260     Perl(動作確認は 5.8.0)
261     GNU Make(動作確認は 3.80)
262     GNU sed(動作確認は 4.0.7)
263     patch(動作確認は 2.5.8)
264
265 4.2 BINUTILSのインストール
266
267 BINUTILSは、GCCのインストールに必要なため,GCCに先だってインストール
268 する。BINUTILSのインストール手順は次の通り。
269
270     % mkdir <BINUTILS-OBJDIR>
271     % cd <BINUTILS-OBJDIR>
272     % <BINUTILS-SRCDIR>/configure --target=<TARGET> --prefix=<PREFIX>\
273       --disable-nls
274     % make
275     % make install
276
277 4.3 GCCへのパッチ
278
279 Cygwin上でGCC 3.2.3をmakeする場合に一部障害が発生するため、次のパッチ
280 が必要となる。(SH版のみ。GCC 3.3.x以降では不要)
281
282     % cp gcc-3.2.3_fixinc_gnu-regex.patch <GCC-SRCDIR>
283     % cd <GCC-SRCDIR>
284     % patch -p1 < gcc-3.2.3_fixinc_gnu-regex.patch
285
286 以下の手順に従って、GCCをTOPPERS/JSPカーネルに対応させるためのパッチ
287 をあてる。
288
289     % cp gcc-3.2.3_gthr-toppers-1.patch <GCC-SRCDIR>
290     % cd <GCC-SRCDIR>
291     % patch -p1 < gcc-3.2.3_gthr-toppers-1.patch
292
293 4.4 GCCのインストール(1)
294
295 GCCのインストールにはNEWLIBが必要であるが、NEWLIBをインストールするに
296 はGCCが必要なため、若干の工夫が必要になる。
297
298     % mkdir <GCC-OBJDIR>
299     % cd <GCC-OBJDIR>
300     % <GCC-SRCDIR>/configure --target=<TARGET> --prefix=<PREFIX>\
301       --enable-languages=c,c++ --enable-threads=toppers\
302       --disable-nls
303     % make all-gcc
304     % make install-host
305
306 4.5 NEWLIBのインストール
307
308 次の手順に従って、NEWLIBをインストールする.
309
310     % mkdir <NEWLIB-OBJDIR>
311     % cd <NEWLIB-OBJDIR>
312     % <NEWLIB-SRCDIR>/configure --target=<TARGET> --prefix=<PREFIX>
313     % make
314     % make install
315
316 なお、CygwinのバージョンによってはNEWLIBのインストールに失敗する場合
317 がある。そのような場合は、Cygwinのバージョンを変更するか、NEWLIBをバ
318 イナリで入手すること。
319
320 4.6 GCCのインストール(2)
321
322 次の手順に従って、GCCの残り部分をインストールする.
323
324     % cd <GCC-OBJDIR>
325     % make
326     % make install
327
328
329 5.C++バインディングの実装詳細
330
331 5.1 ファイル構成
332
333 (1) cxxrt.cfg
334
335 cxxrt.cfgはC++対応ランタイムの内部で使用するオブジェクトを生成する。
336 C++の機能を使用する場合には、必ずコンフィギュレーションファイルから、
337 cxxrt.cfgをインクルードする必要がある。
338
339 (2) cxxrt.c
340
341 cxxrt.cはC++対応ランタイムの本体であり、例外処理等で必要となる関数や
342 変数の定義が行われる。
343
344 (3) newlibrt.c
345
346 newlibrt.cはNEWLIBの関数をTOPPERS/JSPカーネルに対応させるためのランタ
347 イムであり、C++を使用する場合には必須である。
348 このランタイムは、C++を使用しない場合でも、NEWLIBを使用する際には単独
349 で使用することができる。
350
351 5.2 同期機能
352
353 例外処理および標準C++ライブラリ内部で使用する同期機能を提供する関数群。
354 標準C++ライブラリはフリースタンディング環境ではサポートされないが、お
355 そらくlibstdc++の全機能を使用することができると思われる。(ただし、動
356 作は確認していない)
357
358 (1) int _toppers_cxxrt_lock(_toppers_cxxrt_sync_t *sync);
359
360 マルチタスク動作時では、ロックを掛け、クリティカルセクションを開始す
361 る。非マルチタスク動作時には何もしない。
362 成功時には0を返し、失敗時には負の値を返す。
363
364 この関数はネスティング可能である。
365
366 (2) int _toppers_cxxrt_trylock(_toppers_cxxrt_sync_t *sync);
367
368 _toppers_cxxrt_lock関数とほぼ同じであるが、既に他のタスクによってロック
369 中の場合でも待機状態には移行せず、単に呼出しに失敗する。
370 現在の実装では、_toppers_cxxrt_lock関数はディスパッチ禁止を用いて実現し
371 ているため、どちらも同じである。
372
373 (3) int _toppers_cxxrt_unlock(_toppers_cxxrt_sync_t *sync);
374
375 マルチタスク動作時では、ロックを解除し、クリティカルセクションを終了
376 する。非マルチタスク動作時には何もしない。
377 成功時には0を返し、失敗時には負の値を返す。
378
379 (4) int _toppers_cxxrt_once(_toppers_cxxrt_once_t *once,
380                           void (*func)(void));
381
382 指定した関数を、システム全体で一度だけ実行させる。funcを実行中に、異
383 なるタスクでも同じ関数を実行させようとした場合、funcの実行が完了する
384 まで待機状態に移行する。
385 成功時には0を返し、失敗時には負の値を返す。
386
387 5.3 タスクローカル記憶域機能
388
389 タスクごとに用意される、見かけ上静的な記憶域を提供する関数群であり、
390 例外処理で使用される。
391 タスクローカル記憶域として確保できるのは、デフォルトでは2個までである
392 が、_CXXRT_KEY_MAXマクロをユーザ定義することで、3個以上に拡張すること
393 ができる。
394
395 (1) int _toppers_cxxrt_key_create(struct _toppers_cxxrt_tls **key,
396                                 void (*dtor)(void*))
397
398 タスクローカル記憶域に確保する変数を新規作成する。
399 成功時には0を返し、*keyに変数を識別するためのキーが格納される。
400 dtorには、キーを削除する際に、タスクごとの各変数に対して実行すべき終
401 了処理を指定する。
402 失敗時には負の値を返す。
403
404 (2) int _toppers_cxxrt_key_delete(struct _toppers_cxxrt_tls *key);
405
406 _toppers_cxxrt_key_create関数で作成したキーを削除する。
407 成功時には0を返し、失敗時には負の値を返す。
408
409 5.4 NEWLIBのカスタマイズ
410
411 (1) void __malloc_lock(struct _reent *ptr);
412
413 mallocおよびfreeの排他制御を行う。他のタスクによってロックされている
414 状況で呼出された場合は待機状態に移行する。
415
416 (2) void __malloc_unlock(struct _reent *ptr);
417
418 __malloc_lock関数によるロックを解除する。
419
420 (3) void *_sbrk_r(struct _reent *ptr, ptrdiff_t nbytes);
421
422 プログラムのヒープ領域をnbyteだけ拡大する。成功時には、新しい領域の先
423 頭へのポインタを返す。失敗時は負の値を返し、errnoおよびptr->_errnoに
424 ENOMEMを設定する。
425
426 ヒープ領域には、外部識別子end(.bssセクションの終端)から、マルチタス
427 ク動作開始前のスタックポインタまでを使用する。
428 メモリマップ上、複数のメモリイメージが発生するターゲットでは、.bssセ
429 クションとスタックポインタの初期値を同一イメージ上に配置する必要があ
430 る。
431 ヒープ領域と起動時のスタック領域が連続していない場合、sys_config.h内
432 でHEAP_TOPマクロをヒープの終端アドレスに定義する必要がある。
433
434 本来であれば、_sbrk_r関数の原始関数にあたる_sbrk関数をカスタマイズす
435 べきであるが、ターゲットによっては、_write関数等と同一の翻訳単位にオ
436 リジナルの_sbrk関数が定義されており、リンク時に障害が発生する原因とな
437 るため、_sbrk_r関数をカスタマイズしている。
438
439 5.5 その他
440
441 (1) int main();
442
443 JSPカーネル上で動作するC/C++プログラムはフリースタンディング環境であ
444 るため、エントリ関数はmainではなくkernel_startである。しかし、NEWLIB
445 ではエントリポイントとしてmainが使用されることを期待しているため、
446 main関数がなければリンクエラーになる場合がある。
447 C++対応ランタイムでは、リンクを解決することのみを目的としてmain関数を
448 定義する。
449
450
451 6.ターゲット依存部の実装
452
453 現在、C++バインディングがサポートする実行環境は、MS7727CP01(SH3)およ
454 びAKI-H8/3069Fである。
455 また、GNU開発環境のターゲットとして、SH用にはsh-hitachi-elf、H8用には
456 h8300-hmsを使用している。
457
458 6.1 GNU開発環境に関するもの
459
460 GNU開発環境全般に関する要素として、以下のものがある。
461
462 (1) リンカスクリプトの対応
463
464 C++を用いる場合のリンカスクリプトには、.ctorおよび.dtor、すなわちグロ
465 ーバルなコンストラクタやデストラクタのポインタテーブルを形成するため
466 のセクション定義が必要である。
467 また、.eh_frameや.gcc_except_tableなどの例外処理用のセクション定義も
468 必要になる。
469
470 6.2 ELF形式に関連するもの
471
472 SHに限らず、ELF形式に依存する要素として、下記内容の対応が必要である。
473
474 (1) crti.o, crtbegin.o, crtend.o, crtn.oのリンク
475
476 グローバルなコンストラクタおよびデストラクタの呼出しや、例外処理関連
477 に必要なため、これらのファイルを正しい順序でリンクする必要がある。
478 リンクの順序は、
479
480 start.o crti.o crtbegin.o ユーザプログラム libkernel.a libstdc++.a
481 libm.a libc.a libgcc.a crtend.o crtn.o
482
483 である。
484 この指定には、ターゲット依存部のconfig/sh3/Makefile.configにおいて、
485
486 START_OBJS = \
487     start.o \
488     $(shell $(CC) $(COPTS) -print-file-name=crti.o | sed -e 's/\\/\//g') \
489     $(shell $(CC) $(COPTS) -print-file-name=crtbegin.o | sed -e 's/\\/\//g')
490 END_OBJS   = \
491     $(shell $(CC) $(COPTS) -print-file-name=crtend.o | sed -e 's/\\/\//g') \
492     $(shell $(CC) $(COPTS) -print-file-name=crtn.o | sed -e 's/\\/\//g')
493
494 のように定義されている。
495 なお、文字'\'を'/'に置換しているのは、MinGW + MSysの環境で使用できる
496 ようにするためである。
497 また、make時に誤ってcrti.oなどのコンパイルを試みようとすることを回避
498 する目的で、START_OBJSとEND_OBJS(およびstart.o)のmakeルールを特化し
499 ている。
500
501 (2) リンカスクリプトの対応
502
503 .initや.fini等のELF形式特有のセクション定義が必要である。
504
505 6.3 SHに特有のもの
506
507 ターゲットがSHの場合に特有な要素として、以下のものがある。
508
509 (1) _init関数および_fini関数
510
511 GCCの多くのターゲットでは、ELF形式の場合、初期化関数および終了時関数
512 として、_init関数と_fini関数を使用する。しかし、SHの場合にはinit関数
513 とfini関数(先頭の下線がない)を使用している。そのため、tool_defs.h
514 において、initおよびfiniにそれぞれマクロ置換している。
515
516
517 7.アプリケーション作成におけるヒント
518
519 7.1 静的なオブジェクト
520
521 静的なオブジェクトは普通に定義することができるが、以下の点に注意する
522 必要がある。
523
524 (1) カーネル非動作状態
525
526 グローバルなコンストラクタやデストラクタは、カーネル非動作状態で呼出
527 される。したがって、これらの関数内では、μITRONのサービスコールを呼出
528 すことは出来ない。唯一呼出すことが出来るサービスコールは、JSPカーネル
529 の独自拡張であるvsns_iniだけである。
530
531 クラスをグローバルでもローカルでも使えるようにするには、必要に応じて、
532 vsns_iniでカーネルの動作状態を判別し、状態に応じて処理を分ける必要が
533 ある。
534
535 (2) 関数内の静的オブジェクト
536
537 関数内で定義された静的オブジェクトのコンストラクタは、必ずしも起動時
538 に呼出される訳ではなく、実行パスが最初にそのオブジェクトの定義箇所に
539 差掛かった時点で呼出される。
540 したがって、コンストラクタがカーネル動作状態で呼出されるか、非動作状
541 態で呼出されるかは、そのオブジェクトが定義された関数が最初に呼出され
542 るタイミングに依存する。
543
544 一般的に、この問題を回避するにはDouble-Checked Lockingと呼ばれる手法
545 が用いられる。
546
547 class foo
548 {
549   // クラス定義
550 };
551
552 void func()
553 {
554   static foo* ptr = 0;
555   if (ptr == 0)
556   {
557     wai_sem(SEMID);
558     if (ptr == 0)
559     {
560       static foo x;
561       ptr = &x;
562     }
563     sig_sem(SEMID);
564   }
565   // 関数本体の処理
566 }
567
568 (3) システムログの使用
569
570 デストラクタでは、システムログを制限なく使用することができるが、グロ
571 ーバルなコンストラクタでは、デフォルトではシステムログを使用すること
572 ができない。
573
574 7.2 new演算子とdelete演算子
575
576 (1) 排他制御について
577
578 new演算子とdelete演算子は、処理速度を向上するため、フリーストアからの
579 メモリ割付け(std::malloc関数を用いて実装)はディスパッチ禁止状態で行
580 っている。
581 アプリケーションの要求によって、他の方法で排他制御を行う必要がある場
582 合には、systask/cxxrt.cの中の__malloc_lock関数と__malloc_unlock関数を
583 カスタマイズすればよい。
584
585 (2) 使用に関する制約
586
587 非タスクコンテキストやタスク例外処理ルーチンで呼出すことはできない。
588 カーネル非動作状態(vsns_ini関数がTRUEを返す期間)では、通常通り使用
589 することができる。
590
591 (3) オーバーロードについて
592
593 グローバルなnew演算子とdelete演算子は、実行効率はまずまずであるが、空
594 間効率は決して高いとはいえない。また、特定のクラスの最低生成数につい
595 ても評価しにくいため、厳密な動作保証を必要とするクラスに関しては、new
596 演算子とdelete演算子をオーバーロードすることを推奨する。
597
598 オーバーロードに際しては、固定長メモリプール等を用いることが出来る。
599 例えば、以下のようにクラスを定義することが出来る。
600
601 #include <t_services.h>
602 #include <cstddef>
603 #include "kernel_id.h"
604
605 class foo
606 {
607   static ID mpfid_;
608 public:
609   static void* operator new(std::size_t size) throw()
610   {
611     VP ptr;
612     get_mpf(mpfid_, &ptr);
613     assert(ptr != 0);
614     return ptr;
615   }
616   static void operator delete(void* ptr) throw()
617   {
618     rel_mpf(mpfid_, ptr);
619   }
620 };
621
622 static ID foo::mpfid_ = FOO_MPF;    // 固定長メモリプールのID番号
623
624 また、new演算子の配置構文を使用することで、タイムアウト指定等の機能を
625 追加することも可能である。
626
627 static void* operator new(std::size_t size, TMO tmout);
628 static void operator delete(void* ptr, TMO) throw();
629
630 なお、new演算子をオーバーロードする場合、必ず対応するdelete演算子も合
631 わせてオーバーロードしなければならない。
632 上記の場合、delete演算子でTMO型の引数を使用することはないが、newされ
633 たクラスのコンストラクタから例外がスローされた場合(new演算子そのもの
634 ではない)、対応するdelete演算子が必要になる。
635
636 7.3 例外処理
637
638 (1) 例外処理の内部処理
639
640 GCCでは、configure時に--enable-sjlj-exceptionsを指定した場合、例外処
641 理を実現するためにsetjmpおよびlongjmp関数を使用している。ターゲットに
642 よっては他の実現方法を選択することもできるが、動作確認は行っていない。
643
644 例外をT型のオブジェクトをthrowした場合、内部的には以下の順序で処理が
645 行われる。
646
647     1) std::malloc関数により、T型のオブジェクトを格納可能なメモリブロ
648        ックが割付けられる。
649        割付けに失敗した場合、緊急用の静的なバッファが当てられる。
650
651     2) T型のコピーコンストラクタが呼出され、throwされたオブジェクトの
652        コピーが、1)で割付けたブロックを用いて生成される。
653        コピーコンストラクタ内で例外がthrowされた場合はstd::terminate
654        関数が呼出された後、std::abort関数により異常終了する。
655
656     3) 例外処理フレームを検索し、catchされるまでの経路に存在するロー
657        カルなオブジェクトのデストラクタが呼出される。
658        ここで、デストラクタ内で例外がthrowされた場合はstd::terminate
659        関数が呼出された後、std::abort関数により異常終了する。
660
661     4) T型(またはその基底クラス)に対応するcatchブロックが見つかった
662        場合は、そのブロックに広域分岐する。catchブロックのパラメータ
663        が値渡しの場合、コピーコンストラクタによって新しいローカルなオ
664        ブジェクトが生成される。
665        対応するcatchブロックが見つからなかった場合や値渡しの際に例外
666        がthrowされた場合はstd::terminate関数が呼出された後、std::abort
667        関数により異常終了する。
668
669     5) catchブロック内の処理が実行される。
670
671     6) 上記2)で生成されたオブジェクトのデストラクタが呼出される。
672
673 (2) タスク再起動時の初期化
674
675 JSP 1.4では再起動時の初期化処理として_toppers_cxxrt_reset_specific関
676 数を呼び出す必要があったが、JSP 1.4.1では_toppers_cxxrt_reset_specific
677 関数の呼び出しは必要としない。
678 その代わり、タスクのエントリ関数から例外が動作した場合の動作は未定義
679 である。
680
681 (3) 効率の向上
682
683 configure時に--enable-sjlj-exceptionsを指定した場合、例外をthrowしな
684 い場合でも、若干の実行効率の低下が起こる。また、空間効率が著しく低下
685 する場合がある。
686 効率を少しでも改善するには、以下の方法が有効である。
687
688     1) できるだけインライン関数を使用する。例外処理に関するオーバーヘ
689        ッドの多くは、関数の呼出しに付随して発生する。
690
691     2) 決して例外を発生しない関数には、必ず例外指定throw()を付加する。
692        特に、C言語で実装された関数は、必ずthrow()を付けること。
693
694     3) 例外が発生するかもしれない関数には例外指定を付けない。
695        例外指定を付けるとフィルタリング処理が暗黙的に展開される。
696
697     4) 可能な限りデストラクタを定義しない。
698        関数内でデストラクタを持つローカルなオブジェクトを使わなければ、
699        例外をthrowするかもしれない関数を呼んでも、オーバーヘッドにな
700        らない場合がある。
701
702     5) 一時オブジェクトの生成を避ける
703        一時オブジェクト生成はそれ自体がオーバーヘッドであるだけでなく、
704        コンストラクタで例外が発生する機会を作り、またデストラクタが呼
705        び出される機会を増やす。
706
707 7.4 C言語との混在
708
709 C++からC言語で定義した関数を呼出す場合、extern "C"により"C"リンケージ
710 であることを明示的に指定しなければならない。
711
712 extern "C" int foo();
713
714 extern "C" {
715   void hoge();
716   void bar();
717 }
718
719 また、C言語から呼出す可能性のある関数をC++で定義する場合もextern "C"
720 を関数定義に付加する必要がある。
721
722 CとC++では互換性のない型もあるため、両方から使用する関数に、そうした
723 型を使用すべきではない。例えば、boolやクラス型などである。
724 特に、kernel_cfg.cはC言語であるため、タスク等の拡張情報にクラスのポイ
725 ンタを指定することはできない。
726
727 C関数からC++関数の呼出しは、原則として行うべきではない。内部で例外が
728 発生した場合、動作が保証できないのがその理由である。
729 通常の呼出しの他、コールバック関数を用いる場合も例外ではない。
730
731 C++関数からC関数を呼出す場合、C関数には例外指定throw()を付加すべきで
732 ある。こうすることで大幅に効率の向上が期待できる。
733
734 以上
735