source: EcnlProtoTool/trunk/asp3_dcre/kernel/time_event.c@ 429

Last change on this file since 429 was 429, checked in by coas-nagasima, 4 years ago

ASP3, TINET, mbed を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 17.6 KB
Line 
1/*
2 * TOPPERS/ASP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
5 *
6 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
7 * Toyohashi Univ. of Technology, JAPAN
8 * Copyright (C) 2005-2019 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
10 *
11 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
12 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16 * スコード中に含まれていること.
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20 * の無保証規定を掲載すること.
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23 * と.
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27 * 報告すること.
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32 * 免責すること.
33 *
34 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 * の責任を負わない.
39 *
40 * $Id$
41 */
42
43/*
44 * タイムイベント管理モジュール
45 */
46
47#include "kernel_impl.h"
48#include "time_event.h"
49
50/*
51 * TCYC_HRTCNTの定義のチェック
52 */
53#if defined(USE_64BIT_HRTCNT) && defined(TCYC_HRTCNT)
54#error TCYC_HRTCNT must not be defined when USE_64BIT_HRTCNT.
55#endif
56
57/*
58 * TSTEP_HRTCNTの範囲チェック
59 */
60#if TSTEP_HRTCNT > 4000U
61#error TSTEP_HRTCNT is too large.
62#endif /* TSTEP_HRTCNT > 4000U */
63
64/*
65 * HRTCNT_BOUNDの定義のチェック
66 */
67#ifndef USE_64BIT_HRTCNT
68
69#if HRTCNT_BOUND >= 4294000000U
70#error HRTCNT_BOUND is too large.
71#endif /* HRTCNT_BOUND >= 4294000000U */
72
73#ifdef TCYC_HRTCNT
74#if HRTCNT_BOUND >= TCYC_HRTCNT
75#error HRTCNT_BOUND is too large.
76#endif /* HRTCNT_BOUND >= TCYC_HRTCNT */
77#endif /* TCYC_HRTCNT */
78
79#else /* USE_64BIT_HRTCNT */
80
81#ifdef HRTCNT_BOUND
82#error USE_64BIT_HRTCNT is not supported on this target.
83#endif /* HRTCNT_BOUND */
84
85#endif /* USE_64BIT_HRTCNT */
86
87/*
88 * タイムイベントヒープ操作マクロ
89 */
90#define PARENT(p_tmevtn) (tmevt_heap + (((p_tmevtn) - tmevt_heap) >> 1))
91 /* 親ノードを求める */
92#define LCHILD(p_tmevtn) (tmevt_heap + (((p_tmevtn) - tmevt_heap) << 1))
93 /* 左の子ノードを求める */
94/*
95 * タイムイベントヒープ中の先頭のノード
96 */
97#define p_top_tmevtn (&(tmevt_heap[1]))
98#define top_evttim (tmevt_heap[1].p_tmevtb->evttim)
99 /* 先頭のタイムイベントの発生時刻 */
100/*
101 * タイムイベントヒープ中の最後のノード
102 */
103#define p_last_tmevtn (tmevt_heap[0].p_last)
104
105/*
106 * イベント時刻の前後関係の判定[ASPD1009]
107 *
108 * イベント時刻は,boundary_evttimからの相対値で比較する.すなわち,
109 * boundary_evttimを最も早い時刻,boundary_evttim-1が最も遅い時刻とみ
110 * なして比較する.
111 */
112#define EVTTIM_ADVANCE(t) ((t) - boundary_evttim)
113#define EVTTIM_LT(t1, t2) (EVTTIM_ADVANCE(t1) < EVTTIM_ADVANCE(t2))
114#define EVTTIM_LE(t1, t2) (EVTTIM_ADVANCE(t1) <= EVTTIM_ADVANCE(t2))
115
116#ifdef TOPPERS_tmeini
117
118/*
119 * 境界イベント時刻[ASPD1008]
120 */
121EVTTIM boundary_evttim;
122
123/*
124 * 最後に現在時刻を算出した時点でのイベント時刻[ASPD1012]
125 */
126EVTTIM current_evttim;
127
128/*
129 * 最後に現在時刻を算出した時点での高分解能タイマのカウント値[ASPD1012]
130 */
131HRTCNT current_hrtcnt;
132
133/*
134 * 最も進んでいた時のイベント時刻[ASPD1041]
135 */
136EVTTIM monotonic_evttim;
137
138/*
139 * システム時刻のオフセット[ASPD1043]
140 */
141SYSTIM systim_offset;
142
143/*
144 * 高分解能タイマ割込みの処理中であることを示すフラグ[ASPD1032]
145 */
146bool_t in_signal_time;
147
148/*
149 * タイムイベント管理モジュールの初期化[ASPD1061]
150 */
151void
152initialize_tmevt(void)
153{
154 current_evttim = 0U; /*[ASPD1047]*/
155 boundary_evttim = current_evttim - BOUNDARY_MARGIN;
156 /*[ASPD1048]*/
157 monotonic_evttim = 0U; /*[ASPD1046]*/
158 systim_offset = 0U; /*[ASPD1044]*/
159 in_signal_time = false; /*[ASPD1033]*/
160 p_last_tmevtn = tmevt_heap;
161}
162
163#endif /* TOPPERS_tmeini */
164
165/*
166 * タイムイベントの挿入位置を上向きに探索
167 *
168 * 時刻evttimに発生するタイムイベントを挿入するノードを空けるために,
169 * ヒープの上に向かって空ノードを移動させる.移動前の空ノードの位置を
170 * p_tmevtnに渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す.
171 */
172#ifdef TOPPERS_tmeup
173
174TMEVTN *
175tmevt_up(TMEVTN *p_tmevtn, EVTTIM evttim)
176{
177 TMEVTN *p_parent;
178
179 while (p_tmevtn > p_top_tmevtn) {
180 /*
181 * 親ノードのイベント発生時刻の方が早い(または同じ)ならば,
182 * p_tmevtnが挿入位置なのでループを抜ける.
183 */
184 p_parent = PARENT(p_tmevtn);
185 if (EVTTIM_LE(p_parent->p_tmevtb->evttim, evttim)) {
186 break;
187 }
188
189 /*
190 * 親ノードをp_tmevtnの位置に移動させる.
191 */
192 *p_tmevtn = *p_parent;
193 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
194
195 /*
196 * p_tmevtnを親ノードの位置に更新.
197 */
198 p_tmevtn = p_parent;
199 }
200 return(p_tmevtn);
201}
202
203#endif /* TOPPERS_tmeup */
204
205/*
206 * タイムイベントの挿入位置を下向きに探索
207 *
208 * 時刻evttimに発生するタイムイベントを挿入するノードを空けるために,
209 * ヒープの下に向かって空ノードを移動させる.移動前の空ノードの位置を
210 * p_tmevtnに渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す.
211 */
212#ifdef TOPPERS_tmedown
213
214TMEVTN *
215tmevt_down(TMEVTN *p_tmevtn, EVTTIM evttim)
216{
217 TMEVTN *p_child;
218
219 while ((p_child = LCHILD(p_tmevtn)) <= p_last_tmevtn) {
220 /*
221 * 左右の子ノードのイベント発生時刻を比較し,早い方の子ノード
222 * の位置をp_childに設定する.以下の子ノードは,ここで選ばれた
223 * 方の子ノードのこと.
224 */
225 if (p_child + 1 <= p_last_tmevtn
226 && EVTTIM_LT((p_child + 1)->p_tmevtb->evttim,
227 p_child->p_tmevtb->evttim)) {
228 p_child = p_child + 1;
229 }
230
231 /*
232 * 子ノードのイベント発生時刻の方が遅い(または同じ)ならば,
233 * p_tmevtnが挿入位置なのでループを抜ける.
234 */
235 if (EVTTIM_LE(evttim, p_child->p_tmevtb->evttim)) {
236 break;
237 }
238
239 /*
240 * 子ノードをp_tmevtnの位置に移動させる.
241 */
242 *p_tmevtn = *p_child;
243 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
244
245 /*
246 * p_tmevtnを子ノードの位置に更新.
247 */
248 p_tmevtn = p_child;
249 }
250 return(p_tmevtn);
251}
252
253#endif /* TOPPERS_tmedown */
254
255/*
256 * タイムイベントヒープへの追加
257 *
258 * p_tmevtbで指定したタイムイベントブロックを,タイムイベントヒープに
259 * 追加する.
260 */
261Inline void
262tmevtb_insert(TMEVTB *p_tmevtb)
263{
264 TMEVTN *p_tmevtn;
265
266 /*
267 * p_last_tmevtnをインクリメントし,そこから上に挿入位置を探す.
268 */
269 p_tmevtn = tmevt_up(++p_last_tmevtn, p_tmevtb->evttim);
270
271 /*
272 * タイムイベントをp_tmevtnの位置に挿入する.
273 */
274 p_tmevtn->p_tmevtb = p_tmevtb;
275 p_tmevtb->p_tmevtn = p_tmevtn;
276}
277
278/*
279 * タイムイベントヒープからの削除
280 */
281Inline void
282tmevtb_delete(TMEVTB *p_tmevtb)
283{
284 TMEVTN *p_tmevtn = p_tmevtb->p_tmevtn;
285 TMEVTN *p_parent;
286 EVTTIM event_evttim;
287
288 /*
289 * 削除によりタイムイベントヒープが空になる場合は何もしない.
290 */
291 if (--p_last_tmevtn < p_top_tmevtn) {
292 return;
293 }
294
295 /*
296 * 削除したノードの位置に最後のノード(p_last_tmevtn + 1 の位置の
297 * ノード)を挿入し,それを適切な位置へ移動させる.実際には,最後
298 * のノードを実際に挿入するのではなく,削除したノードの位置が空ノー
299 * ドになるので,最後のノードを挿入すべき位置へ向けて空ノードを移
300 * 動させる.
301 *
302 * 最後のノードのイベント発生時刻が,削除したノードの親ノードのイ
303 * ベント発生時刻より前の場合には,上に向かって挿入位置を探す.そ
304 * うでない場合には,下に向かって探す.
305 */
306 event_evttim = (p_last_tmevtn + 1)->p_tmevtb->evttim;
307 if (p_tmevtn > p_top_tmevtn
308 && EVTTIM_LT(event_evttim,
309 (p_parent = PARENT(p_tmevtn))->p_tmevtb->evttim)) {
310 /*
311 * 親ノードをp_tmevtnの位置に移動させる.
312 */
313 *p_tmevtn = *p_parent;
314 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
315
316 /*
317 * 削除したノードの親ノードから上に向かって挿入位置を探す.
318 */
319 p_tmevtn = tmevt_up(p_parent, event_evttim);
320 }
321 else {
322 /*
323 * 削除したノードから下に向かって挿入位置を探す.
324 */
325 p_tmevtn = tmevt_down(p_tmevtn, event_evttim);
326 }
327
328 /*
329 * 最後のノードをp_tmevtnの位置に挿入する.
330 */
331 *p_tmevtn = *(p_last_tmevtn + 1);
332 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
333}
334
335/*
336 * タイムイベントヒープの先頭のノードの削除
337 */
338Inline TMEVTB *
339tmevtb_delete_top(void)
340{
341 TMEVTN *p_tmevtn;
342 TMEVTB *p_top_tmevtb = p_top_tmevtn->p_tmevtb;
343 EVTTIM event_evttim;
344
345 /*
346 * 削除によりタイムイベントヒープが空になる場合は何もしない.
347 */
348 if (--p_last_tmevtn >= p_top_tmevtn) {
349 /*
350 * ルートノードに最後のノード(p_last_tmevtn + 1 の位置のノー
351 * ド)を挿入し,それを適切な位置へ移動させる.実際には,最後
352 * のノードを実際に挿入するのではなく,ルートノードが空ノード
353 * になるので,最後のノードを挿入すべき位置へ向けて空ノードを
354 * 移動させる.
355 */
356 event_evttim = (p_last_tmevtn + 1)->p_tmevtb->evttim;
357 p_tmevtn = tmevt_down(p_top_tmevtn, event_evttim);
358
359 /*
360 * 最後のノードをp_tmevtnの位置に挿入する.
361 */
362 *p_tmevtn = *(p_last_tmevtn + 1);
363 p_tmevtn->p_tmevtb->p_tmevtn = p_tmevtn;
364 }
365 return(p_top_tmevtb);
366}
367
368/*
369 * 現在のイベント時刻の更新
370 */
371#ifdef TOPPERS_tmecur
372
373void
374update_current_evttim(void)
375{
376 HRTCNT new_hrtcnt, hrtcnt_advance;
377 EVTTIM previous_evttim;
378
379 new_hrtcnt = target_hrt_get_current(); /*[ASPD1013]*/
380 hrtcnt_advance = new_hrtcnt - current_hrtcnt; /*[ASPD1014]*/
381#ifdef TCYC_HRTCNT
382 if (new_hrtcnt < current_hrtcnt) {
383 hrtcnt_advance += TCYC_HRTCNT;
384 }
385#endif /* TCYC_HRTCNT */
386 current_hrtcnt = new_hrtcnt; /*[ASPD1016]*/
387
388 previous_evttim = current_evttim;
389 current_evttim += (EVTTIM) hrtcnt_advance; /*[ASPD1015]*/
390 boundary_evttim = current_evttim - BOUNDARY_MARGIN; /*[ASPD1011]*/
391
392 if (monotonic_evttim - previous_evttim < (EVTTIM) hrtcnt_advance) {
393#ifdef UINT64_MAX
394 if (current_evttim < monotonic_evttim) {
395 systim_offset += 1LLU << 32; /*[ASPD1045]*/
396 }
397#endif /* UINT64_MAX */
398 monotonic_evttim = current_evttim; /*[ASPD1042]*/
399 }
400}
401
402#endif /* TOPPERS_tmecur */
403
404/*
405 * 現在のイベント時刻を遅い方に丸めたイベント時刻の算出[ASPD1027]
406 *
407 * 現在のイベント時刻を更新した後に呼ぶことを想定している.
408 */
409Inline EVTTIM
410calc_current_evttim_ub(void)
411{
412 return(current_evttim + ((EVTTIM) TSTEP_HRTCNT));
413}
414
415/*
416 * 高分解能タイマ割込みの発生タイミングの設定
417 */
418#ifdef TOPPERS_tmeset
419
420void
421set_hrt_event(void)
422{
423 HRTCNT hrtcnt;
424
425 if (p_last_tmevtn < p_top_tmevtn) {
426 /*
427 * タイムイベントがない場合
428 */
429#ifdef USE_64BIT_HRTCNT
430 target_hrt_clear_event();
431#else /* USE_64BIT_HRTCNT */
432 target_hrt_set_event(HRTCNT_BOUND); /*[ASPD1007]*/
433#endif /* USE_64BIT_HRTCNT */
434 }
435 else if (EVTTIM_LE(top_evttim, current_evttim)) {
436 target_hrt_raise_event(); /*[ASPD1017]*/
437 }
438 else {
439 hrtcnt = (HRTCNT)(top_evttim - current_evttim);
440#ifdef USE_64BIT_HRTCNT
441 target_hrt_set_event(hrtcnt);
442#else /* USE_64BIT_HRTCNT */
443 if (hrtcnt > HRTCNT_BOUND) {
444 target_hrt_set_event(HRTCNT_BOUND); /*[ASPD1006]*/
445 }
446 else {
447 target_hrt_set_event(hrtcnt); /*[ASPD1002]*/
448 }
449#endif /* USE_64BIT_HRTCNT */
450 }
451}
452
453#endif /* TOPPERS_tmeset */
454
455/*
456 * タイムイベントブロックのヒープへの挿入
457 */
458#ifdef TOPPERS_tmereg
459
460void
461tmevtb_register(TMEVTB *p_tmevtb)
462{
463 tmevtb_insert(p_tmevtb);
464}
465
466#endif /* TOPPERS_tmereg */
467
468/*
469 * 相対時間指定によるタイムイベントの登録
470 *
471 */
472#ifdef TOPPERS_tmeenqrel
473
474void
475tmevtb_enqueue_reltim(TMEVTB *p_tmevtb, RELTIM time)
476{
477 /*
478 * 現在のイベント時刻とタイムイベントの発生時刻を求める[ASPD1026].
479 */
480 update_current_evttim();
481 p_tmevtb->evttim = calc_current_evttim_ub() + time;
482
483 /*
484 * タイムイベントブロックをヒープに挿入する[ASPD1030].
485 */
486 tmevtb_insert(p_tmevtb);
487
488 /*
489 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1031]
490 * [ASPD1034].
491 */
492 if (!in_signal_time && p_tmevtb->p_tmevtn == p_top_tmevtn) {
493 set_hrt_event();
494 }
495}
496
497#endif /* TOPPERS_tmeenqrel */
498
499/*
500 * タイムイベントの登録解除
501 */
502#ifdef TOPPERS_tmedeq
503
504void
505tmevtb_dequeue(TMEVTB *p_tmevtb)
506{
507 TMEVTN *p_tmevtn;
508
509 /*
510 * タイムイベントブロックをヒープから削除する[ASPD1039].
511 */
512 p_tmevtn = p_tmevtb->p_tmevtn;
513 tmevtb_delete(p_tmevtb);
514
515 /*
516 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1040].
517 */
518 if (!in_signal_time && p_tmevtn == p_top_tmevtn) {
519 update_current_evttim();
520 set_hrt_event();
521 }
522}
523
524#endif /* TOPPERS_tmedeq */
525
526/*
527 * システム時刻の調整時のエラーチェック
528 */
529#ifdef TOPPERS_tmechk
530
531bool_t
532check_adjtim(int32_t adjtim)
533{
534 if (adjtim > 0) {
535 return(p_last_tmevtn >= p_top_tmevtn /*[NGKI3588]*/
536 && EVTTIM_LE(top_evttim + TMAX_ADJTIM, current_evttim));
537 }
538 else if (adjtim < 0) { /*[NGKI3589]*/
539 return(monotonic_evttim - current_evttim >= -TMIN_ADJTIM);
540 }
541 return(false);
542}
543
544#endif /* TOPPERS_tmechk */
545
546/*
547 * タイムイベントが発生するまでの時間の計算
548 */
549#ifdef TOPPERS_tmeltim
550
551RELTIM
552tmevt_lefttim(TMEVTB *p_tmevtb)
553{
554 EVTTIM evttim, current_evttim_ub;
555
556 /*
557 * 現在のイベント時刻を遅い方に丸めた時刻を求める[ASPD1050].
558 */
559 update_current_evttim();
560 current_evttim_ub = calc_current_evttim_ub();
561
562 /*
563 * タイムイベント発生までの相対時間を求める[ASPD1049].
564 */
565 evttim = p_tmevtb->evttim;
566 if (EVTTIM_LE(evttim, current_evttim_ub)) {
567 /*
568 * タイムイベントの発生時刻を過ぎている場合には0を返す[NGKI0552].
569 */
570 return(0U);
571 }
572 else {
573 return((RELTIM)(evttim - current_evttim_ub));
574 }
575}
576
577#endif /* TOPPERS_tmeltim */
578
579/*
580 * 高分解能タイマ割込みの処理
581 */
582#ifdef TOPPERS_sigtim
583
584void
585signal_time(void)
586{
587 TMEVTB *p_tmevtb;
588 bool_t callflag;
589#ifndef TOPPERS_OMIT_SYSLOG
590 uint_t nocall = 0;
591#endif /* TOPPERS_OMIT_SYSLOG */
592
593 assert(sense_context());
594 assert(!sense_lock());
595
596 lock_cpu();
597 in_signal_time = true; /*[ASPD1033]*/
598
599 do {
600 /*
601 * コールバック関数を呼び出さなければループを抜ける[ASPD1020].
602 */
603 callflag = false;
604
605 /*
606 * 現在のイベント時刻を求める[ASPD1022].
607 */
608 update_current_evttim();
609
610 /*
611 * 発生時刻がcurrent_evttim以前のタイムイベントがあれば,タイ
612 * ムイベントヒープから削除し,コールバック関数を呼び出す
613 * [ASPD1018][ASPD1019].
614 */
615 while (p_last_tmevtn >= p_top_tmevtn
616 && EVTTIM_LE(top_evttim, current_evttim)) {
617 p_tmevtb = tmevtb_delete_top();
618 (*(p_tmevtb->callback))(p_tmevtb->arg);
619 callflag = true;
620#ifndef TOPPERS_OMIT_SYSLOG
621 nocall += 1;
622#endif /* TOPPERS_OMIT_SYSLOG */
623 }
624 } while (callflag); /*[ASPD1020]*/
625
626#ifndef TOPPERS_OMIT_SYSLOG
627 /*
628 * タイムイベントが処理されなかった場合.
629 */
630 if (nocall == 0) {
631 syslog_0(LOG_NOTICE, "no time event is processed in hrt interrupt.");
632 }
633#endif /* TOPPERS_OMIT_SYSLOG */
634
635 /*
636 * 高分解能タイマ割込みの発生タイミングを設定する[ASPD1025].
637 */
638 set_hrt_event();
639
640 in_signal_time = false; /*[ASPD1033]*/
641 unlock_cpu();
642}
643
644#endif /* TOPPERS_sigtim */
Note: See TracBrowser for help on using the repository browser.