task_manage.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: task_manage.c,v 1.5 2006/03/14 04:37:54 honda Exp $
00039  */
00040 
00045 #include "fdmp_kernel.h"
00046 #include "check.h"
00047 #include "task.h"
00048 #include "wait.h"
00049 
00053 #ifdef __act_tsk
00054 
00055 SYSCALL ER
00056 act_tsk(ID tskid)
00057 {
00058     TCB     *tcb;
00059     ER      ercd;
00060     CCB     *ccb;
00061     BOOL    dspreq = FALSE;
00062  
00063     LOG_ACT_TSK_ENTER(tskid);
00064     CHECK_TSKCTX_UNL();
00065     ccb = T_CHECK_CLSID_CCB(tskid);
00066     tskid = remove_clsid(tskid);
00067     CHECK_TSKID_SELF(ccb, tskid);
00068     tcb = get_tcb_self(ccb, tskid);
00069 
00070   retry:
00071     T_ACQUIRE_LOCK(ccb->tsk_lock);
00072     if (TSTAT_DORMANT(tcb->tstat)) {
00073         if (make_active(ccb, tcb)) {
00074             dspreq = dispatch_request(ccb->prcid);
00075         }
00076         ercd = E_OK;
00077     }
00078     else if (!(tcb->actcnt)) {
00079         tcb->actcnt = TRUE;
00080         ercd = E_OK;
00081     }
00082     else {
00083         ercd = E_QOVR;
00084     }
00085     T_RELEASE_LOCK_AND_DISPATCH(ccb->tsk_lock, dspreq);
00086 
00087   exit:
00088     LOG_ACT_TSK_LEAVE(ercd);
00089     return(ercd);
00090 }
00091 
00092 #endif /* __act_tsk */
00093 
00097 #ifdef __iact_tsk
00098 
00099 SYSCALL ER
00100 iact_tsk(ID tskid)
00101 {
00102     TCB     *tcb;
00103     ER      ercd;
00104     CCB     *ccb;
00105 
00106     LOG_IACT_TSK_ENTER(tskid);
00107     CHECK_INTCTX_UNL();
00108     ccb = I_CHECK_CLSID_CCB(tskid);
00109     tskid = remove_clsid(tskid);
00110     CHECK_TSKID(ccb, tskid);
00111     tcb = get_tcb(ccb, tskid);
00112 
00113   retry:
00114     I_ACQUIRE_LOCK(ccb->tsk_lock);
00115     if (TSTAT_DORMANT(tcb->tstat)) {
00116         if (make_active(ccb, tcb)) {
00117             if (dispatch_request(ccb->prcid)) {
00118                 reqflg = TRUE;
00119             }
00120         }
00121         ercd = E_OK;
00122     }
00123     else if (!(tcb->actcnt)) {
00124         tcb->actcnt = TRUE;
00125         ercd = E_OK;
00126     }
00127     else {
00128         ercd = E_QOVR;
00129     }
00130     I_RELEASE_LOCK(ccb->tsk_lock);
00131 
00132   exit:
00133     LOG_IACT_TSK_LEAVE(ercd);
00134     return(ercd);
00135 }
00136 
00137 #endif /* __iact_tsk */
00138 
00142 #ifdef __can_act
00143 
00144 SYSCALL ER_UINT
00145 can_act(ID tskid)
00146 {
00147     TCB     *tcb;
00148     ER_UINT ercd;
00149     CCB     *ccb;
00150 
00151     LOG_CAN_ACT_ENTER(tskid);
00152     CHECK_TSKCTX_UNL(); 
00153     ccb = T_CHECK_CLSID_CCB(tskid);
00154     tskid = remove_clsid(tskid);
00155     CHECK_TSKID_SELF(ccb, tskid);
00156     tcb = get_tcb_self(ccb, tskid);
00157         
00158   retry:    
00159     T_ACQUIRE_LOCK(ccb->tsk_lock);
00160     if (tcb == runtsk && tcb->terflg) {
00161         ercd = E_OBJ;
00162     }
00163     else {
00164         ercd = tcb->actcnt ? 1 : 0; 
00165         tcb->actcnt = FALSE;
00166     }
00167     T_RELEASE_LOCK(ccb->tsk_lock);
00168 
00169   exit:
00170     LOG_CAN_ACT_LEAVE(ercd);
00171     return(ercd);
00172 }
00173 
00174 #endif /* __can_act */
00175 
00180 #ifdef __ext_tsk
00181 
00182 SYSCALL void
00183 ext_tsk(void)
00184 {
00185     LOG_EXT_TSK_ENTER();
00186 
00187     if (sense_context()) {
00188         /*
00189          *  非タスクコンテキストから ext_tsk が呼ばれた場合,
00190          *  システムログにエラーを記録し,そのまま実行を続ける.
00191          *  その結果,強制的にタスクコンテキストに切り換えて,
00192          *  実行状態のタスクを終了させることになる.カーネルは
00193          *  そのまま実行を継続するが,ターゲットによっては,非
00194          *  タスクコンテキスト用のスタックにゴミが残ったり,割
00195          *  込みハンドラのネスト数の管理に矛盾が生じたりする場
00196          *  合がある.
00197          */
00198         syslog_0(LOG_ALERT,
00199             "ext_tsk is called from non-task contexts.");
00200     }
00201 
00202   retry:
00203     if (sense_lock()) {
00204         /*
00205          *  CPUロック状態で ext_tsk が呼ばれた場合は,CPUロック
00206          *  を解除してからタスクを終了する.実装上は,サービス
00207          *  コール内でのCPUロックを省略すればよいだけ.
00208          */
00209         syslog_0(LOG_WARNING,
00210             "ext_tsk is called from CPU locked state.");
00211     }
00212     else {
00213         if (sense_context()) {
00214             i_lock_cpu();
00215         }
00216         else  {
00217             t_lock_cpu();
00218         }
00219     }
00220 
00221     if (ACQUIRE_LOCK(runccb->tsk_lock)) {
00222         if (sense_context()) {
00223             i_unlock_cpu();
00224         }
00225         else  {
00226             t_unlock_cpu();
00227         }       
00228         goto retry;
00229     }
00230     
00231     if (!(enadsp)) {
00232         /*
00233          *  ディスパッチ禁止状態で ext_tsk が呼ばれた場合は,
00234          *  ディスパッチ許可状態にしてからタスクを終了する.
00235          */
00236         syslog_0(LOG_WARNING,
00237             "ext_tsk is called from dispatch disabled state.");
00238         enadsp = TRUE;
00239     }
00240 
00246     if (!(runtsk->terflg)) {
00247         make_non_runnable(runccb, runtsk);
00248         make_dormant(runtsk);
00249         if (runtsk->actcnt) {
00250             runtsk->actcnt = FALSE;
00251             make_active(runccb, runtsk);
00252         }       
00253     }
00254     RELEASE_LOCK(runccb->tsk_lock);
00255     exit_and_dispatch();
00256 }
00257 
00258 #endif /* __ext_tsk */
00259 
00263 #ifdef __ter_tsk
00264 
00265 SYSCALL ER
00266 ter_tsk(ID tskid)
00267 {
00268     TCB     *tcb;
00269     CCB     *ccb, *occb;
00270     UINT    tstat;
00271     ER      ercd;
00272     BOOL    dspreq = FALSE;
00273 
00274     LOG_TER_TSK_ENTER(tskid);
00275     CHECK_TSKCTX_UNL();
00276     ccb = T_CHECK_CLSID_CCB(tskid);
00277     tskid = remove_clsid(tskid);
00278     CHECK_TSKID(ccb, tskid);
00279     tcb = get_tcb(ccb, tskid);
00280     CHECK_NONSELF(tcb);
00281 
00282   retry:    
00283     T_ACQUIRE_LOCK(ccb->tsk_lock);
00284     if (TSTAT_DORMANT(tstat = tcb->tstat)) {
00285         ercd = E_OBJ;
00286     }
00287     else {
00288         if (TSTAT_RUNNABLE(tstat)) {
00289             if (make_non_runnable(ccb, tcb)) {
00290                 /*
00291                  * 対象タスクが他プロセッサ上のタスクかつRUNNABLEの場合,
00292                  * RUN状態の可能性があるため,ディスパッチ要求を出す 
00293                  */
00294                 assert(ccb != my_local_ccb);
00295                 dspreq = TRUE;
00296             }
00297         }
00298         else if (TSTAT_WAITING(tstat)) {
00299             if ((tstat & TS_WAIT_WOBJCB) == 0) {
00300                 wait_cancel(ccb, tcb);
00301             }
00302             else {              
00303                 /*
00304                  * オブジェクト待ちの場合
00305                  */
00306                 /*
00307                  * 
00308                  * デットロックを回避のため,一度ロックを手放した状態で
00309                  * 二つ以上のter_tskが競合した場合に一回分しか実行されない可能性
00310                  * がある.そこで,既に他のter_tskが発行されていれば(pend_tertskがTRUE)
00311                  * actcntの操作のみを行いリターンする.
00312                  */ 
00313                 if (tcb->pend_tertsk) {
00314                     if (tcb->actcnt) {
00315                         tcb->actcnt = FALSE;
00316                         ercd = E_OK;
00317                     }
00318                     else {
00319                         ercd = E_OBJ;
00320                     }
00321                     RELEASE_LOCK(ccb->tsk_lock);
00322                     goto exit;
00323                 }
00324                 
00325                 /*
00326                  * デッドロック回避を行う 
00327                  * 待ち対象になっているオブジェクトのCCBを取得し,
00328                  * タスク強制終了保留フラグのセットから,
00329                  * 一度タスクロックを開放(プロセッサロックは開放しない)する 
00330                  */
00331                 occb = ((WINFO_WOBJ *)(tcb->winfo))->ccb;
00332                 tcb->pend_tertsk = TRUE;
00333                 RELEASE_LOCK(ccb->tsk_lock);
00334 
00335                 /*
00336                  * あらためて
00337                  *   オブジェクトロック -> タスクロック
00338                  * の順でロックを取得
00339                  */
00340                 if (ACQUIRE_LOCK(occb->obj_lock)) {
00341                     t_unlock_cpu();
00342                     goto retry;
00343                 }           
00344                 T_ACQUIRE_NESTED_LOCK(ccb->tsk_lock, occb->obj_lock);
00345 
00346                 /* 既に他の箇所で終了処理がなされたかチェック */
00347                 if (!(tcb->pend_tertsk)){
00348                     /* 既に他の箇所で終了処理がなされた */
00349                     T_RELEASE_NESTED_LOCK(ccb->tsk_lock, occb->obj_lock);
00350                     T_RELEASE_LOCK(occb->obj_lock);
00351                     ercd = E_OK;
00352                     goto exit;
00353                 }               
00354                 wait_cancel(ccb, tcb);
00355                 RELEASE_LOCK(occb->obj_lock);
00356             }
00357         }       
00358         /*
00359          * TCBを解放して,terflgをTRUEにする.
00360          */ 
00361         make_dormant(tcb);     
00362         tcb->terflg = TRUE;
00363         if (tcb->actcnt) {
00364             tcb->actcnt = FALSE;
00365             if (make_active(ccb, tcb)) {
00366                 dspreq = TRUE;
00367             }
00368         }
00369         if (dspreq){
00370             dspreq = dispatch_request(ccb->prcid);
00371         }       
00372         ercd = E_OK;
00373     }
00374     T_RELEASE_LOCK_AND_DISPATCH(ccb->tsk_lock, dspreq);
00375 
00376   exit:
00377     LOG_TER_TSK_LEAVE(ercd);
00378     return(ercd);
00379 }
00380 
00381 #endif /* __ter_tsk */
00382 
00386 #ifdef __chg_pri
00387 
00388 SYSCALL ER
00389 chg_pri(ID tskid, PRI tskpri)
00390 {
00391     CCB     *ccb, *occb;
00392     TCB     *tcb;  
00393     UINT    newpri;
00394     UINT    tstat;
00395     ER      ercd;
00396     BOOL    dspreq = FALSE;
00397 
00398     LOG_CHG_PRI_ENTER(tskid, tskpri);
00399     CHECK_TSKCTX_UNL();
00400     ccb = T_CHECK_CLSID_CCB(tskid);
00401     tskid = remove_clsid(tskid);
00402     CHECK_TSKID_SELF(ccb, tskid);
00403     CHECK_TPRI_INI(tskpri);
00404     tcb = get_tcb_self(ccb, tskid);
00405     newpri = (tskpri == TPRI_INI) ? tcb->tinib->ipriority
00406                     : INT_PRIORITY(tskpri);
00407 
00408   retry:
00409     T_ACQUIRE_LOCK(ccb->tsk_lock);
00410     if (TSTAT_DORMANT(tstat = tcb->tstat) || (tcb == runtsk && tcb->terflg)) {
00411         ercd = E_OBJ;
00412     }
00413     else if (TSTAT_RUNNABLE(tstat)) {
00414         if (change_priority(ccb, tcb, newpri)) {
00415             dspreq = dispatch_request(ccb->prcid);
00416         }
00417         ercd = E_OK;
00418     }
00419     else {
00420         if ((tstat & TS_WAIT_WOBJCB) == 0) {
00421             tcb->priority = newpri;
00422         }
00423         else {
00424             /*
00425              * オブジェクト待ちの場合,デッドロック回避を行う
00426              */
00427             
00428             /*
00429              * 優先度変更保留セットし,
00430              * 待ち対象になっているオブジェクトのCCBを取得から,
00431              * 一度タスクロックを開放(プロセッサロックは開放しない)する 
00432              */
00433             occb = ((WINFO_WOBJ *)(tcb->winfo))->ccb;
00434             tcb->pend_chgpri = TRUE;
00435             tcb->pend_newpri = newpri;
00436             RELEASE_LOCK(ccb->tsk_lock);
00437 
00438             /*
00439              * あらためて
00440              *   オブジェクトロック -> タスクロック
00441              * の順でロックを取得
00442              */
00443             if (ACQUIRE_LOCK(occb->obj_lock)) {
00444                 t_unlock_cpu();
00445                 goto retry;
00446             }           
00447             T_ACQUIRE_NESTED_LOCK(ccb->tsk_lock, occb->obj_lock);
00448 
00449             /* タスクの状態が変化していないかチェック */
00450             if (!(tcb->pend_chgpri)) {
00451                 /* 既に他の箇所で優先度変更処理がなされた */
00452                 T_RELEASE_NESTED_LOCK(ccb->tsk_lock, occb->obj_lock);
00453                 T_RELEASE_LOCK(occb->obj_lock);
00454                 ercd = E_OK;
00455                 goto exit;
00456             }
00457             tcb->priority = tcb->pend_newpri;
00458             tcb->pend_chgpri = FALSE;
00459             wobj_change_priority(((WINFO_WOBJ *)(tcb->winfo))
00460                              ->wobjcb, tcb);
00461             RELEASE_LOCK(occb->obj_lock);
00462         }
00463         ercd = E_OK;
00464     }
00465     T_RELEASE_LOCK_AND_DISPATCH(ccb->tsk_lock, dspreq);
00466 
00467   exit:
00468     LOG_CHG_PRI_LEAVE(ercd);
00469     return(ercd);
00470 }
00471 
00472 #endif /* __chg_pri */
00473 
00477 #ifdef __get_pri
00478 
00479 SYSCALL ER
00480 get_pri(ID tskid, PRI *p_tskpri)
00481 {
00482     CCB *ccb;
00483     TCB *tcb;
00484     ER  ercd;
00485 
00486     LOG_GET_PRI_ENTER(tskid, p_tskpri);
00487     CHECK_TSKCTX_UNL();
00488     ccb = T_CHECK_CLSID_CCB(tskid);
00489     tskid = remove_clsid(tskid);
00490     CHECK_TSKID_SELF(ccb, tskid);
00491     tcb = get_tcb_self(ccb, tskid);
00492 
00493   retry:
00494     T_ACQUIRE_LOCK(ccb->tsk_lock);
00495     if (TSTAT_DORMANT(tcb->tstat) || (tcb == runtsk && tcb->terflg)) {
00496         ercd = E_OBJ;
00497     }
00498     else {
00499         *p_tskpri = EXT_TSKPRI(tcb->priority);
00500         ercd = E_OK;
00501     }
00502     T_RELEASE_LOCK(ccb->tsk_lock);
00503 
00504   exit:
00505     LOG_GET_PRI_LEAVE(ercd, *p_tskpri);
00506     return(ercd);
00507 }
00508 
00509 #endif /* __get_pri */

Copyright © 2006 by TAKAGI Nobuhisa.
このページは Mon Apr 3 23:49:13 2006 に Doxygen によって生成されました。