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 によって生成されました。