|
|
time_event.c説明を見る。00001 /* 00002 * TOPPERS/JSP Kernel 00003 * Toyohashi Open Platform for Embedded Real-Time Systems/ 00004 * Just Standard Profile Kernel 00005 * 00006 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory 00007 * Toyohashi Univ. of Technology, JAPAN 00008 * 00009 * 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 00010 * によって公表されている GNU General Public License の Version 2 に記 00011 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア 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 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お 00032 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も 00033 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 00034 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. 00035 * 00036 * @(#) $Id: time_event.c,v 1.7 2003/06/04 01:46:16 hiro Exp $ 00037 */ 00038 00039 /* 00040 * タイムイベント管理モジュール 00041 */ 00042 00043 #include "jsp_kernel.h" 00044 #include "check.h" 00045 #include "time_event.h" 00046 00047 /* 00048 * タイムイベントヒープ操作マクロ 00049 */ 00050 #define PARENT(index) ((index) >> 1) /* 親ノードを求める */ 00051 #define LCHILD(index) ((index) << 1) /* 右の子ノードを求める */ 00052 #define TMEVT_NODE(index) (tmevt_heap[(index) - 1]) 00053 00054 /* 00055 * イベント発生時刻比較マクロ 00056 * 00057 * イベント発生時刻は,current_time からの相対値で比較する.すなわち, 00058 * current_time を最小値(最も近い時刻),current_time - 1 が最大値 00059 * (最も遠い時刻)とみなして比較する. 00060 */ 00061 #define EVTTIM_LT(t1, t2) (((t1) - current_time) < ((t2) - current_time)) 00062 #define EVTTIM_LE(t1, t2) (((t1) - current_time) <= ((t2) - current_time)) 00063 00064 #ifdef __tmeini 00065 00066 /* 00067 * システム時刻のオフセット 00068 */ 00069 SYSTIM systim_offset; 00070 00071 /* 00072 * 現在のシステム時刻(単位: ミリ秒) 00073 * 00074 * 厳密には,前のタイムティックのシステム時刻. 00075 */ 00076 SYSTIM current_time; 00077 00078 /* 00079 * 次のタイムティックのシステム時刻(単位: 1ミリ秒) 00080 */ 00081 SYSTIM next_time; 00082 00083 /* 00084 * システム時刻積算用変数(単位: 1/TIM_DENOミリ秒) 00085 */ 00086 #if TIC_DENO != 1 00087 UINT next_subtime; 00088 #endif /* TIC_DENO != 1 */ 00089 00090 /* 00091 * タイムイベントヒープの最後の使用領域のインデックス 00092 */ 00093 UINT last_index; 00094 00095 /* 00096 * タイマモジュールの初期化 00097 */ 00098 void 00099 tmevt_initialize() 00100 { 00101 systim_offset = 0; 00102 current_time = 0; 00103 #if TIC_DENO == 1 00104 next_time = current_time + TIC_NUME; 00105 #else /* TIC_DENO == 1 */ 00106 next_subtime += TIC_NUME; 00107 next_time = current_time + next_subtime / TIC_DENO; 00108 next_subtime %= TIC_DENO; 00109 #endif /* TIC_DENO == 1 */ 00110 last_index = 0; 00111 } 00112 00113 #endif /* __tmeini */ 00114 00115 /* 00116 * タイムイベントの挿入位置を上向きに探索 00117 * 00118 * 時刻 time に発生するタイムイベントを挿入するノードを空けるために, 00119 * ヒープの上に向かって空ノードを移動させる.移動前の空ノードの位置を 00120 * index に渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す. 00121 */ 00122 #ifdef __tmeup 00123 00124 UINT 00125 tmevt_up(UINT index, EVTTIM time) 00126 { 00127 UINT parent; 00128 00129 while (index > 1) { 00130 /* 00131 * 親ノードのイベント発生時刻の方が早い(または同じ) 00132 * ならば,index が挿入位置なのでループを抜ける. 00133 */ 00134 parent = PARENT(index); 00135 if (EVTTIM_LE(TMEVT_NODE(parent).time, time)) { 00136 break; 00137 } 00138 00139 /* 00140 * 親ノードを index の位置に移動させる. 00141 */ 00142 TMEVT_NODE(index) = TMEVT_NODE(parent); 00143 TMEVT_NODE(index).tmevtb->index = index; 00144 00145 /* 00146 * index を親ノードの位置に更新. 00147 */ 00148 index = parent; 00149 } 00150 return(index); 00151 } 00152 00153 #endif /* __tmeup */ 00154 00155 /* 00156 * タイムイベントの挿入位置を下向きに探索 00157 * 00158 * 時刻 time に発生するタイムイベントを挿入するノードを空けるために, 00159 * ヒープの下に向かって空ノードを移動させる.移動前の空ノードの位置を 00160 * index に渡すと,移動後の空ノードの位置(すなわち挿入位置)を返す. 00161 */ 00162 #ifdef __tmedown 00163 00164 UINT 00165 tmevt_down(UINT index, EVTTIM time) 00166 { 00167 UINT child; 00168 00169 while ((child = LCHILD(index)) <= last_index) { 00170 /* 00171 * 左右の子ノードのイベント発生時刻を比較し,早い方の 00172 * 子ノードの位置を child に設定する.以下の子ノード 00173 * は,ここで選ばれた方の子ノードのこと. 00174 */ 00175 if (child + 1 <= last_index 00176 && EVTTIM_LT(TMEVT_NODE(child + 1).time, 00177 TMEVT_NODE(child).time)) { 00178 child = child + 1; 00179 } 00180 00181 /* 00182 * 子ノードのイベント発生時刻の方が遅い(または同じ) 00183 * ならば,index が挿入位置なのでループを抜ける. 00184 */ 00185 if (EVTTIM_LE(time, TMEVT_NODE(child).time)) { 00186 break; 00187 } 00188 00189 /* 00190 * 子ノードを index の位置に移動させる. 00191 */ 00192 TMEVT_NODE(index) = TMEVT_NODE(child); 00193 TMEVT_NODE(index).tmevtb->index = index; 00194 00195 /* 00196 * index を子ノードの位置に更新. 00197 */ 00198 index = child; 00199 } 00200 return(index); 00201 } 00202 00203 #endif /* __tmedown */ 00204 00205 /* 00206 * タイムイベントヒープへの登録 00207 * 00208 * タイムイベントブロック tmevtb を,time で指定した時間が経過後にイ 00209 * ベントが発生するように,タイムイベントヒープに登録する. 00210 */ 00211 #ifdef __tmeins 00212 00213 void 00214 tmevtb_insert(TMEVTB *tmevtb, EVTTIM time) 00215 { 00216 UINT index; 00217 00218 /* 00219 * last_index をインクリメントし,そこから上に挿入位置を探す. 00220 */ 00221 index = tmevt_up(++last_index, time); 00222 00223 /* 00224 * タイムイベントを index の位置に挿入する. 00225 */ 00226 TMEVT_NODE(index).time = time; 00227 TMEVT_NODE(index).tmevtb = tmevtb; 00228 tmevtb->index = index; 00229 } 00230 00231 #endif /* __tmeins */ 00232 00233 /* 00234 * タイムイベントヒープからの削除 00235 */ 00236 #ifdef __tmedel 00237 00238 void 00239 tmevtb_delete(TMEVTB *tmevtb) 00240 { 00241 UINT index = tmevtb->index; 00242 UINT parent; 00243 EVTTIM event_time = TMEVT_NODE(last_index).time; 00244 00245 /* 00246 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00247 */ 00248 if (--last_index == 0) { 00249 return; 00250 } 00251 00252 /* 00253 * 削除したノードの位置に最後のノード(last_index + 1 の位置 00254 * のノード)を挿入し,それを適切な位置へ移動させる.実際には, 00255 * 最後のノードを実際に挿入するのではなく,削除したノードの位 00256 * 置が空ノードになるので,最後のノードを挿入すべき位置へ向け 00257 * て空ノードを移動させる. 00258 * 最後のノードのイベント発生時刻が,削除したノードの親ノード 00259 * のイベント発生時刻より前の場合には,上に向かって挿入位置を 00260 * 探す.そうでない場合には,下に向かって探す. 00261 */ 00262 if (index > 1 && EVTTIM_LT(event_time, 00263 TMEVT_NODE(parent = PARENT(index)).time)) { 00264 /* 00265 * 親ノードを index の位置に移動させる. 00266 */ 00267 TMEVT_NODE(index) = TMEVT_NODE(parent); 00268 TMEVT_NODE(index).tmevtb->index = index; 00269 00270 /* 00271 * 削除したノードの親ノードから上に向かって挿入位置を 00272 * 探す. 00273 */ 00274 index = tmevt_up(parent, event_time); 00275 } 00276 else { 00277 /* 00278 * 削除したノードから下に向かって挿入位置を探す. 00279 */ 00280 index = tmevt_down(index, event_time); 00281 } 00282 00283 /* 00284 * 最後のノードを index の位置に挿入する. 00285 */ 00286 TMEVT_NODE(index) = TMEVT_NODE(last_index + 1); 00287 TMEVT_NODE(index).tmevtb->index = index; 00288 } 00289 00290 #endif /* __tmedel */ 00291 00292 /* 00293 * タイムイベントヒープの先頭のノードの削除 00294 */ 00295 Inline void 00296 tmevtb_delete_top() 00297 { 00298 UINT index; 00299 EVTTIM event_time = TMEVT_NODE(last_index).time; 00300 00301 /* 00302 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00303 */ 00304 if (--last_index == 0) { 00305 return; 00306 } 00307 00308 /* 00309 * ルートノードに最後のノード(last_index + 1 の位置のノード) 00310 * を挿入し,それを適切な位置へ移動させる.実際には,最後のノー 00311 * ドを実際に挿入するのではなく,ルートノードが空ノードになる 00312 * ので,最後のノードを挿入すべき位置へ向けて空ノードを移動さ 00313 * せる. 00314 */ 00315 index = tmevt_down(1, event_time); 00316 00317 /* 00318 * 最後のノードを index の位置に挿入する. 00319 */ 00320 TMEVT_NODE(index) = TMEVT_NODE(last_index + 1); 00321 TMEVT_NODE(index).tmevtb->index = index; 00322 } 00323 00324 /* 00325 * タイムティックの供給 00326 * 00327 * TIC_NUME < TIC_DENO の時は,除算を使わずに時刻の更新ができるが,ソー 00328 * スコードを読みやすくにするために #if の多用を避けている. 00329 */ 00330 #ifdef __isig_tim 00331 00332 SYSCALL ER 00333 isig_tim() 00334 { 00335 TMEVTB *tmevtb; 00336 ER ercd; 00337 00338 LOG_ISIG_TIM_ENTER(); 00339 CHECK_INTCTX_UNL(); 00340 i_lock_cpu(); 00341 00342 /* 00343 * next_time よりイベント発生時刻の早い(または同じ)タイムイ 00344 * ベントを,タイムイベントヒープから削除し,コールバック関数 00345 * を呼び出す. 00346 */ 00347 while (last_index > 0 && EVTTIM_LE(TMEVT_NODE(1).time, next_time)) { 00348 tmevtb = TMEVT_NODE(1).tmevtb; 00349 tmevtb_delete_top(); 00350 (*(tmevtb->callback))(tmevtb->arg); 00351 00352 /* 00353 * ここで優先度の高い割込みを受け付ける. 00354 */ 00355 i_unlock_cpu(); 00356 i_lock_cpu(); 00357 } 00358 00359 /* 00360 * current_time を更新する. 00361 */ 00362 current_time = next_time; 00363 00364 /* 00365 * next_time,next_subtime を更新する. 00366 */ 00367 #if TIC_DENO == 1 00368 next_time = current_time + TIC_NUME; 00369 #else /* TIC_DENO == 1 */ 00370 next_subtime += TIC_NUME; 00371 next_time = current_time + next_subtime / TIC_DENO; 00372 next_subtime %= TIC_DENO; 00373 #endif /* TIC_DENO == 1 */ 00374 00375 ercd = E_OK; 00376 i_unlock_cpu(); 00377 00378 exit: 00379 LOG_ISIG_TIM_LEAVE(ercd); 00380 return(ercd); 00381 } 00382 00383 #endif /* __isig_tim */ 00384 Copyright © 2006 by TAKAGI Nobuhisa. Copyright © 2006 by Kijineko Inc.. このページは Mon Dec 18 17:18:41 2006 に Doxygen によって生成されました。 データ入力からプログラム開発まで!様々なスキルを持ったメンバーが登録しています【@SOHO】 |