/* * タスク管理モジュールの初期化 */ void initialize_task(void) { uint_t i, j; TCB *p_tcb; p_runtsk = NULL; p_schedtsk = NULL; enadsp = true; dspflg = true; for (i = 0; i < tnum_tsk; i++) { j = INDEX_TSK(torder_table[i]); p_tcb = &(tcb_table[j]); p_tcb->p_tinib = &(tinib_table[j]); if (p_tcb->p_tinib->domid == TDOM_KERNEL) { p_tcb->p_dominib = &dominib_kernel; } else { p_tcb->p_dominib = get_dominib(p_tcb->p_tinib->domid); } p_tcb->p_schedcb = p_tcb->p_dominib->p_schedcb; p_tcb->actque = false; make_dormant(p_tcb); p_tcb->p_lastmtx = NULL; if ((p_tcb->p_tinib->tskatr & TA_ACT) != 0U) { make_active(p_tcb); } } }
/* * タスク管理モジュールの初期化 */ void initialize_task(void) { uint_t i, j; TCB *p_tcb; p_runtsk = NULL; p_schedtsk = NULL; reqflg = false; ipmflg = true; disdsp = false; dspflg = true; for (i = 0; i < TNUM_TPRI; i++) { queue_initialize(&(ready_queue[i])); } ready_primap = 0U; for (i = 0; i < tnum_tsk; i++) { j = INDEX_TSK(torder_table[i]); p_tcb = &(tcb_table[j]); p_tcb->p_tinib = &(tinib_table[j]); p_tcb->actque = false; make_dormant(p_tcb); queue_initialize(&(p_tcb->mutex_queue)); if ((p_tcb->p_tinib->tskatr & TA_ACT) != 0U) { (void) make_active(p_tcb); } } }
/* * Termination of other task */ SYSCALL ER _tk_ter_tsk( ID tskid ) { TCB *tcb; TSTAT state; ER ercd = E_OK; CHECK_TSKID(tskid); CHECK_NONSELF(tskid); tcb = get_tcb(tskid); BEGIN_CRITICAL_SECTION; state = (TSTAT)tcb->state; if ( !task_alive(state) ) { ercd = ( state == TS_NONEXIST )? E_NOEXS: E_OBJ; } else if ( tcb->klocked ) { /* Normally, it does not become this state. * When the state is page-in wait in the virtual memory * system and when trying to terminate any task, * it becomes this state. */ ercd = E_OBJ; } else { _ter_tsk(tcb); make_dormant(tcb); } END_CRITICAL_SECTION; return ercd; }
/* * task management module initialization */ void initialize_task(void) { uint_t i, j; TCB *p_tcb; p_runtsk = p_schedtsk = NULL; reqflg = false; ipmflg = true; disdsp = false; dspflg = true; for (i = 0; i < TNUM_TPRI; i++) { queue_initialize(&(ready_queue[i])); } #ifdef PRIMAP_LEVEL_1 ready_primap = 0U; #else /* PRIMAP_LEVEL_1 */ ready_primap1 = 0U; for (i = 0; i < TNUM_PRIMAP2; i++) { ready_primap2[i] = 0U; } #endif /* PRIMAP_LEVEL_1 */ for (i = 0; i < tnum_tsk; i++) { j = INDEX_TSK(torder_table[i]); p_tcb = &(tcb_table[j]); p_tcb->p_tinib = &(tinib_table[j]); p_tcb->actque = false; make_dormant(p_tcb); if ((p_tcb->p_tinib->tskatr & TA_ACT) != 0U) { make_active(p_tcb); } } }
ER ter_tsk(ID tskid) { TCB *p_tcb; bool_t dspreq = false; ER ercd; LOG_TER_TSK_ENTER(tskid); CHECK_TSKCTX_UNL(); CHECK_TSKID(tskid); p_tcb = get_tcb(tskid); CHECK_NONSELF(p_tcb); t_lock_cpu(); if (p_tcb->p_tinib->tskatr == TA_NOEXS) { ercd = E_NOEXS; } else if (VIOLATE_ACPTN(p_tcb->p_tinib->acvct.acptn2)) { ercd = E_OACV; } else if (TSTAT_DORMANT(p_tcb->tstat)) { ercd = E_OBJ; } else { if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * p_tcbは自タスクでないため,(シングルプロセッサでは)実 * 行状態でなく,make_non_runnable(p_tcb)でタスクディスパッ * チが必要になることはない. */ (void) make_non_runnable(p_tcb); } else if (TSTAT_WAITING(p_tcb->tstat)) { wait_dequeue_wobj(p_tcb); wait_dequeue_tmevtb(p_tcb); } if (!queue_empty(&(p_tcb->mutex_queue))) { if ((*mtxhook_release_all)(p_tcb)) { dspreq = true; } } make_dormant(p_tcb); if (p_tcb->actque) { p_tcb->actque = false; if (make_active(p_tcb)) { dspreq = true; } } if (dspreq) { dispatch(); } ercd = E_OK; } t_unlock_cpu(); error_exit: LOG_TER_TSK_LEAVE(ercd); return(ercd); }
ER ext_tsk(void) { ER ercd; LOG_EXT_TSK_ENTER(); CHECK_TSKCTX(); if (t_sense_lock()) { /* * CPUロック状態でext_tskが呼ばれた場合は,CPUロックを解除し * てからタスクを終了する.実装上は,サービスコール内でのCPU * ロックを省略すればよいだけ. */ } else { t_lock_cpu(); } if (disdsp) { /* * ディスパッチ禁止状態でext_tskが呼ばれた場合は,ディスパッ * チ許可状態にしてからタスクを終了する. */ disdsp = false; } if (!ipmflg) { /* * 割込み優先度マスク(IPM)がTIPM_ENAALL以外の状態でext_tsk * が呼ばれた場合は,IPMをTIPM_ENAALLにしてからタスクを終了す * る. */ t_set_ipm(TIPM_ENAALL); ipmflg = true; } dspflg = true; (void) make_non_runnable(p_runtsk); if (!queue_empty(&(p_runtsk->mutex_queue))) { (void) (*mtxhook_release_all)(p_runtsk); } #ifdef TOPPERS_SUPPORT_OVRHDR ovrtimer_stop(); #endif /* TOPPERS_SUPPORT_OVRHDR */ make_dormant(p_runtsk); if (p_runtsk->actque) { p_runtsk->actque = false; (void) make_active(p_runtsk); } exit_and_dispatch(); ercd = E_SYS; error_exit: LOG_EXT_TSK_LEAVE(ercd); return(ercd); }
ER ext_tsk(void) { ER ercd; LOG_EXT_TSK_ENTER(); CHECK_TSKCTX(); if (t_sense_lock()) { /* * CPUロック状態でext_tskが呼ばれた場合は,CPUロックを解除し * てからタスクを終了する.実装上は,サービスコール内でのCPU * ロックを省略すればよいだけ. */ } else { t_lock_cpu(); } if (disdsp) { /* * ディスパッチ禁止状態でext_tskが呼ばれた場合は,ディスパッ * チ許可状態にしてからタスクを終了する. */ disdsp = false; } if (t_get_ipm() != TIPM_ENAALL) { /* * 割込み優先度マスク(IPM)がTIPM_ENAALL以外の状態でext_tsk * が呼ばれた場合は,IPMをTIPM_ENAALLにしてからタスクを終了す * る. */ t_set_ipm(TIPM_ENAALL); } dspflg = true; (void) make_non_runnable(p_runtsk); make_dormant(p_runtsk); if (p_runtsk->actque) { p_runtsk->actque = false; (void) make_active(p_runtsk); } exit_and_dispatch(); return(E_SYS); error_exit: LOG_EXT_TSK_LEAVE(ercd); return(ercd); }
ER ter_tsk(ID tskid) { TCB *p_tcb; ER ercd; LOG_TER_TSK_ENTER(tskid); CHECK_TSKCTX_UNL(); CHECK_TSKID(tskid); p_tcb = get_tcb(tskid); CHECK_NONSELF(p_tcb); t_lock_cpu(); if (TSTAT_DORMANT(p_tcb->tstat)) { ercd = E_OBJ; } else { if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * p_tcbは自タスクでないため,(シングルプロセッサでは)実 * 行状態でなく,make_non_runnable(p_tcb)でタスクディスパッ * チが必要になることはない. */ (void) make_non_runnable(p_tcb); } else if (TSTAT_WAITING(p_tcb->tstat)) { wait_dequeue_wobj(p_tcb); wait_dequeue_tmevtb(p_tcb); } make_dormant(p_tcb); if (p_tcb->actque) { p_tcb->actque = false; if (make_active(p_tcb)) { dispatch(); } } ercd = E_OK; } t_unlock_cpu(); error_exit: LOG_TER_TSK_LEAVE(ercd); return(ercd); }
SYSCALL ER ter_tsk(ID tskid) { TCB *tcb; UINT tstat; ER ercd; LOG_TER_TSK_ENTER(tskid); CHECK_TSKCTX_UNL(); CHECK_TSKID(tskid); tcb = get_tcb(tskid); CHECK_NONSELF(tcb); t_lock_cpu(); if (TSTAT_DORMANT(tstat = tcb->tstat)) { ercd = E_OBJ; } else { if (TSTAT_RUNNABLE(tstat)) { make_non_runnable(tcb); } else if (TSTAT_WAITING(tstat)) { wait_cancel(tcb); } make_dormant(tcb); if (tcb->actcnt) { tcb->actcnt = FALSE; if (make_active(tcb)) { dispatch(); } } ercd = E_OK; } t_unlock_cpu(); exit: LOG_TER_TSK_LEAVE(ercd); return(ercd); }
/* * End its own task */ SYSCALL void _tk_ext_tsk( void ) { #ifdef DORMANT_STACK_SIZE /* To avoid destroying stack used in 'make_dormant', allocate the dummy area on the stack. */ volatile VB _dummy[DORMANT_STACK_SIZE]; MEMSET((void *)_dummy, 0xCC, DORMANT_STACK_SIZE); #endif /* Check context error */ #if CHK_CTX2 if ( in_indp() ) { #if USE_KERNEL_MESSAGE tm_putstring((UB*)"tk_ext_tsk was called in the task independent\n"); #endif tm_monitor(); /* To monitor */ } #endif #if CHK_CTX1 if ( in_ddsp() ) { #if USE_KERNEL_MESSAGE tm_putstring((UB*)"tk_ext_tsk was called in the dispatch disabled\n"); #endif } #endif DISABLE_INTERRUPT; _ter_tsk(ctxtsk); make_dormant(ctxtsk); force_dispatch(); /* No return */ #ifdef DORMANT_STACK_SIZE /* for WARNING */ _dummy[0] = 0; #endif }
ER_UINT acre_tsk(const T_CTSK *pk_ctsk) { TCB *p_tcb; TINIB *p_tinib; ATR tskatr; TASK task; PRI itskpri; size_t stksz; STK_T *stk; ER ercd; LOG_ACRE_TSK_ENTER(pk_ctsk); CHECK_TSKCTX_UNL(); tskatr = pk_ctsk->tskatr; task = pk_ctsk->task; itskpri = pk_ctsk->itskpri; stksz = pk_ctsk->stksz; stk = pk_ctsk->stk; CHECK_RSATR(tskatr, TA_ACT|TA_NOACTQUE|TARGET_TSKATR); CHECK_PAR(FUNC_ALIGN(task)); CHECK_PAR(FUNC_NONNULL(task)); CHECK_PAR(VALID_TPRI(itskpri)); CHECK_PAR(stksz >= TARGET_MIN_STKSZ); if (stk != NULL) { CHECK_PAR(STKSZ_ALIGN(stksz)); CHECK_PAR(STACK_ALIGN(stk)); } lock_cpu(); if (queue_empty(&free_tcb)) { ercd = E_NOID; } else { if (stk == NULL) { stk = kernel_malloc(ROUND_STK_T(stksz)); tskatr |= TA_MEMALLOC; } if (stk == NULL) { ercd = E_NOMEM; } else { p_tcb = ((TCB *) queue_delete_next(&free_tcb)); p_tinib = (TINIB *)(p_tcb->p_tinib); p_tinib->tskatr = tskatr; p_tinib->exinf = pk_ctsk->exinf; p_tinib->task = task; p_tinib->ipriority = INT_PRIORITY(itskpri); #ifdef USE_TSKINICTXB init_tskinictxb(&(p_tinib->tskinictxb), stksz, stk); #else /* USE_TSKINICTXB */ p_tinib->stksz = stksz; p_tinib->stk = stk; #endif /* USE_TSKINICTXB */ p_tcb->actque = false; make_dormant(p_tcb); if ((p_tcb->p_tinib->tskatr & TA_ACT) != 0U) { make_active(p_tcb); } ercd = TSKID(p_tcb); } } unlock_cpu(); error_exit: LOG_ACRE_TSK_LEAVE(ercd); return(ercd); }
/* * Create task */ SYSCALL ID _tk_cre_tsk P1( CONST T_CTSK *pk_ctsk ) { #if CHK_RSATR const ATR VALID_TSKATR = { /* Valid value of task attribute */ TA_HLNG |TA_SSTKSZ |TA_USERSTACK |TA_TASKSPACE |TA_RESID |TA_RNG3 |TA_FPU |TA_COP0 |TA_COP1 |TA_COP2 |TA_COP3 |TA_GP #if USE_OBJECT_NAME |TA_DSNAME #endif }; #endif TCB *tcb; INT stksz, sstksz, sysmode, resid; void *stack = NULL, *sstack; ER ercd; CHECK_RSATR(pk_ctsk->tskatr, VALID_TSKATR); CHECK_PRI(pk_ctsk->itskpri); CHECK_NOCOP(pk_ctsk->tskatr); #if USE_SINGLE_STACK CHECK_NOSPT((pk_ctsk->tskatr & TA_USERSTACK) == 0); #endif #if CHK_PAR if ( (pk_ctsk->tskatr & TA_USERSTACK) != 0 ) { CHECK_PAR((pk_ctsk->tskatr & TA_RNG3) != TA_RNG0); CHECK_PAR(pk_ctsk->stksz == 0); } else { CHECK_PAR(pk_ctsk->stksz >= 0); } if ( (pk_ctsk->tskatr & TA_TASKSPACE) != 0 ) { CHECK_PAR(pk_ctsk->lsid >= 0 && pk_ctsk->lsid <= MAX_LSID); } #endif if ( (pk_ctsk->tskatr & TA_RESID) != 0 ) { CHECK_RESID(pk_ctsk->resid); resid = pk_ctsk->resid; } else { resid = SYS_RESID; /* System resource group */ } if ( (pk_ctsk->tskatr & TA_SSTKSZ) != 0 ) { CHECK_PAR(pk_ctsk->sstksz >= MIN_SYS_STACK_SIZE); sstksz = pk_ctsk->sstksz; } else { sstksz = default_sstksz; } if ( (pk_ctsk->tskatr & TA_RNG3) == TA_RNG0 ) { sysmode = 1; sstksz += pk_ctsk->stksz; stksz = 0; } else { sysmode = 0; #if USE_SINGLE_STACK sstksz += pk_ctsk->stksz; stksz = 0; #else stksz = pk_ctsk->stksz; #endif } /* Adjust stack size by 8 bytes */ sstksz = (sstksz + 7) / 8 * 8; stksz = (stksz + 7) / 8 * 8; /* Allocate system stack area */ sstack = IAmalloc((UINT)sstksz, TA_RNG0); if ( sstack == NULL ) { return E_NOMEM; } if ( stksz > 0 ) { /* Allocate user stack area */ stack = IAmalloc((UINT)stksz, pk_ctsk->tskatr); if ( stack == NULL ) { IAfree(sstack, TA_RNG0); return E_NOMEM; } } BEGIN_CRITICAL_SECTION; /* Get control block from FreeQue */ tcb = (TCB*)QueRemoveNext(&free_tcb); if ( tcb == NULL ) { ercd = E_LIMIT; goto error_exit; } /* Initialize control block */ tcb->exinf = pk_ctsk->exinf; tcb->tskatr = pk_ctsk->tskatr; tcb->task = pk_ctsk->task; tcb->ipriority = (UB)int_priority(pk_ctsk->itskpri); tcb->resid = resid; tcb->stksz = stksz; tcb->sstksz = sstksz; #if USE_OBJECT_NAME if ( (pk_ctsk->tskatr & TA_DSNAME) != 0 ) { STRNCPY((char*)tcb->name, (char*)pk_ctsk->dsname, OBJECT_NAME_LENGTH); } #endif #if TA_GP /* Set global pointer */ if ( (pk_ctsk->tskatr & TA_GP) != 0 ) { gp = pk_ctsk->gp; } tcb->gp = gp; #endif /* Set stack pointer */ if ( stksz > 0 ) { tcb->istack = (VB*)stack + stksz; } else { tcb->istack = pk_ctsk->stkptr; } tcb->isstack = (VB*)sstack + sstksz - RESERVE_SSTACK(tcb->tskatr); /* Set initial value of task operation mode */ tcb->isysmode = (B)sysmode; tcb->sysmode = (H)sysmode; /* Set initial value of task space */ if ( (pk_ctsk->tskatr & TA_TASKSPACE) != 0 ) { tcb->tskctxb.uatb = pk_ctsk->uatb; tcb->tskctxb.lsid = pk_ctsk->lsid; } else { tcb->tskctxb.uatb = NULL; tcb->tskctxb.lsid = 0; /* Task Space */ } /* make it to DORMANT state */ make_dormant(tcb); ercd = tcb->tskid; error_exit: END_CRITICAL_SECTION; if ( ercd < E_OK ) { IAfree(sstack, TA_RNG0); if ( stksz > 0 ) { IAfree(stack, pk_ctsk->tskatr); } } return ercd; }
ER ter_tsk(ID tskid) { TCB *p_tcb; ER ercd = E_OK; bool_t dspreq = false; PCB *f_p_pcb; PCB *t_p_pcb; PCB *my_p_pcb; PCB *p_pcb; LOG_TER_TSK_ENTER(tskid); CHECK_TSKCTX_UNL(); CHECK_TSKID(tskid); p_tcb = get_tcb(tskid); t_lock_cpu(); retry: p_pcb = t_acquire_tsk_lock(p_tcb); my_p_pcb = get_my_p_pcb(); /* 自タスクを指定するとエラー */ if ((p_tcb) == my_p_pcb->p_runtsk) { ercd = E_ILUSE; release_tsk_lock(p_pcb); } /* 異なるプロセッサに割り付けられているタスクならエラーとする */ else if (p_pcb != my_p_pcb) { ercd = E_OBJ; release_tsk_lock(p_pcb); } else if (TSTAT_DORMANT(p_tcb->tstat)) { ercd = E_OBJ; release_tsk_lock(p_pcb); } else { if (!(TSTAT_WAITING(p_tcb->tstat) && TSTAT_WAIT_WOBJ(p_tcb->tstat))) { /* オブジェクト待ち以外の状態の場合 */ if ((p_tcb->actprc == TPRC_NONE) || (p_tcb->actprc == p_pcb->prcid)) { /* 再起動時のマイグレーションなし */ if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * 対象タスクが他プロセッサ上のタスクかつRUNNABLEの場合, * RUN状態の可能性があるため,ディスパッチ要求を出す必要があるが, * 本システムコールは同じプロセッサに割り付けられているタスクのみ * に発行可能であるので,ディスパッチ要求を出す必要はない. */ (void)make_non_runnable(p_tcb); } else if (TSTAT_WAITING(p_tcb->tstat)) { /* オブジェクト待ち以外の待ち状態の場合 */ wait_dequeue_tmevtb(p_tcb); } make_dormant(p_tcb); if (p_tcb->actque) { p_tcb->actque = false; p_tcb->actprc = TPRC_NONE; if (make_active(p_tcb)) { dspreq = dispatch_request(p_pcb); } } release_tsk_lock(p_pcb); if (dspreq) { dispatch(); } } else { /* 起動要求キューイングあり & 他プロセッサにマイグレーションあり */ /* 移動先のプロセッサのPCBを取得 */ t_p_pcb = get_mp_p_pcb(p_tcb->actprc); /* 一旦タスクロックを離す */ release_tsk_lock(p_pcb); /* * 現在割り付けられているプロセッサと移動先のプロセッサのタスク * ロックを取得 */ t_acquire_dual_tsk_lock(p_tcb, p_tcb->actprc, &p_pcb, &t_p_pcb); /* * マイグレーション先のプロセッサが変更された場合はリトライ * 対象タスクと自タスクが所属するプロセッサが異なる場合も * リトライする. */ if ((p_tcb->actprc != t_p_pcb->prcid) || (p_pcb != my_p_pcb)) { release_dual_tsk_lock(p_pcb, t_p_pcb); goto retry; } if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * 対象タスクが他プロセッサ上のタスクかつRUNNABLEの場合, * RUN状態の可能性があるため,ディスパッチ要求を出す必要があるが, * 本システムコールは同じプロセッサに割り付けられているタスクのみ * に発行可能であるので,ディスパッチ要求を出す必要はない. */ (void)make_non_runnable(p_tcb); } else if (TSTAT_WAITING(p_tcb->tstat)) { /* オブジェクト待ち以外の待ち状態の場合 */ wait_dequeue_tmevtb(p_tcb); } make_dormant(p_tcb); p_tcb->actque = false; p_tcb->actprc = TPRC_NONE; f_p_pcb = p_pcb; p_tcb->p_pcb = t_p_pcb; if (make_active(p_tcb)) { /* * 現在所属するプロセッサと同じプロセッサにマイグレー * ションする場合はここに来ないため,dispatch_request() * 戻り値はチェックしない. */ (void)dispatch_request(t_p_pcb); } release_dual_tsk_lock(f_p_pcb, t_p_pcb); } } else { /* オブジェクト待ち状態の場合 */ if ((p_tcb->actprc == TPRC_NONE) || (p_tcb->actprc == p_pcb->prcid)) { /* 再起動時のマイグレーションなし */ /* * デッドロック回避のため,ロックを取得し直す */ WOBJCB *p_wobjcb = p_tcb->p_wobjcb; release_tsk_lock(p_pcb); /* * あらためて * オブジェクトロック -> タスクロック * の順でロックを取得 */ TEST_G_LABEL("_test_ter_tsk_01"); t_acquire_obj_lock(&GET_OBJLOCK(p_wobjcb)); if ((p_pcb = t_acquire_nested_tsk_lock(p_tcb, &GET_OBJLOCK(p_wobjcb))) == NULL){ goto retry; } /* * オブジェクト待ち状態以外ないし,異なるオブジェクトに対する待ち * になっていないかチェック. */ if ((TSTAT_WAITING(p_tcb->tstat) && !TSTAT_WAIT_WOBJ(p_tcb->tstat)) || p_wobjcb != p_tcb->p_wobjcb) { release_nested_tsk_lock(p_pcb); release_obj_lock(&GET_OBJLOCK(p_wobjcb)); goto retry; } wait_dequeue_wobj(p_tcb); wait_dequeue_tmevtb(p_tcb); release_obj_lock(&GET_OBJLOCK(p_wobjcb)); make_dormant(p_tcb); if (p_tcb->actque) { p_tcb->actque = false; p_tcb->actprc = TPRC_NONE; if (make_active(p_tcb)) { dspreq = dispatch_request(p_pcb); } } release_tsk_lock(p_pcb); if (dspreq) { dispatch(); } } else { /* 起動要求キューイングあり & 他プロセッサへのマイグレーション */ /* 移動先のプロセッサのPCBを取得 */ t_p_pcb = get_mp_p_pcb(p_tcb->actprc); /* * デッドロック回避のため,ロックを取得し直す */ WOBJCB *p_wobjcb = p_tcb->p_wobjcb; release_tsk_lock(p_pcb); /* * あらためて * オブジェクトロック -> タスクロック * の順でロックを取得 */ TEST_G_LABEL("_test_ter_tsk_02"); t_acquire_obj_lock(&GET_OBJLOCK(p_wobjcb)); if (t_acquire_nested_dual_tsk_lock(p_tcb, p_tcb->actprc, &GET_OBJLOCK(p_wobjcb), &p_pcb, &t_p_pcb)) { goto retry; } /* * 異なるオブジェクトに対する待ちないし,オブジェクト待ち状態以外に * になっていない,異なるプロセッサへのマイグレーション,対象タスク * がマイグレートしているならリトライ. */ if ((p_wobjcb != p_tcb->p_wobjcb) || (TSTAT_WAITING(p_tcb->tstat) && !TSTAT_WAIT_WOBJ(p_tcb->tstat)) || (get_mp_p_pcb(p_tcb->actprc) != t_p_pcb) || (p_pcb != my_p_pcb)) { release_dual_tsk_lock(p_pcb, t_p_pcb); release_obj_lock(&GET_OBJLOCK(p_wobjcb)); goto retry; } wait_dequeue_wobj(p_tcb); wait_dequeue_tmevtb(p_tcb); release_obj_lock(&GET_OBJLOCK(p_wobjcb)); make_dormant(p_tcb); p_tcb->actque = false; p_tcb->actprc = TPRC_NONE; f_p_pcb = p_pcb; p_tcb->p_pcb = t_p_pcb; if (make_active(p_tcb)) { /* * 現在所属するプロセッサと同じプロセッサにマイグレー * ションする場合はここに来ないため,dispatch_request() * 戻り値はチェックしない. */ (void)dispatch_request(t_p_pcb); } release_dual_tsk_lock(f_p_pcb, t_p_pcb); } } } t_unlock_cpu(); error_exit: LOG_TER_TSK_LEAVE(ercd); return(ercd); }
ER ter_tsk(ID tskid) { TCB *p_tcb; ER ercd; bool_t dspreq = false; PCB *p_pcb; PCB *my_p_pcb; LOG_TER_TSK_ENTER(tskid); CHECK_TSKCTX_UNL(); CHECK_TSKID(tskid); p_tcb = get_tcb(tskid); t_lock_cpu(); p_pcb = t_acquire_tsk_lock(p_tcb); my_p_pcb = get_my_p_pcb(); /* 自タスクを指定するとエラー */ if ((p_tcb) == my_p_pcb->p_runtsk) { ercd = E_ILUSE; } /* 異なるプロセッサに割り付けられているタスクならエラーとする */ else if (p_pcb != my_p_pcb) { ercd = E_OBJ; } else if (TSTAT_DORMANT(p_tcb->tstat)) { ercd = E_OBJ; } else { if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * 対象タスクが他プロセッサ上のタスクかつRUNNABLEの場合, * RUN状態の可能性があるため,ディスパッチ要求を出す必要があるが, * 本システムコールは同じプロセッサに割り付けられているタスクのみ * に発行可能であるので,ディスパッチ要求を出す必要はない. */ (void)make_non_runnable(p_tcb); } else if (TSTAT_WAITING(p_tcb->tstat)) { wait_dequeue_wobj(p_tcb); wait_dequeue_tmevtb(p_tcb); } make_dormant(p_tcb); if (p_tcb->actque) { p_tcb->actque = false; /* * マイグレーション要求がキューイングしている場合は, * マイグレーション処理を行う. */ if ((p_tcb->actprc != TPRC_NONE) && (p_tcb->actprc != my_p_pcb->prcid)) { p_tcb->p_pcb = get_mp_p_pcb(p_tcb->actprc); } p_tcb->actprc = TPRC_NONE; if (make_active(p_tcb)) { dspreq = dispatch_request(p_tcb->p_pcb); } } ercd = E_OK; } release_tsk_lock(p_pcb); if (dspreq) { dispatch(); } t_unlock_cpu(); error_exit: LOG_TER_TSK_LEAVE(ercd); return(ercd); }
ER ext_tsk(void) { ER ercd; PCB *t_p_pcb; PCB *my_p_pcb; TCB *p_runtsk; bool_t locked; LOG_EXT_TSK_ENTER(); CHECK_TSKCTX(); /* * CPUロック状態でext_tskが呼ばれた場合は,ロック取得時に割込みを許可 * しない. * ロック取得時に割込みを許可しないのは, 過度状態の場合にロックを取得 * できなかった場合に割込みを許可すると,割込みが入りサスペンド状態と * なってしまうためである. */ locked = t_sense_lock(); retry: if (locked) { my_p_pcb = acquire_tsk_lock_without_preemption_self(); } else { t_lock_cpu(); my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check(); } p_runtsk = my_p_pcb->p_runtsk; /* 再起動時のマイグレーションなし */ if ((p_runtsk->actprc == TPRC_NONE) || (p_runtsk->actprc == my_p_pcb->prcid)) { /* * ディスパッチ禁止状態でext_tskが呼ばれた場合に対応して,ディスパッ * チ許可状態にしてからタスクを終了する. */ my_p_pcb->disdsp = false; /* * 割込み優先度マスク(IPM)がTIPM_ENAALL以外の状態でext_tskが呼ばれ * た場合に対応して,IPMをTIPM_ENAALLにしてからタスクを終了する. */ t_set_ipm(TIPM_ENAALL); my_p_pcb->ipmflg = true; my_p_pcb->dspflg = true; /* * スピンロックを取得している場合は,スピンロックを解除する */ force_unlock_spin(my_p_pcb); (void) make_non_runnable(p_runtsk); make_dormant(p_runtsk); if (p_runtsk->actque) { p_runtsk->actque = false; p_runtsk->actprc = TPRC_NONE; (void) make_active(p_runtsk); } release_tsk_lock(my_p_pcb); exit_and_dispatch(); ercd = E_SYS; } else { /* 移動先のプロセッサのPCBを取得 */ t_p_pcb = get_mp_p_pcb(p_runtsk->actprc); /* 一旦タスクロックを離す */ release_tsk_lock(my_p_pcb); /* * 現在割り付けられているプロセッサと移動先のプロセッサのタスク * ロックを取得 */ if (locked) { acquire_dual_tsk_lock_without_preemption(p_runtsk, p_runtsk->actprc, &my_p_pcb, &t_p_pcb); } else { t_acquire_dual_tsk_lock(p_runtsk, p_runtsk->actprc, &my_p_pcb, &t_p_pcb); } /* * マイグレーション先のプロセッサが変更された場合はリトライ */ if (p_runtsk->actprc != t_p_pcb->prcid) { release_dual_tsk_lock(p_runtsk->p_pcb, t_p_pcb); goto retry; } /* * ここで各カーネル状態を変更するのは,ディスパッチ禁止状態と割込 * み優先度マスク全解除状態でない状態による過度状態の場合に,各カ * ーネル状態を変更してから,ロック取得関数で割込みを許可して割込 * みが入ると,割込みからのリターン時にディスパッチャが呼ばれてし * まい,休止状態となるためである. */ my_p_pcb->disdsp = false; t_set_ipm(TIPM_ENAALL); my_p_pcb->ipmflg = true; my_p_pcb->dspflg = true; force_unlock_spin(my_p_pcb); /* 現在コンテキストを捨ててマイグレーション */ exit_and_migrate(p_runtsk->actprc); ercd = E_SYS; } error_exit: LOG_EXT_TSK_LEAVE(ercd); return(ercd); }
ER ext_tsk(void) { ER ercd; PCB *my_p_pcb; TCB *p_runtsk; LOG_EXT_TSK_ENTER(); CHECK_TSKCTX(); /* * CPUロック状態でext_tskが呼ばれた場合は,ロック取得時に割込みを許可 * しない. * ロック取得時に割込みを許可しないのは, 過度状態の場合にロックを取得 * できなかった場合に割込みを許可すると,割込みが入りサスペンド状態と * なってしまうためである. * ディスパッチ禁止や割込み優先度マスク全解除状態でない場合の過度状態の * 場合は,割込みが入っても割込みの出口でディスパッチャに行かずに戻って * くるため問題ない. */ if (t_sense_lock()) { my_p_pcb = acquire_tsk_lock_without_preemption_self(); } else { t_lock_cpu(); my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check(); } p_runtsk = my_p_pcb->p_runtsk; if (my_p_pcb->disdsp) { /* * ディスパッチ禁止状態でext_tskが呼ばれた場合に対応して,ディスパッ * チ許可状態にしてからタスクを終了する. */ my_p_pcb->disdsp = false; } if (!my_p_pcb->ipmflg) { /* * 割込み優先度マスク(IPM)がTIPM_ENAALL以外の状態でext_tskが呼ばれ * た場合に対応して,IPMをTIPM_ENAALLにしてからタスクを終了する. */ t_set_ipm(TIPM_ENAALL); my_p_pcb->ipmflg = true; } my_p_pcb->dspflg = true; /* * スピンロックを取得している場合は,スピンロックを解除する */ force_unlock_spin(my_p_pcb); /* 再起動時のマイグレーションなし */ if ((p_runtsk->actprc == TPRC_NONE) || (p_runtsk->actprc == my_p_pcb->prcid)) { (void) make_non_runnable(p_runtsk); make_dormant(p_runtsk); if (p_runtsk->actque) { p_runtsk->actque = false; p_runtsk->actprc = TPRC_NONE; (void) make_active(p_runtsk); } release_tsk_lock(my_p_pcb); exit_and_dispatch(); ercd = E_SYS; } else { /* 現在コンテキストを捨ててマイグレーション */ exit_and_migrate(p_runtsk->actprc); ercd = E_SYS; } error_exit: LOG_EXT_TSK_LEAVE(ercd); return(ercd); }
ER_UINT acre_tsk(const T_CTSK *pk_ctsk) { ID domid; const DOMINIB *p_dominib; TCB *p_tcb; TINIB *p_tinib; ATR tskatr; SIZE sstksz, ustksz; void *sstk, *ustk; ACPTN acptn; ER ercd; LOG_ACRE_TSK_ENTER(pk_ctsk); CHECK_TSKCTX_UNL(); CHECK_MACV_READ(pk_ctsk, T_CTSK); CHECK_RSATR(pk_ctsk->tskatr, TA_ACT|TARGET_TSKATR|TA_DOMMASK); domid = get_atrdomid(pk_ctsk->tskatr); CHECK_ATRDOMID_ACTIVE(domid); CHECK_ALIGN_FUNC(pk_ctsk->task); CHECK_NONNULL_FUNC(pk_ctsk->task); CHECK_TPRI(pk_ctsk->itskpri); p_dominib = (domid == TDOM_SELF) ? p_runtsk->p_tinib->p_dominib : (domid == TDOM_KERNEL) ? &dominib_kernel : get_dominib(domid); if (p_dominib == &dominib_kernel) { /* * システムタスクの場合 */ ustksz = 0U; ustk = NULL; CHECK_PAR(pk_ctsk->sstk == NULL); CHECK_PAR(pk_ctsk->stksz > 0U); sstksz = pk_ctsk->stksz; sstk = pk_ctsk->stk; if (sstk != NULL) { CHECK_PAR(pk_ctsk->sstksz == 0U); } else { sstksz += pk_ctsk->sstksz; } } else { /* * ユーザタスクの場合 */ ustksz = pk_ctsk->stksz; ustk = pk_ctsk->stk; CHECK_PAR(ustksz >= TARGET_MIN_USTKSZ); CHECK_NOSPT(ustk != NULL); CHECK_TARGET_USTACK(ustksz, ustk, p_dominib); sstksz = pk_ctsk->sstksz; sstk = pk_ctsk->sstk; } CHECK_PAR(sstksz >= TARGET_MIN_SSTKSZ); if (sstk != NULL) { CHECK_ALIGN_STKSZ(sstksz); CHECK_ALIGN_STACK(sstk); } CHECK_ACPTN(sysstat_acvct.acptn3); tskatr = pk_ctsk->tskatr; t_lock_cpu(); if (queue_empty(&free_tcb)) { ercd = E_NOID; } else { if (sstk == NULL) { sstk = kernel_malloc(ROUND_STK_T(sstksz)); tskatr |= TA_MEMALLOC; } if (sstk == NULL) { ercd = E_NOMEM; } else { p_tcb = ((TCB *) queue_delete_next(&free_tcb)); p_tinib = (TINIB *)(p_tcb->p_tinib); p_tinib->p_dominib = p_dominib; p_tinib->tskatr = tskatr; p_tinib->exinf = pk_ctsk->exinf; p_tinib->task = pk_ctsk->task; p_tinib->ipriority = INT_PRIORITY(pk_ctsk->itskpri); #ifdef USE_TSKINICTXB init_tskinictxb(&(p_tinib->tskinictxb), p_dominib, sstksz, sstk, utsksz, ustk, pk_ctsk); #else /* USE_TSKINICTXB */ p_tinib->sstksz = sstksz; p_tinib->sstk = sstk; p_tinib->ustksz = ustksz; p_tinib->ustk = ustk; #endif /* USE_TSKINICTXB */ p_tinib->texatr = TA_NULL; p_tinib->texrtn = NULL; acptn = default_acptn(domid); p_tinib->acvct.acptn1 = acptn; p_tinib->acvct.acptn2 = acptn; p_tinib->acvct.acptn3 = acptn | rundom; p_tinib->acvct.acptn4 = acptn; p_tcb->actque = false; make_dormant(p_tcb); queue_initialize(&(p_tcb->mutex_queue)); if ((p_tcb->p_tinib->tskatr & TA_ACT) != 0U) { make_active(p_tcb); } ercd = TSKID(p_tcb); } } t_unlock_cpu(); error_exit: LOG_ACRE_TSK_LEAVE(ercd); return(ercd); }