source: asp3_wo_tecs/trunk/doc/ovrhdr_memo.txt@ 302

Last change on this file since 302 was 302, checked in by ertl-honda, 7 years ago

TECSレスのASP3の開発のため以下のtrunkからコピー
http://dev.toppers.jp/svn/asp3/branches/WO_TECS-3.C.0

File size: 20.4 KB
Line 
1 TOPPERS Confidential
2 TOPPERSプロジェクト ディスカッションメモ
3 オーバランハンドラに関する設計メモ
4
5 作成者
6: 高田広章(名古屋大学)
7 最終更新: 2015年8月21日
8
9○メモの位置付け
10
11このドキュメントは,TOPPERS/ASP3カーネルのオーバランハンドラ機能拡張に
12関する設計メモである.
13
14○データ型と定数の定義
15
16プロセッサ時間を表現するデータ型PRCTIMの定義を,t_stddef.hに含める.
17
18----------------------------------------
19typedef uint32_t PRCTIM; /* プロセッサ時間 */
20----------------------------------------
21
22残りプロセッサ時間に指定できる最大値は,ターゲット依存部(target_kernel.h
23またはそこからインクルードされるファイル)で定義するものとするが,デフォ
24ルトの定義をkernel.hに含める.
25
26----------------------------------------
27#ifndef TMAX_OVRTIM
28#define TMAX_OVRTIM UINT32_MAX
29#endif /* TMAX_OVRTIM */
30----------------------------------------
31
32また,オーバランハンドラのデータ型OVRHDRの定義を,kernel.hに含める.
33
34----------------------------------------
35typedef void (*OVRHDR)(ID tskid, intptr_t exinf);
36----------------------------------------
37
38この他に,オーバランハンドラ機能のサービスコールの宣言と関連する定数の
39定義を,kernelに含める.
40
41○用いるハードウェア資源とサポートできない場合の措置
42
43オーバランハンドラを実現するために,システム時刻を進めるための高分解能
44タイマとは別のタイマ(以下,これをオーバランタイマと呼ぶ)を用いる.そ
45のため,ターゲットによっては,オーバランハンドラをサポートできない場合
46も考えられる.
47
48そこで,オーバランハンドラをサポートできる場合には,ターゲット依存部に
49おいて,TOPPERS_TARGET_SUPPORT_OVRHDRをマクロ定義するものとする.
50
51オーバランハンドラ機能拡張のkernel.hでは,TOPPERS_TARGET_SUPPORT_OVRHDR
52がマクロ定義されていれば,TOPPERS_SUPPORT_OVRHDRを定義する.
53
54----------------------------------------
55#ifdef TOPPERS_TARGET_SUPPORT_OVRHDR
56#define TOPPERS_SUPPORT_OVRHDR /* オーバランハンドラ機能拡張 */
57#endif /* TOPPERS_TARGET_SUPPORT_OVRHDR */
58----------------------------------------
59
60オーバランハンドラ機能は,TOPPERS_SUPPORT_OVRHDRが定義されている場合の
61み組み込む.これにより,オーバランハンドラ機能拡張を使用し,ターゲット
62依存部がオーバランハンドラをサポートしている場合のみ,オーバランハンド
63ラ機能が組み込まれることになる.
64
65○オーバランハンドラに関連するデータ構造
66
67オーバランハンドラを実装
68するために,TCBに,オーバランハンドラが動作状æ…
69‹
70であることを示すフィールドstaovrと,残りプロセッサ時間を表すフィールド
71leftotmを追加する(task.h).
72
73----------------------------------------
74typedef struct task_control_block {
75 ...
76 BIT_FIELD_BOOL staovr : 1; /* オーバランハンドラ動作状æ…
77‹ */
78 ...
79 PRCTIM leftotm; /* 残りプロセッサ時間 */
80 ...
81} TCB;
82----------------------------------------
83
84オーバランハンドラの動作状æ…
85‹ã¯ï¼Œã‚¿ã‚¹ã‚¯ã®ç™»éŒ²æ™‚とタスクが休止状æ…
86‹ã«é·ç§»
87する時に,動作していない状æ…
88‹ã«åˆæœŸåŒ–される[NGKI2587]ことから,
89make_dormantの中でstaovrをfalseに初期化する(task.c).
90
91----------------------------------------
92void
93make_dormant(TCB *p_tcb)
94{
95 ...
96 p_tcb->staovr = false;
97 ...
98}
99----------------------------------------
100
101オーバランハンドラに対しては,管理ブロックは必
102要なく,DEF_OVRで定義した
103情
104報を格納した初期化ブロックのみを用意する.初期化ブロックも,単一の要
105素で十分であり,é…
106åˆ—である必
107要はない(overrun.h).
108
109----------------------------------------
110typedef struct overrun_handler_initialization_block {
111 ATR ovratr; /* オーバランハンドラ属性 */
112 OVRHDR ovrhdr; /* オーバランハンドラの起動番地 */
113} OVRINIB;
114----------------------------------------
115extern const OVRINIB ovrinib;
116----------------------------------------
117
118オーバランタイマが動作中かを示すフラグとして,boot_t型の変数
119ovrtimer_flagを用意する(overrun.h,overrun.c).
120
121----------------------------------------
122extern boot_t ovrtimer_flag;
123----------------------------------------
124
125シングルプロセッサの場合には,オーバランタイマが動作中かは,次の方法で
126判別することができる.
127
128 タスクコンテキストでは,
129 (p_runtsk != NULL && p_runtsk->staovr)の時のみ動作している.
130 非タスクコンテキストでは,動作していない.
131
132そのため,このフラグを用いない実装
133も可能であるが,マルチプロセッサへの
134拡張性やターゲット依存性を下げるために,これを用いる実装
135としている(実
136際,Mac OS Xターゲット依存部では,これを活用している).
137
138ovrtimer_flagを用いることにしたことから,割込み/CPU例外出å…
139¥å£å‡¦ç†ã«ãŠ
140いて,p_runtskがNULLであるかどうかをチェックせずに,ovrtimer_stopを呼ぶ
141こととしている(ターゲット依存部 ポーティングガイド).
142
143○残りプロセッサ時間の保存/復帰処理の内
144容
145
146ディスパッチャおよび割込み処理/CPU例外処理の出å…
147¥å£ã§ï¼Œã‚¿ã‚¹ã‚¯ã®æ®‹ã‚Šãƒ—ロ
148セッサ時間を保存/復帰する必
149要がある.å…
150·ä½“的には,以下のような処理が必
151
152要である.
153
154(a) dispatchへのå…
155¥å£
156
157ovrtimer_flagがtrueであれば(または,p_runtsk->staovrがtrueであれば),
158オーバランタイマを停止させ,残りプロセッサ時間をp_runtsk->leftotmに格納
159する.残りプロセッサ時間がなくなっていた場合には,p_runtsk->leftotmに0
160を格納する.
161
162(b) dispatchからの出口
163
164p_runtsk->staovrがtrueであれば,残りプロセッサ時間をp_runtsk->leftotmと
165してオーバランタイマを動作開始する.
166
167(c) 割込み処理/CPU例外処理のå…
168¥å£
169
170タスクコンテキストで割込み/CPU例外が発生した場合に,ovrtimer_flagが
171trueであれば(または,p_runtskがNULLでなく,p_runtsk->staovrがtrueであ
172れば),オーバランタイマを停止させ,残りプロセッサ時間を
173p_runtsk->leftotmに格納する.残りプロセッサ時間がなくなっていた場合には,
174p_runtsk->leftotmに0を格納する.
175
176この処理は,カーネル管理の割込みをすべて禁止した状æ…
177‹ã§è¡Œã†å¿…
178要がある.
179割込み/CPU例外発生直後にすべての割込みが禁止されないプロセッサでは,割
180込みを禁止した後にこの処理を行う必
181要がある.
182
183(d) 割込み処理/CPU例外処理の出口
184
185タスクコンテキストに戻る場合に,p_runtskがNULLでなく,p_runtsk->staovr
186がtrueであれば,残りプロセッサ時間をp_runtsk->leftotmとしてオーバランタ
187イマを動作開始する.
188
189(e) タスクの終了時
190
191ovrtimer_flagがtrueであれば(または,p_runtsk->staovrがtrueであれば),
192オーバランタイマを停止させる.残りプロセッサ時間をp_runtsk->leftotmに格
193納する必
194要はない(タスクが終了すると,オーバランハンドラは停止するた
195め).
196
197(f) タスクの実行開始時
198
199p_runtsk->staovrがtrueであれば,残りプロセッサ時間をp_runtsk->leftotmと
200してオーバランタイマを動作開始する.
201
202○ターゲット依存部のインタフェース
203
204オーバランハンドラ機能のターゲット依存部では,オーバランハンドラ用のタ
205イマ(以下,オーバランタイマと呼ぶ)を操作するための機能を提供する.
206
207まず,次の定数をマクロ定義する.
208
209(1) TMAX_OVRTIM
210
211残りプロセッサ時間としてオーバランハンドラ用タイマに設定できる最大の値.
212単位はマイクロ秒とする.ターゲット依存部で定義しない場合には,kernel.h
213でUINT32_MAXに定義する.
214
215また,次の5つの関数を用意する.
216
217(1) void target_ovrtimer_initialize(intptr_t exinf)
218
219オーバランタイマの初期化処理を行う.タイマの動作開始は行わない.
220
221この関数は,target_timer.cfg中に記述する静的APIにより,初期化ルーチンと
222してカーネルに登録することを想定している.
223
224(2) void target_ovrtimer_terminate(intptr_t exinf)
225
226オーバランタイマの停止処理を行う.
227
228この関数は,target_timer.cfg中に記述する静的APIにより,終了処理ルーチン
229としてカーネルに登録することを想定している.
230
231(3) void target_ovrtimer_start(PRCTIM ovrtim)
232
233オーバランタイマを,ovrtimで指定した時間が経過したら割込みが発生するよ
234うに設定し,動作開始する.ovrtimが0の場合は,できる限り早くオーバランタ
235イマ割込みを発生させる.ovrtimの単位はマイクロ秒とする.
236
237(4) PRCTIM target_ovrtimer_stop(void)
238
239オーバランタイマを停止し,タイマの残り時間(割込み発生までの時間)を返
240す.残り時間がなくなっていた場合には,0を返す.また,オーバランタイマか
241らの割込み要求をクリアする(クリアしないとスプリアス割込みが発生するが,
242クリアすることは必
243須ではない).
244
245(5) PRCTIM target_ovrtimer_get_current(void)
246
247オーバランタイマの残り時間(割込み発生までの時間)を読み出す.残り時間
248がなくなっていた場合には,0を返す.オーバランタイマからの割込みはクリア
249しない.
250
251○残りプロセッサ時間の保存/復帰の実装
252(ターゲット非依存部)
253
254まず,(a)と(b)を実現する関数ovrtimer_stopとovrtimer_startをターゲット非
255依存部に設け,ターゲット依存部の該当箇所から呼び出すようにする.
256
257----------------------------------------
258void
259ovrtimer_stop(void)
260{
261 if (ovrtimer_flag) {
262 assert(p_rutsk != NULL && p_runtsk->staovr);
263 p_runtsk->leftotm = target_ovrtimer_stop();
264 ovrtimer_flag = false;
265 }
266}
267----------------------------------------
268void
269ovrtimer_start(void)
270{
271 if (p_runtsk->staovr) {
272 target_ovrtimer_start(p_runtsk->leftotm);
273 ovrtimer_flag = true;
274 }
275}
276----------------------------------------
277
278
279(c)は,(a)と同じ処理内
280容であるため,ovrtimer_stopを呼び出せばよい.(d)
281は,p_runtskがNULLでない場合に,ovrtime_startを呼び出すように実現すれば
282よい.
283
284(e)は,残りプロセッサ時間をp_runtsk->leftotmに格納する必
285要がない点で
286(a)と処理内
287容が異なるため,ext_tskとena_terに次の修正を加える
288(task_term.c).task_terminateの中で,TCB中のstaovrを初期化するため,
289それを呼ぶ前にオーバランタイマの停止処理をå…
290¥ã‚Œã‚‹å¿…
291要がある.
292
293----------------------------------------
294ER
295ext_tsk(void)
296{
297 ...
298#ifdef TOPPERS_SUPPORT_OVRHDR
299 if (p_runtsk->staovr) {
300 (void) target_ovrtimer_stop();
301 ovrtimer_flag = false;
302 }
303#endif /* TOPPERS_SUPPORT_OVRHDR */
304 (void) task_terminate(p_runtsk);
305 exit_and_dispatch();
306 ...
307}
308----------------------------------------
309ER
310ena_ter(void)
311{
312 ...
313#ifdef TOPPERS_SUPPORT_OVRHDR
314 if (p_runtsk->staovr) {
315 (void) target_ovrtimer_stop();
316 ovrtimer_flag = false;
317 }
318#endif /* TOPPERS_SUPPORT_OVRHDR */
319 (void) task_terminate(p_runtsk);
320 exit_and_dispatch();
321 ...
322}
323----------------------------------------
324
325(f)は(b)と同じ処理内
326容であるため,ovrtimer_startを呼び出せばよい.
327
328○残りプロセッサ時間の保存/復帰の実装
329(ターゲット依存部)
330
331(a) dispatchへのå…
332¥å£
333
334----------------------------------------
335void
336dispatch(void)
337{
338|#ifdef TOPPERS_SUPPORT_OVRHDR
339| ovrtimer_stop(); /* オーバランタイマの停止 */
340|#endif /* TOPPERS_SUPPORT_OVRHDR */
341 スクラッチレジスタを除くすべてのレジスタをスタックに保存する
342 ...
343}
344----------------------------------------
345
346(b) dispatchからの出口
347
348----------------------------------------
349void
350dispatch(void)
351{
352 ...
353
354 dispatch_r:
355 スクラッチレジスタを除くすべてのレジスタをスタックから復帰する
356|#ifdef TOPPERS_SUPPORT_OVRHDR
357| ovrtimer_start(); /* オーバランタイマの動作開始 */
358|#endif /* TOPPERS_SUPPORT_OVRHDR */
359 calltex(); … (*b)
360}
361----------------------------------------
362
363(c) 割込み処理/CPU例外処理のå…
364¥å£
365
366割込み処理/CPU例外処理のå…
367¥å£ã¯æ¬¡ã®é€šã‚Šã«ä¿®æ­£ã™ã‚‹ï¼Ž
368
369----------------------------------------
370void
371<割込みの出å…
372¥å£å‡¦ç†>(void)
373{
374 少なくともカーネル管理の割込みを禁止した状æ…
375‹ã«ã™ã‚‹ … (*f)
376 スクラッチレジスタをスタックに保存する
377 if (タスクコンテキストで割込み発生) {
378|#ifdef TOPPERS_SUPPORT_OVRHDR
379| ovrtimer_stop(); /* オーバランタイマの停止 */
380|#endif /* TOPPERS_SUPPORT_OVRHDR */
381 dspflgをスタックに保存する
382 dspflg = false;
383 スタックを非タスクコンテキスト用のスタックに切り換え,
384 非タスクコンテキストに切り換える
385 }
386 ...
387}
388----------------------------------------
389void
390<CPU例外の出å…
391¥å£å‡¦ç†>(void)
392{
393 if (タスクコンテキストでCPU例外発生) {
394 (少なくとも)カーネル管理の割込みを禁止した状æ…
395‹ã«ã™ã‚‹
396|#ifdef TOPPERS_SUPPORT_OVRHDR
397| ovrtimer_stop(); /* オーバランタイマの停止 */
398|#endif /* TOPPERS_SUPPORT_OVRHDR */
399 dspflgをスタックに保存する
400 dspflg = false;
401 スタックを非タスクコンテキスト用のスタックに切り換え,
402 非タスクコンテキストに切り換える
403 }
404 ...
405}
406----------------------------------------
407
408(d) 割込み処理/CPU例外処理の出口
409
410割込み処理/CPU例外処理の出口は次の通りに修正する.
411
412----------------------------------------
413void
414<割込みの出å…
415¥å£å‡¦ç†>(void)
416{
417 ...
418
419 ret_int_r:
420 スクラッチレジスタを除くすべてのレジスタをスタックから復帰する
421 }
422|#ifdef TOPPERS_SUPPORT_OVRHDR
423| if (p_runtsk != NULL) {
424| ovrtimer_start(); /* オーバランタイマの動作開始 */
425| }
426|#endif /* TOPPERS_SUPPORT_OVRHDR */
427 }
428 ...
429}
430----------------------------------------
431void
432<CPU例外の出å…
433¥å£å‡¦ç†>(void)
434{
435 ...
436
437 ret_exc_r:
438 スクラッチレジスタを除くすべてのレジスタをスタックから復帰する
439 }
440|#ifdef TOPPERS_SUPPORT_OVRHDR
441| if (p_runtsk != NULL) {
442| ovrtimer_start(); /* オーバランタイマの動作開始 */
443| }
444|a#endif /* TOPPERS_SUPPORT_OVRHDR */
445 }
446 CPU例外処理からのリターン後に,CPUロック解除状æ…
447‹ã«æˆ»ã‚‹ã‚ˆã†ã«æº–備する
448 }
449 ...
450}
451----------------------------------------
452
453(e) タスクの終了時
454
455ターゲット非依存部のext_tskとena_terで対応した.
456
457(f) タスクの実行開始時
458
459----------------------------------------
460void
461activate_context(TCB *p_tcb)
462{
463 ...
464
465 start_r:
466|#ifdef TOPPERS_SUPPORT_OVRHDR
467| ovrtimer_start(); /* オーバランタイマの動作開始 */
468|#endif /* TOPPERS_SUPPORT_OVRHDR */
469 CPUロック解除状æ…
470‹ã«ã™ã‚‹
471 自タスク(p_runtsk)の起動番地を,拡張情
472報をパラメータとして呼び出す
473 ext_tskに分岐する ... (*c)
474}
475----------------------------------------
476
477○オーバランハンドラの呼出しの実装
478
479
480オーバランタイマが満了し,割込みが発生した場合には,ターゲット依存部の
481割込みハンドラ(または,割込みサービスルーチン)から,ターゲット非依存
482部のcall_ovrhdrを呼び出す.
483
484ここで,オーバランタイマ割込みハンドラの起動と,sta_ovr/stp_ovrの呼出
485しの競合の問題がある.å…
486·ä½“例として,オーバランタイマが満了した直後に,
487他の高優å…
488ˆåº¦ã®å‰²è¾¼ã¿ãŒç™ºç”Ÿã—,その処理中でオーバランハンドラが再動作開
489始(残りプロセッサは更新される)された場合や停止された場合が問題になる.
490この場合,オーバランタイマ割込みハンドラの中で,オーバランハンドラを呼
491び出さないようにすべきである.
492
493ターゲット非依存部のcall_ovrhdrの実装
494は次の通り.
495
496----------------------------------------
497void
498call_ovrhdr(void)
499{
500 assert(sense_context());
501 assert(!sense_lock());
502 assert(ovrinib.ovrhdr != NULL);
503
504 lock_cpu();
505 if (p_runtsk != NULL && p_runtsk->staovr && p_runtsk->leftotm == 0U) {
506 p_runtsk->staovr = false;
507 unlock_cpu();
508
509 LOG_OVR_ENTER(p_runtsk);
510 ((OVRHDR)(ovrinib.ovrhdr))(TSKID(p_runtsk), p_runtsk->p_tinib->exinf);
511 LOG_OVR_LEAVE(p_runtsk);
512 }
513 else {
514 /*
515 * このルーチンが呼び出される前に,オーバランハンドラの起動が
516 * キャンセルされた場合
517 */
518 unlock_cpu();
519 }
520}
521----------------------------------------
522
523p_runtskがNULLの場合を考æ…
524®ã—ているのは,スプリアス割込みに対するロバス
525ト性を確保するためである.
526
527オーバランハンドラの呼出し後に,呼出し前の状æ…
528‹ï¼ˆCPUロック,割込み優å…
529ˆåº¦
530マスク)に戻さないのは,このルーチンからのリターン後に,割込み出口処理
531でå…
532ƒã®çŠ¶æ…
533‹ã«æˆ»ã™ãŸã‚ã§ã‚る.
534
535call_ovrhdrは,割込みハンドラから(または,割込みハンドラとして)呼び出
536されるため,このルーチンに来るまでに,ovrtimer_stopが呼ばれている(すな
537わち,オーバランタイマが停止している).
538
539割込みハンドラの設定は,以下のような静的APIを,target_timer.h中に記述す
540ることで行うものとする(ターゲットの事情
541で変更してよい).
542
543----------------------------------------
544#ifdef TOPPERS_SUPPORT_OVRHDR
545ATT_INI({ TA_NULL, 0, target_ovrtimer_initialize });
546ATT_TER({ TA_NULL, 0, target_ovrtimer_terminate });
547CFG_INT(INTNO_OVRTIMER, { TA_ENAINT | INTATR_OVRTIMER, INTPRI_OVRTIMER });
548DEF_INH(INHNO_OVRTIMER, { TA_NULL, target_ovrtimer_handler });
549#endif /* TOPPERS_SUPPORT_OVRHDR */
550----------------------------------------
551
552これらの静的API中の,INHNO_OVRTIMER,INTNO_OVRTIMER,INTPRI_OVRTIMER,
553INTATR_OVRTIMERの4つの定数は,target_timer.h中で定義する.
554
555○オーバヘッドの低減方法
556
557以上で説明した方法では,ターゲット依存部のアセンブリ言語で記述すること
558を想定したコードから,ターゲット非依存部のovrtimer_startと
559ovrtimer_stopを呼び出しているが,これらの関数は短いもので,アセンブリ言
560語の中に展開した方が効率がよい.これらの関数をアセンブリ言語の中に展開
561する場合には,それぞれ,OMIT_OVRTIMER_STARTとOMIT_OVRTIMER_STOPをマクロ
562定義する.
563
564○マルチプロセッサ対応カーネルへの対応に関するメモ
565
566マルチプロセッサ対応カーネルにおいて,sta_ovr,stp_ovrを,呼び出した処
567理単位と異なるプロセッサに割り付けられたタスクを対象に発行した場合の実
568装
569は工夫を要する.
570
571基本的には,対象タスクが割り付けられたプロセッサに対してプロセッサ間割
572込みをかけることによって,対象タスクのオーバランハンドラの動作を開始/
573停止させることが必
574要である.
575
576○Mac OS Xターゲット依存部に関するメモ
577
578Mac OS Xターゲット依存部では,割込み処理/CPU例外処理出口からリターンし
579た直後,dispatch_handlerが動作する前に,他の割込み処理が実行される場合
580があり,その場合には,ovrtimer_stopが続けて呼び出される状況が生じる.ター
581ゲット非依存部でovrtimer_flagを用いることで,ovrtimer_stopが続けて呼び
582出されても問題ないようになっているため,この実装
583で差し支えない.
584
585ターゲット非依存部でovrtimer_flagを用いない場合,割込み処理/CPU例外出
586口処理でタスク切換えを行う場合に,切換え前のタスクに対してオーバランハ
587ンドラを動作開始し,直後に停止するという(ムダな)処理を行う実装
588が考え
589られる.
590
591以上
Note: See TracBrowser for help on using the repository browser.