|
|
time_event.c説明を見る。00001 /* 00002 * TOPPERS/FDMP Kernel 00003 * Toyohashi Open Platform for Embedded Real-Time Systems/ 00004 * Function Distributed Multiprocessor Kernel 00005 * 00006 * Copyright (C) 2000-2004 by Embedded and Real-Time Systems Laboratory 00007 * Toyohashi Univ. of Technology, JAPAN 00008 * Copyright (C) 2005-2006 by Embedded and Real-Time Systems Laboratory 00009 * Graduate School of Information Science, Nagoya Univ., JAPAN 00010 * 00011 * 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 00012 * によって公表されている GNU General Public License の Version 2 に記 00013 * 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア 00014 * を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, 00015 * 利用と呼ぶ)することを無償で許諾する. 00016 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 00017 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー 00018 * スコード中に含まれていること. 00019 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 00020 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 00021 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 00022 * の無保証規定を掲載すること. 00023 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 00024 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ 00025 * と. 00026 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 00027 * 作権表示,この利用条件および下記の無保証規定を掲載すること. 00028 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに 00029 * 報告すること. 00030 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 00031 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. 00032 * 00033 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お 00034 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も 00035 * 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 00036 * 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. 00037 * 00038 * @(#) $Id: time_event.c,v 1.3 2006/03/14 04:37:54 honda Exp $ 00039 */ 00040 00048 #include "fdmp_kernel.h" 00049 #include "check.h" 00050 #include "class.h" 00051 #include "time_event.h" 00052 00053 00054 /* 00055 * タイムイベントヒープ操作マクロ 00056 */ 00057 #define PARENT(index) ((index) >> 1) /* 親ノードを求める */ 00058 #define LCHILD(index) ((index) << 1) /* 右の子ノードを求める */ 00059 #define TMEVT_NODE(ccb, index) ((ccb->p_tmevt_heap)[(index) - 1]) 00060 00061 /* 00062 * イベント発生時刻比較マクロ 00063 * 00064 * イベント発生時刻は,current_time からの相対値で比較する.すなわち, 00065 * current_time を最小値(最も近い時刻),current_time - 1 が最大値 00066 * (最も遠い時刻)とみなして比較する. 00067 */ 00068 #define EVTTIM_LT(t1, t2) (((t1) - current_time) < ((t2) - current_time)) 00069 #define EVTTIM_LE(t1, t2) (((t1) - current_time) <= ((t2) - current_time)) 00070 00071 #ifdef __tmeini 00072 00076 SYSTIM systim_offset; 00077 00083 SYSTIM current_time; 00084 00088 SYSTIM next_time; 00089 00090 /* 00091 * システム時刻積算用変数(単位: 1/TIM_DENOミリ秒) 00092 */ 00093 #if TIC_DENO != 1 00094 UINT next_subtime; 00095 #endif /* TIC_DENO != 1 */ 00096 00100 UINT last_index; 00101 00106 void 00107 tmevt_initialize() 00108 { 00109 systim_offset = 0; 00110 current_time = 0; 00111 #if TIC_DENO == 1 00112 next_time = current_time + TIC_NUME; 00113 #else /* TIC_DENO == 1 */ 00114 next_subtime += TIC_NUME; 00115 next_time = current_time + next_subtime / TIC_DENO; 00116 next_subtime %= TIC_DENO; 00117 #endif /* TIC_DENO == 1 */ 00118 last_index = 0; 00119 00120 my_local_exccb->p_tmevt_heap = &tmevt_heap[0]; 00121 my_local_exccb->p_last_index = &last_index; 00122 } 00123 00124 #endif /* __tmeini */ 00125 00133 #ifdef __tmeup 00134 00135 UINT 00136 tmevt_up(CCB *ccb, UINT index, EVTTIM time) 00137 { 00138 UINT parent; 00139 00140 while (index > 1) { 00141 /* 00142 * 親ノードのイベント発生時刻の方が早い(または同じ) 00143 * ならば,index が挿入位置なのでループを抜ける. 00144 */ 00145 parent = PARENT(index); 00146 if (EVTTIM_LE(TMEVT_NODE(ccb, parent).time, time)) { 00147 break; 00148 } 00149 00150 /* 00151 * 親ノードを index の位置に移動させる. 00152 */ 00153 TMEVT_NODE(ccb, index) = TMEVT_NODE(ccb, parent); 00154 TMEVT_NODE(ccb, index).tmevtb->index = index; 00155 00156 /* 00157 * index を親ノードの位置に更新. 00158 */ 00159 index = parent; 00160 } 00161 return(index); 00162 } 00163 00164 #endif /* __tmeup */ 00165 00173 #ifdef __tmedown 00174 00175 UINT 00176 tmevt_down(CCB *ccb, UINT index, EVTTIM time) 00177 { 00178 UINT child; 00179 00180 while ((child = LCHILD(index)) <= *ccb->p_last_index) { 00181 /* 00182 * 左右の子ノードのイベント発生時刻を比較し,早い方の 00183 * 子ノードの位置を child に設定する.以下の子ノード 00184 * は,ここで選ばれた方の子ノードのこと. 00185 */ 00186 if (child + 1 <= *ccb->p_last_index 00187 && EVTTIM_LT(TMEVT_NODE(ccb, child + 1).time, 00188 TMEVT_NODE(ccb, child).time)) { 00189 child = child + 1; 00190 } 00191 00192 /* 00193 * 子ノードのイベント発生時刻の方が遅い(または同じ) 00194 * ならば,index が挿入位置なのでループを抜ける. 00195 */ 00196 if (EVTTIM_LE(time, TMEVT_NODE(ccb, child).time)) { 00197 break; 00198 } 00199 00200 /* 00201 * 子ノードを index の位置に移動させる. 00202 */ 00203 TMEVT_NODE(ccb, index) = TMEVT_NODE(ccb, child); 00204 TMEVT_NODE(ccb, index).tmevtb->index = index; 00205 00206 /* 00207 * index を子ノードの位置に更新. 00208 */ 00209 index = child; 00210 } 00211 return(index); 00212 } 00213 00214 #endif /* __tmedown */ 00215 00222 #ifdef __tmeins 00223 00224 void 00225 tmevtb_insert(CCB *ccb, TMEVTB *tmevtb, EVTTIM time) 00226 { 00227 UINT index; 00228 00229 /* 00230 * last_index をインクリメントし,そこから上に挿入位置を探す. 00231 */ 00232 index = tmevt_up((CCB*)ccb, ++(*ccb->p_last_index), time); 00233 00234 /* 00235 * タイムイベントを index の位置に挿入する. 00236 */ 00237 TMEVT_NODE(ccb, index).time = time; 00238 TMEVT_NODE(ccb, index).tmevtb = tmevtb; 00239 tmevtb->index = index; 00240 } 00241 00242 #endif /* __tmeins */ 00243 00247 #ifdef __tmedel 00248 00249 void 00250 tmevtb_delete(CCB *ccb, TMEVTB *tmevtb) 00251 { 00252 UINT index = tmevtb->index; 00253 UINT parent; 00254 EVTTIM event_time = TMEVT_NODE(ccb, *ccb->p_last_index).time; 00255 00256 /* 00257 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00258 */ 00259 if (--*ccb->p_last_index == 0) { 00260 return; 00261 } 00262 00263 /* 00264 * 削除したノードの位置に最後のノード(last_index + 1 の位置 00265 * のノード)を挿入し,それを適切な位置へ移動させる.実際には, 00266 * 最後のノードを実際に挿入するのではなく,削除したノードの位 00267 * 置が空ノードになるので,最後のノードを挿入すべき位置へ向け 00268 * て空ノードを移動させる. 00269 * 最後のノードのイベント発生時刻が,削除したノードの親ノード 00270 * のイベント発生時刻より前の場合には,上に向かって挿入位置を 00271 * 探す.そうでない場合には,下に向かって探す. 00272 */ 00273 if (index > 1 && EVTTIM_LT(event_time, 00274 TMEVT_NODE(ccb, parent = PARENT(index)).time)) { 00275 /* 00276 * 親ノードを index の位置に移動させる. 00277 */ 00278 TMEVT_NODE(ccb, index) = TMEVT_NODE(ccb, parent); 00279 TMEVT_NODE(ccb, index).tmevtb->index = index; 00280 00281 /* 00282 * 削除したノードの親ノードから上に向かって挿入位置を 00283 * 探す. 00284 */ 00285 index = tmevt_up(ccb, parent, event_time); 00286 } 00287 else { 00288 /* 00289 * 削除したノードから下に向かって挿入位置を探す. 00290 */ 00291 index = tmevt_down(ccb, index, event_time); 00292 } 00293 00294 /* 00295 * 最後のノードを index の位置に挿入する. 00296 */ 00297 TMEVT_NODE(ccb, index) = TMEVT_NODE(ccb, *ccb->p_last_index + 1); 00298 TMEVT_NODE(ccb, index).tmevtb->index = index; 00299 } 00300 00301 #endif /* __tmedel */ 00302 00306 Inline void 00307 tmevtb_delete_top() 00308 { 00309 UINT index; 00310 EVTTIM event_time = TMEVT_NODE(my_local_ccb, last_index).time; 00311 00312 /* 00313 * 削除によりタイムイベントヒープが空になる場合は何もしない. 00314 */ 00315 if (--last_index == 0) { 00316 return; 00317 } 00318 00319 /* 00320 * ルートノードに最後のノード(last_index + 1 の位置のノード) 00321 * を挿入し,それを適切な位置へ移動させる.実際には,最後のノー 00322 * ドを実際に挿入するのではなく,ルートノードが空ノードになる 00323 * ので,最後のノードを挿入すべき位置へ向けて空ノードを移動さ 00324 * せる. 00325 */ 00326 index = tmevt_down(my_local_ccb, 1, event_time); 00327 00328 /* 00329 * 最後のノードを index の位置に挿入する. 00330 */ 00331 TMEVT_NODE(my_local_ccb, index) = TMEVT_NODE(my_local_ccb, last_index + 1); 00332 TMEVT_NODE(my_local_ccb, index).tmevtb->index = index; 00333 } 00334 00342 #ifdef __isig_tim 00343 00344 SYSCALL ER 00345 isig_tim() 00346 { 00347 TMEVTB *tmevtb; 00348 ER ercd; 00349 00350 LOG_ISIG_TIM_ENTER(); 00351 CHECK_INTCTX_UNL(); 00352 00353 retry: 00354 I_ACQUIRE_LOCK(my_local_ccb->tsk_lock); 00355 /* 00356 * next_time よりイベント発生時刻の早い(または同じ)タイムイ 00357 * ベントを,タイムイベントヒープから削除し,コールバック関数 00358 * を呼び出す. 00359 */ 00360 while (last_index > 0 00361 && EVTTIM_LE(TMEVT_NODE(my_local_ccb, 1).time, next_time)) { 00362 tmevtb = TMEVT_NODE(my_local_ccb, 1).tmevtb; 00363 tmevtb_delete_top(); 00364 (*(tmevtb->callback))(tmevtb->arg); 00365 00366 /* 00367 * I_RELEASE_LOCK()で割込みが許可されるため,ここで優先度 00368 * の高い割込みを受け付ける. 00369 * I_ACQUIRE_LOCK()では,retryに戻る可能性があるが問題ない 00370 */ 00371 I_RELEASE_LOCK(my_local_ccb->tsk_lock); 00372 I_ACQUIRE_LOCK(my_local_ccb->tsk_lock); 00373 } 00374 /* 00375 * current_time を更新する. 00376 */ 00377 current_time = next_time; 00378 00379 /* 00380 * next_time,next_subtime を更新する. 00381 */ 00382 #if TIC_DENO == 1 00383 next_time = current_time + TIC_NUME; 00384 #else /* TIC_DENO == 1 */ 00385 next_subtime += TIC_NUME; 00386 next_time = current_time + next_subtime / TIC_DENO; 00387 next_subtime %= TIC_DENO; 00388 #endif /* TIC_DENO == 1 */ 00389 I_RELEASE_LOCK(my_local_ccb->tsk_lock); 00390 ercd = E_OK; 00391 00392 exit: 00393 LOG_ISIG_TIM_LEAVE(ercd); 00394 return(ercd); 00395 } 00396 00397 #endif /* __isig_tim */ Copyright © 2006 by TAKAGI Nobuhisa. このページは Mon Apr 3 23:49:13 2006 に Doxygen によって生成されました。 |