00001 /* 00002 * TOPPERS/ASP Kernel 00003 * Toyohashi Open Platform for Embedded Real-Time Systems/ 00004 * Advanced Standard Profile Kernel 00005 * 00006 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory 00007 * Toyohashi Univ. of Technology, JAPAN 00008 * Copyright (C) 2005-2008 by Embedded and Real-Time Systems Laboratory 00009 * Graduate School of Information Science, Nagoya Univ., JAPAN 00010 * 00011 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ 00012 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 00013 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. 00014 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 00015 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー 00016 * スコード中に含まれていること. 00017 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 00018 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 00019 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 00020 * の無保証規定を掲載すること. 00021 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 00022 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ 00023 * と. 00024 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 00025 * 作権表示,この利用条件および下記の無保証規定を掲載すること. 00026 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに 00027 * 報告すること. 00028 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 00029 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. 00030 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 00031 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを 00032 * 免責すること. 00033 * 00034 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お 00035 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 00036 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ 00037 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ 00038 * の責任を負わない. 00039 * 00040 * @(#) $Id: time_event.c 874 2008-04-11 10:33:17Z hiro $ 00041 */ 00042 00043 /* 00044 * タイムイベント管理モジュール 00045 */ 00046 00047 #include "kernel_impl.h" 00048 #include "check.h" 00049 #include "time_event.h" 00050 00051 /* 00052 * タイムイベントヒープ操作マクロ 00053 */ 00054 #define PARENT(index) ((index) >> 1) /* 親ノードを求める */ 00055 #define LCHILD(index) ((index) << 1) /* 右の子ノードを求める */ 00056 #define TMEVT_NODE(index) (tmevt_heap[(index) - 1]) 00057 00058 /* 00059 * イベント発生時刻比較マクロ 00060 * 00061 * イベント発生時刻は,current_timeからの相対値で比較する.すなわち, 00062 * current_timeを最小値(最も近い時刻),current_time-1が最大値(最も 00063 * 遠い時刻)とみなして比較する. 00064 */ 00065 #define EVTTIM_LT(t1, t2) (((t1) - current_time) < ((t2) - current_time)) 00066 #define EVTTIM_LE(t1, t2) (((t1) - current_time) <= ((t2) - current_time)) 00067 00068 #ifdef TOPPERS_tmeini 00069 00070 /* 00071 * 現在のシステム時刻(単位: ミリ秒) 00072 * 00073 * 厳密には,前のタイムティックのシステム時刻. 00074 */ 00075 EVTTIM current_time; 00076 00077 /* 00078 * 次のタイムティックのシステム時刻(単位: 1ミリ秒) 00079 */ 00080 EVTTIM next_time; 00081 00082 /* 00083 * システム時刻積算用変数(単位: 1/TIM_DENOミリ秒) 00084 */ 00085 #if TIC_DENO != 1U 00086 uint_t next_subtime; 00087 #endif /* TIC_DENO != 1U */ 00088 00089 /* 00090 * タイムイベントヒープの最後の使用領域のインデックス 00091 */ 00092 uint_t last_index; 00093 00094 /* 00095 * タイマモジュールの初期化 00096 */ 00097 void 00098 initialize_tmevt(void) 00099 { 00100 current_time = 0U; 00101 next_time = current_time + TIC_NUME / TIC_DENO; 00102 #if TIC_DENO != 1U 00103 next_subtime = TIC_NUME % TIC_DENO; 00104 #endif /* TIC_DENO != 1U */ 00105 last_index = 0U; 00106 } 00107 00108 #endif /* TOPPERS_tmeini */ 00109 00110 /* 00111 * タイムイベントの挿入位置を上向きに探索 00112 * 00113 * 時刻timeに発生するタイムイベントを挿入するノードを空けるために, 00114 * ヒープの上に向かって空ノードを移動させる.移動前の空ノードの位置を 00115 * indexに渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す. 00116 */ 00117 #ifdef TOPPERS_tmeup 00118 00119 uint_t 00120 tmevt_up(uint_t index, EVTTIM time) 00121 { 00122 uint_t parent; 00123 00124 while (index > 1) { 00125 /* 00126 * 親ノードのイベント発生時刻の方が早い(または同じ) 00127 * ならば,index が挿入位置なのでループを抜ける. 00128 */ 00129 parent = PARENT(index); 00130 if (EVTTIM_LE(TMEVT_NODE(parent).time, time)) { 00131 break; 00132 } 00133 00134 /* 00135 * 親ノードを index の位置に移動させる. 00136 */ 00137 TMEVT_NODE(index) = TMEVT_NODE(parent); 00138 TMEVT_NODE(index).p_tmevtb->index = index; 00139 00140 /* 00141 * index を親ノードの位置に更新. 00142 */ 00143 index = parent; 00144 } 00145 return(index); 00146 } 00147 00148 #endif /* TOPPERS_tmeup */ 00149 00150 /* 00151 * タイムイベントの挿入位置を下向きに探索 00152 * 00153 * 時刻timeに発生するタイムイベントを挿入するノードを空けるために, 00154 * ヒープの下に向かって空ノードを移動させる.移動前の空ノードの位置を 00155 * indexに渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す. 00156 */ 00157 #ifdef TOPPERS_tmedown 00158 00159 uint_t 00160 tmevt_down(uint_t index, EVTTIM time) 00161 { 00162 uint_t child; 00163 00164 while ((child = LCHILD(index)) <= last_index) { 00165 /* 00166 * 左右の子ノードのイベント発生時刻を比較し,早い方の 00167 * 子ノードの位置を child に設定する.以下の子ノード 00168 * は,ここで選ばれた方の子ノードのこと. 00169 */ 00170 if (child + 1 <= last_index 00171 && EVTTIM_LT(TMEVT_NODE(child + 1).time, 00172 TMEVT_NODE(child).time)) { 00173 child = child + 1; 00174 } 00175 00176 /* 00177 * 子ノードのイベント発生時刻の方が遅い(または同じ) 00178 * ならば,index が挿入位置なのでループを抜ける. 00179 */ 00180 if (EVTTIM_LE(time, TMEVT_NODE(child).time)) { 00181 break; 00182 } 00183 00184 /* 00185 * 子ノードを index の位置に移動させる. 00186 */ 00187 TMEVT_NODE(index) = TMEVT_NODE(child); 00188 TMEVT_NODE(index).p_tmevtb->index = index; 00189 00190 /* 00191 * index を子ノードの位置に更新. 00192 */ 00193 index = child; 00194 } 00195 return(index); 00196 } 00197 00198 #endif /* TOPPERS_tmedown */ 00199 00200 /* 00201 * タイムイベントヒープへの登録 00202 * 00203 * p_tmevtbで指定したタイムイベントブロックを,timeで指定した時間が経 00204 * 過後にイベントが発生するように,タイムイベントヒープに登録する. 00205 */ 00206 #ifdef TOPPERS_tmeins 00207 00208 void 00209 tmevtb_insert(TMEVTB *p_tmevtb, EVTTIM time) 00210 { 00211 uint_t index; 00212 00213 /* 00214 * last_index をインクリメントし,そこから上に挿入位置を探す. 00215 */ 00216 index = tmevt_up(++last_index, time); 00217 00218 /* 00219 * タイムイベントを index の位置に挿入する. 00220 */ 00221 TMEVT_NODE(index).time = time; 00222 TMEVT_NODE(index).p_tmevtb = p_tmevtb; 00223 p_tmevtb->index = index; 00224 } 00225 00226 #endif /* TOPPERS_tmeins */ 00227 00228 /* 00229 * タイムイベントヒープからの削除 00230 */ 00231 #ifdef TOPPERS_tmedel 00232 00233 void 00234 tmevtb_delete(TMEVTB *p_tmevtb) 00235 { 00236 uint_t index = p_tmevtb->index; 00237 uint_t parent; 00238 EVTTIM event_time = TMEVT_NODE(last_index).time; 00239 00240 /* 00241 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00242 */ 00243 if (--last_index == 0) { 00244 return; 00245 } 00246 00247 /* 00248 * 削除したノードの位置に最後のノード(last_index+1の位置のノード) 00249 * を挿入し,それを適切な位置へ移動させる.実際には,最後のノード 00250 * を実際に挿入するのではなく,削除したノードの位置が空ノードにな 00251 * るので,最後のノードを挿入すべき位置へ向けて空ノードを移動させ 00252 * る. 00253 * 最後のノードのイベント発生時刻が,削除したノードの親ノードのイ 00254 * ベント発生時刻より前の場合には,上に向かって挿入位置を探す.そ 00255 * うでない場合には,下に向かって探す. 00256 */ 00257 if (index > 1 && EVTTIM_LT(event_time, 00258 TMEVT_NODE(parent = PARENT(index)).time)) { 00259 /* 00260 * 親ノードをindexの位置に移動させる. 00261 */ 00262 TMEVT_NODE(index) = TMEVT_NODE(parent); 00263 TMEVT_NODE(index).p_tmevtb->index = index; 00264 00265 /* 00266 * 削除したノードの親ノードから上に向かって挿入位置を探す. 00267 */ 00268 index = tmevt_up(parent, event_time); 00269 } 00270 else { 00271 /* 00272 * 削除したノードから下に向かって挿入位置を探す. 00273 */ 00274 index = tmevt_down(index, event_time); 00275 } 00276 00277 /* 00278 * 最後のノードをindexの位置に挿入する. 00279 */ 00280 TMEVT_NODE(index) = TMEVT_NODE(last_index + 1); 00281 TMEVT_NODE(index).p_tmevtb->index = index; 00282 } 00283 00284 #endif /* TOPPERS_tmedel */ 00285 00286 /* 00287 * タイムイベントヒープの先頭のノードの削除 00288 */ 00289 Inline void 00290 tmevtb_delete_top(void) 00291 { 00292 uint_t index; 00293 EVTTIM event_time = TMEVT_NODE(last_index).time; 00294 00295 /* 00296 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00297 */ 00298 if (--last_index == 0) { 00299 return; 00300 } 00301 00302 /* 00303 * ルートノードに最後のノード(last_index + 1 の位置のノード)を 00304 * 挿入し,それを適切な位置へ移動させる.実際には,最後のノードを 00305 * 実際に挿入するのではなく,ルートノードが空ノードになるので,最 00306 * 後のノードを挿入すべき位置へ向けて空ノードを移動させる. 00307 */ 00308 index = tmevt_down(1, event_time); 00309 00310 /* 00311 * 最後のノードをindexの位置に挿入する. 00312 */ 00313 TMEVT_NODE(index) = TMEVT_NODE(last_index + 1); 00314 TMEVT_NODE(index).p_tmevtb->index = index; 00315 } 00316 00317 /* 00318 * タイムイベントまでの残り時間の計算 00319 */ 00320 #ifdef TOPPERS_tmeltim 00321 00322 RELTIM 00323 tmevt_lefttim(TMEVTB *p_tmevtb) 00324 { 00325 EVTTIM time; 00326 00327 time = TMEVT_NODE(p_tmevtb->index).time; 00328 if (EVTTIM_LE(time, next_time)) { 00329 /* 00330 * 次のタイムティックで処理される場合には0を返す. 00331 */ 00332 return(0U); 00333 } 00334 else { 00335 return((RELTIM)(time - base_time)); 00336 } 00337 } 00338 00339 #endif /* TOPPERS_tmeltim */ 00340 00341 /* 00342 * タイムティックの供給 00343 */ 00344 #ifdef TOPPERS_sigtim 00345 00346 void 00347 signal_time(void) 00348 { 00349 TMEVTB *p_tmevtb; 00350 00351 assert(sense_context()); 00352 assert(!i_sense_lock()); 00353 i_lock_cpu(); 00354 00355 /* 00356 * next_timeよりイベント発生時刻の早い(または同じ)タイムイベン 00357 * トを,タイムイベントヒープから削除し,コールバック関数を呼び出 00358 * す. 00359 */ 00360 while (last_index > 0 && EVTTIM_LE(TMEVT_NODE(1).time, next_time)) { 00361 p_tmevtb = TMEVT_NODE(1).p_tmevtb; 00362 tmevtb_delete_top(); 00363 (*(p_tmevtb->callback))(p_tmevtb->arg); 00364 } 00365 00366 /* 00367 * current_timeを更新する. 00368 */ 00369 current_time = next_time; 00370 00371 /* 00372 * next_time,next_subtimeを更新する. 00373 * 00374 * TIC_NUME < TIC_DENOの時は,除算を使わずに時刻の更新ができるが, 00375 * ソースコードを読みやすくにするために#ifの多用を避けている. 00376 */ 00377 #if TIC_DENO == 1U 00378 next_time = current_time + TIC_NUME; 00379 #else /* TIC_DENO == 1U */ 00380 next_subtime += TIC_NUME % TIC_DENO; 00381 next_time = current_time + TIC_NUME / TIC_DENO; 00382 if (next_subtime >= TIC_DENO) { 00383 next_subtime -= TIC_DENO; 00384 next_time += 1U; 00385 } 00386 #endif /* TIC_DENO == 1U */ 00387 00388 i_unlock_cpu(); 00389 } 00390 00391 #endif /* TOPPERS_sigtim */
Copyright © 2008 by Kijineko Inc.