ER
dly_tsk(RELTIM dlytim)
{
	WINFO	winfo;
	TMEVTB	tmevtb;
	ER		ercd;

	LOG_DLY_TSK_ENTER(dlytim);
	CHECK_DISPATCH();
	CHECK_PAR(VALID_RELTIM(dlytim));

	lock_cpu_dsp();
	if (p_runtsk->raster) {
		ercd = E_RASTER;
	}
	else {
		p_runtsk->tstat = TS_WAITING_DLY;
		make_non_runnable(p_runtsk);
		p_runtsk->p_winfo = &winfo;
		winfo.p_tmevtb = &tmevtb;
		tmevtb.callback = (CBACK) wait_tmout_ok;
		tmevtb.arg = (void *) p_runtsk;
		tmevtb_enqueue(&tmevtb, dlytim);
		LOG_TSKSTAT(p_runtsk);
		dispatch();
		ercd = winfo.wercd;
	}
	unlock_cpu_dsp();

  error_exit:
	LOG_DLY_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #2
0
ER
dly_tsk(RELTIM dlytim)
{
	WINFO	winfo;
	TMEVTB	tmevtb;
	ER		ercd;

	LOG_DLY_TSK_ENTER(dlytim);
	CHECK_DISPATCH();
	CHECK_PAR(dlytim <= TMAX_RELTIM);

	t_lock_cpu();
	if (p_runtsk->waifbd) {
		ercd = E_RLWAI;
	}
	else {
		p_runtsk->tstat = (TS_WAITING | TS_WAIT_DLY);
		(void) make_non_runnable(p_runtsk);
		p_runtsk->p_winfo = &winfo;
		winfo.p_tmevtb = &tmevtb;
		tmevtb_enqueue(&tmevtb, dlytim, (CBACK) wait_tmout_ok,
												(void *) p_runtsk);
		LOG_TSKSTAT(p_runtsk);
		dispatch();
		ercd = winfo.wercd;
	}
	t_unlock_cpu();

  error_exit:
	LOG_DLY_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #3
0
SYSCALL ER
dly_tsk(RELTIM dlytim)
{
	WINFO	winfo;
	TMEVTB	tmevtb;
	ER	ercd;

	LOG_DLY_TSK_ENTER(dlytim);
	CHECK_DISPATCH();
	CHECK_PAR(dlytim <= TMAX_RELTIM);

	t_lock_cpu();
	runtsk->tstat = TS_WAITING;
	make_non_runnable(runtsk);
	runtsk->winfo = &winfo;
	winfo.tmevtb = &tmevtb;
	tmevtb_enqueue(&tmevtb, dlytim, (CBACK) wait_tmout_ok, (VP) runtsk);
	LOG_TSKSTAT(runtsk);
	dispatch();
	ercd = winfo.wercd;
	t_unlock_cpu();

    exit:
	LOG_DLY_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #4
0
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
sus_tsk(ID tskid)
{
	TCB		*p_tcb;
	ER		ercd;

	LOG_SUS_TSK_ENTER(tskid);
	CHECK_TSKCTX_UNL();							/*[NGKI1299][NGKI1300]*/
	if (tskid == TSK_SELF) {
		p_tcb = p_runtsk;						/*[NGKI1310]*/
	}
	else {
		CHECK_ID(VALID_TSKID(tskid));			/*[NGKI1302]*/
		p_tcb = get_tcb(tskid);
	}

	lock_cpu();
	if (p_tcb == p_runtsk && !dspflg) {			/*[NGKI1311][NGKI3604]*/
		ercd = E_CTX;
	}
	else if (p_tcb->p_tinib->tskatr == TA_NOEXS) {
		ercd = E_NOEXS;							/*[NGKI1303]*/
	}
	else if (TSTAT_DORMANT(p_tcb->tstat)) {
		ercd = E_OBJ;							/*[NGKI1305]*/
	}
	else if (p_tcb->raster) {
		ercd = E_RASTER;						/*[NGKI3605]*/
	}
	else if (TSTAT_RUNNABLE(p_tcb->tstat)) {
		/*
		 *  実行できる状態から強制待ち状態への遷移[NGKI1307]
		 */
		p_tcb->tstat = TS_SUSPENDED;
		LOG_TSKSTAT(p_tcb);
		make_non_runnable(p_tcb);
		if (p_runtsk != p_schedtsk) {
			dispatch();
		}
		ercd = E_OK;
	}
	else if (TSTAT_SUSPENDED(p_tcb->tstat)) {
		ercd = E_QOVR;							/*[NGKI1306]*/
	}
	else {
		/*
		 *  待ち状態から二重待ち状態への遷移[NGKI1308]
		 */
		p_tcb->tstat |= TS_SUSPENDED;
		LOG_TSKSTAT(p_tcb);
		ercd = E_OK;
	}
	unlock_cpu();

  error_exit:
	LOG_SUS_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #6
0
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);
}
Exemple #7
0
ER
sus_tsk(ID tskid)
{
	TCB		*p_tcb;
	ER		ercd;

	LOG_SUS_TSK_ENTER(tskid);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);
	p_tcb = get_tcb_self(tskid);

	t_lock_cpu();
	if (p_tcb == p_runtsk && !dspflg) {
		ercd = E_CTX;
	}
	else 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->tstat = TS_SUSPENDED;
		LOG_TSKSTAT(p_tcb);
		if (make_non_runnable(p_tcb)) {
			dispatch();
		}
		ercd = E_OK;
	}
	else if (TSTAT_SUSPENDED(p_tcb->tstat)) {
		ercd = E_QOVR;
	}
	else {
		/*
		 *  待ち状態から二重待ち状態への遷移
		 */
		p_tcb->tstat |= TS_SUSPENDED;
		LOG_TSKSTAT(p_tcb);
		ercd = E_OK;
	}
	t_unlock_cpu();

  error_exit:
	LOG_SUS_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #8
0
void
make_wait_tmout(WINFO *winfo, TMEVTB *tmevtb, TMO tmout)
{
	make_non_runnable(runtsk);
	runtsk->winfo = winfo;
	if (tmout > 0) {
		winfo->tmevtb = tmevtb;
		tmevtb_enqueue(tmevtb, (RELTIM) tmout,
					(CBACK) wait_tmout, (VP) runtsk);
	}
	else {
		assert(tmout == TMO_FEVR);
		winfo->tmevtb = NULL;
	}
}
Exemple #9
0
void
make_wait_tmout(WINFO *p_winfo, TMEVTB *p_tmevtb, TMO tmout)
{
	(void) make_non_runnable(p_runtsk);
	p_runtsk->p_winfo = p_winfo;
	if (tmout > 0) {
		p_winfo->p_tmevtb = p_tmevtb;
		tmevtb_enqueue(p_tmevtb, (RELTIM) tmout,
						(CBACK) wait_tmout, (void *) p_runtsk);
	}
	else {
		assert(tmout == TMO_FEVR);
		p_winfo->p_tmevtb = NULL;
	}
}
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);
}
Exemple #11
0
void
make_wait_tmout(WINFO *p_winfo, TMEVTB *p_tmevtb, TMO tmout)
{
	make_non_runnable(p_runtsk);
	p_runtsk->p_winfo = p_winfo;
	if (tmout == TMO_FEVR) {
		p_winfo->p_tmevtb = NULL;
	}
	else {
		assert(tmout <= TMAX_RELTIM);
		p_winfo->p_tmevtb = p_tmevtb;
		p_tmevtb->callback = (CBACK) wait_tmout;
		p_tmevtb->arg = (void *) p_runtsk;
		tmevtb_enqueue(p_tmevtb, (RELTIM) tmout);
	}
}
Exemple #12
0
SYSCALL ER
sus_tsk(ID tskid)
{
	TCB	*tcb;
	UINT	tstat;
	ER	ercd;

	LOG_SUS_TSK_ENTER(tskid);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);
	tcb = get_tcb_self(tskid);

	t_lock_cpu();
	if (tcb == runtsk && !(enadsp)) {
		ercd = E_CTX;
	}
	else if (TSTAT_DORMANT(tstat = tcb->tstat)) {
		ercd = E_OBJ;
	}
	else if (TSTAT_RUNNABLE(tstat)) {
		/*
		 *  実行できる状態から強制待ち状態への遷移
		 */
		tcb->tstat = TS_SUSPENDED;
		LOG_TSKSTAT(tcb);
		if (make_non_runnable(tcb)) {
			dispatch();
		}
		ercd = E_OK;
	}
	else if (TSTAT_SUSPENDED(tstat)) {
		ercd = E_QOVR;
	}
	else {
		/*
		 *  待ち状態から二重待ち状態への遷移
		 */
		tcb->tstat |= TS_SUSPENDED;
		LOG_TSKSTAT(tcb);
		ercd = E_OK;
	}
	t_unlock_cpu();

    exit:
	LOG_SUS_TSK_LEAVE(ercd);
	return(ercd);
}
Exemple #13
0
void
make_wait_tmout(uint_t tstat, WINFO *p_winfo, TMEVTB *p_tmevtb, TMO tmout)
{
	p_runtsk->tstat = tstat;
	make_non_runnable(p_runtsk);
	p_runtsk->p_winfo = p_winfo;
	if (tmout == TMO_FEVR) {
		p_winfo->p_tmevtb = NULL;
	}
	else {
		assert(tmout <= TMAX_RELTIM);
		p_winfo->p_tmevtb = p_tmevtb;
		p_tmevtb->callback = (CBACK) wait_tmout;
		p_tmevtb->arg = (void *) p_runtsk;
		tmevtb_enqueue_reltim(p_tmevtb, (RELTIM) tmout,
									p_runtsk->p_dominib->p_tmevt_heap);
	}
}
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);
}
Exemple #15
0
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);
}
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
mig_tsk(ID tskid, ID prcid)
{
	TCB		*p_tcb;
	ER		ercd = E_OK;
	PCB		*t_p_pcb;
	PCB		*f_p_pcb;
	bool_t	dspreq = false;
	PCB		*my_p_pcb;
#ifdef TOPPERS_SYSTIM_LOCAL
	EVTTIM	left_time;
#endif /* TOPPERS_SYSTIM_LOCAL */

	LOG_MIG_TSK_ENTER(tskid, prcid);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);
	CHECK_PRCID_INI(prcid);

	t_lock_cpu();
	p_tcb = get_tcb_self(tskid, get_my_p_pcb());
	prcid = (prcid == TPRC_INI)? p_tcb->p_tinib->iaffinity : prcid;
	T_CHECK_MIG(p_tcb->p_tinib->affinity_mask, prcid);

	/* 現在割り付けられているプロセッサと移動先のプロセッサのタスクロックを取得 */
	t_acquire_dual_tsk_lock(p_tcb, prcid, &f_p_pcb, &t_p_pcb);
	my_p_pcb = get_my_p_pcb();
	if (f_p_pcb != my_p_pcb) {
		/*
		 * 自タスクと同じプロセッサに割り付けられているタスクでなけれ
		 * ばエラー. mig_tsk を呼び出したタスクがシステムコール呼出し後,
		 * マイグレートされた場合にも,ここでエラーとなる
		 */
		ercd = E_OBJ;
	}
	else if (TSTAT_RUNNABLE(p_tcb->tstat)){
		/* 実行可能状態 */
		if(p_tcb == my_p_pcb->p_runtsk) {
			/* 自タスクに対して発行 */
			if (!(my_p_pcb->dspflg)) {
				/* ディスパッチ禁止中ならエラー */
				ercd = E_CTX;
			}
			else if (t_p_pcb == my_p_pcb) {
				/* 同一プロセッサを指定 */
				/* 優先順位を同一優先度のタスクの中で最低とする */
				dspreq = set_lowest_precedence(p_tcb, my_p_pcb);
				ercd = E_OK; 
			}
			else {
				/* マイグレーション要求を処理 */
				LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
				dispatch_and_migrate(prcid);
				/* ここに戻ってくる時にはロックは解放されている */
				ercd = E_OK;
				t_unlock_cpu();
				goto error_exit;
			}
		} 
		else {
			/* 他タスクの場合 */
			if (t_p_pcb == my_p_pcb) {
				/* 同一プロセッサを指定 */
				/* 
				 *  優先順位を同一優先度のタスクの中で最低とする.
				 *  対象のタスクは最高優先順位のタスクでないため,タ
				 *  スク切り替えは発生しない
				 */
				(void)set_lowest_precedence(p_tcb, my_p_pcb);
				ercd = E_OK; 
			}
			else {
				/* 異なるプロセッサを指定 */
				/* レディーキューから外す */
				make_non_runnable(p_tcb);
				/* pcb の書き換え */
				p_tcb->p_pcb = t_p_pcb;
				LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
				/* 移行先のプロセッサでmake_runnable する*/
				if (make_runnable(p_tcb)) {
					dispatch_request(t_p_pcb);
				}
				ercd = E_OK;
			}
		}
	}
	else if (TSTAT_DORMANT(p_tcb->tstat)) {
		/* 休止状態 */
		LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
		p_tcb->p_pcb = t_p_pcb;
		ercd = E_OK;
	}
	else {
		/* 待ち状態 */
		if ((p_tcb->tmevtb).callback == NULL) {
			/* 時間待ちでない場合 */
			LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
			p_tcb->p_pcb = t_p_pcb;
			ercd = E_OK;
		}
		else {
			/*
			 * 時間待ちの場合 グローバルタイマ方式 なら必要なし
			 */
#ifdef TOPPERS_SYSTIM_LOCAL
			/* キューから削除 */
			left_time = tmevtb_dequeue(f_p_pcb->p_tevtcb, &(p_tcb->tmevtb));
			LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
			/* 移動先のプロセッサのキューに挿入 */
			tmevtb_insert(t_p_pcb->p_tevtcb, &(p_tcb->tmevtb), base_time(t_p_pcb->p_tevtcb) + left_time);
#else  /* TOPPERS_SYSTIM_GLOBAL */
			LOG_TSKMIG(p_tcb, my_p_pcb->prcid, prcid);
#endif /* TOPPERS_SYSTIM_GLOBAL */
			p_tcb->p_pcb = t_p_pcb;
			ercd = E_OK;
		}
	}
	release_dual_tsk_lock(f_p_pcb, t_p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_MIG_TSK_LEAVE(ercd);
	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);
}