ER
get_pri(ID tskid, PRI *p_tskpri)
{
	TCB		*p_tcb;
	ER		ercd;
	PCB		*p_pcb;

	LOG_GET_PRI_ENTER(tskid, p_tskpri);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);

	t_lock_cpu();
	p_tcb = get_tcb_self(tskid, get_my_p_pcb());
	p_pcb = t_acquire_tsk_lock(p_tcb);
	if (TSTAT_DORMANT(p_tcb->tstat)) {
		ercd = E_OBJ;
	}
	else {
		*p_tskpri = EXT_TSKPRI(p_tcb->priority);
		ercd = E_OK;
	}
	release_tsk_lock(p_pcb);
	t_unlock_cpu();

  error_exit:
	LOG_GET_PRI_LEAVE(ercd, *p_tskpri);
	return(ercd);
}
Пример #2
0
ER
imrot_rdq(PRI tskpri, ID prcid)
{
	ER		ercd;
	PCB		*p_pcb;
	PCB		*my_p_pcb;

	LOG_IMROT_RDQ_ENTER(tskpri, prcid);
	CHECK_INTCTX_UNL();
	CHECK_TPRI(tskpri);
	CHECK_PRCID(prcid);

	i_lock_cpu();
	p_pcb = i_acquire_tsk_lock_prcid(prcid);
	if (rotate_ready_queue(INT_PRIORITY(tskpri), p_pcb)) {
		my_p_pcb = get_my_p_pcb();
		my_p_pcb->reqflg = dispatch_request(p_pcb) ? true : my_p_pcb->reqflg;
	}
	ercd = E_OK;
	release_tsk_lock(p_pcb);
	i_unlock_cpu();

  error_exit:
	LOG_IMROT_RDQ_LEAVE(ercd);
	return(ercd);
}
Пример #3
0
ER
ena_dsp(void)
{
	ER		ercd;
	bool_t dspreq = false;
	PCB		*my_p_pcb;

	LOG_ENA_DSP_ENTER();
	CHECK_TSKCTX_UNL();

	t_lock_cpu();
	my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check();
	my_p_pcb->disdsp = false;
	if (t_get_ipm() == TIPM_ENAALL) {
		my_p_pcb->dspflg = true;
		if (my_p_pcb->p_runtsk != my_p_pcb->p_schedtsk) {
			dspreq = true;
		}
	}
	ercd = E_OK;
	release_tsk_lock(my_p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_ENA_DSP_LEAVE(ercd);
	return(ercd);
}
Пример #4
0
ER
mrot_rdq(PRI tskpri, ID prcid)
{
	uint_t	pri;
	ER		ercd;
	bool_t	dspreq = false;
	PCB		*p_pcb;
	
	LOG_MROT_RDQ_ENTER(tskpri, prcid);
	CHECK_TSKCTX_UNL();
	CHECK_TPRI_SELF(tskpri);
	CHECK_PRCID(prcid);

	t_lock_cpu();
	p_pcb = t_acquire_tsk_lock_prcid(prcid);
	pri = (tskpri == TPRI_SELF) ? (get_my_p_pcb())->p_runtsk->priority : INT_PRIORITY(tskpri);
	if (rotate_ready_queue(pri, p_pcb)) {
		dspreq = dispatch_request(p_pcb);
	}
	ercd = E_OK;
	release_tsk_lock(p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_MROT_RDQ_LEAVE(ercd);
	return(ercd);
}
Пример #5
0
ER
rot_rdq(PRI tskpri)
{
	uint_t	pri;
	ER		ercd;
	bool_t	dspreq = false;
	PCB		*my_p_pcb;

	LOG_ROT_RDQ_ENTER(tskpri);
	CHECK_TSKCTX_UNL();
	CHECK_TPRI_SELF(tskpri);

	t_lock_cpu();
	my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check();
	pri = (tskpri == TPRI_SELF) ? my_p_pcb->p_runtsk->priority : INT_PRIORITY(tskpri);
	dspreq = rotate_ready_queue(pri, my_p_pcb);
	ercd = E_OK;
	release_tsk_lock(my_p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_ROT_RDQ_LEAVE(ercd);
	return(ercd);
}
Пример #6
0
void
signal_time(void)
{
	TMEVTB	*p_tmevtb;
	PCB		*my_p_pcb;
	TEVTCB	*my_p_tevtcb;

	assert(sense_context());
	assert(!i_sense_lock());

	i_lock_cpu();
	my_p_pcb = i_acquire_tsk_lock_self();

	my_p_tevtcb = my_p_pcb->p_tevtcb;

	/*
	 *  current_timeを更新する.
	 */
	my_p_tevtcb->current_time = my_p_tevtcb->next_time;

	/*
	 *  next_time,next_subtimeを更新する.
	 */
#if TIC_DENO == 1U
	my_p_tevtcb->next_time = my_p_tevtcb->current_time + TIC_NUME;
#else /* TIC_DENO == 1U */
	my_p_tevtcb->next_subtime += TIC_NUME % TIC_DENO;
	my_p_tevtcb->next_time = my_p_tevtcb->current_time + TIC_NUME / TIC_DENO;
	if (my_p_tevtcb->next_subtime >= TIC_DENO) {
		my_p_tevtcb->next_subtime -= TIC_DENO;
		my_p_tevtcb->next_time += 1U;
	}
#endif /* TIC_DENO == 1U */

	/*
	 *  curent_timeよりイベント発生時刻の早い(または同じ)タイムイベン
	 *  トを,タイムイベントヒープから削除し,コールバック関数を呼び出
	 *  す.
	 */
	while ((my_p_tevtcb->last_index) > 0 && EVTTIM_LE(my_p_tevtcb, TMEVT_NODE(my_p_tevtcb, 1).time, my_p_tevtcb->current_time)) {
		p_tmevtb = TMEVT_NODE(my_p_tevtcb, 1).p_tmevtb;
		tmevtb_delete_top(my_p_tevtcb);
		(*(p_tmevtb->callback))(p_tmevtb->arg);
	}

	/*
	 *  min_timeを更新する.
	 */
	my_p_tevtcb->min_time = my_p_tevtcb->current_time;

	release_tsk_lock(my_p_pcb);
	i_unlock_cpu();
}
ER
get_inf(intptr_t *p_exinf)
{
	ER		ercd;
	PCB		*my_p_pcb;

	LOG_GET_INF_ENTER(p_exinf);
	CHECK_TSKCTX_UNL();

	t_lock_cpu();
	my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check();
	*p_exinf = my_p_pcb->p_runtsk->p_tinib->exinf;
	ercd = E_OK;
	release_tsk_lock(my_p_pcb);
	t_unlock_cpu();

  error_exit:
	LOG_GET_INF_LEAVE(ercd, *p_exinf);
	return(ercd);
}
Пример #8
0
ER
dis_dsp(void)
{
	ER		ercd;
	PCB		*my_p_pcb;

	LOG_DIS_DSP_ENTER();
	CHECK_TSKCTX_UNL();

	t_lock_cpu();
	my_p_pcb = t_acquire_tsk_lock_self_without_runnable_check();
	my_p_pcb->disdsp = true;
	my_p_pcb->dspflg = false;
	ercd = E_OK;
	release_tsk_lock(my_p_pcb);
	t_unlock_cpu();

  error_exit:
	LOG_DIS_DSP_LEAVE(ercd);
	return(ercd);
}
ER
act_tsk(ID tskid)
{
	TCB		*p_tcb;
	ER		ercd;
	bool_t	dspreq = false;
	PCB		*p_pcb;

	LOG_ACT_TSK_ENTER(tskid);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);

	t_lock_cpu();
	p_tcb = get_tcb_self(tskid, get_my_p_pcb());
	p_pcb = t_acquire_tsk_lock(p_tcb);
	if (TSTAT_DORMANT(p_tcb->tstat)) {
		if (make_active(p_tcb)) {
			dspreq = dispatch_request(p_pcb);
		}
		ercd = E_OK;
	}
	else if (!(p_tcb->actque)) {
		p_tcb->actque = true;
		ercd = E_OK;
	}
	else {
		ercd = E_QOVR;
	}
	release_tsk_lock(p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_ACT_TSK_LEAVE(ercd);
	return(ercd);
}
Пример #10
0
ER
irot_rdq(PRI tskpri)
{
	ER		ercd;
	PCB		*my_p_pcb;

	LOG_IROT_RDQ_ENTER(tskpri);
	CHECK_INTCTX_UNL();
	CHECK_TPRI(tskpri);

	i_lock_cpu();
	my_p_pcb = i_acquire_tsk_lock_self();
	if (rotate_ready_queue(INT_PRIORITY(tskpri), my_p_pcb)) {
		my_p_pcb->reqflg = true;
	}
	ercd = E_OK;
	release_tsk_lock(my_p_pcb);
	i_unlock_cpu();

  error_exit:
	LOG_IROT_RDQ_LEAVE(ercd);
	return(ercd);
}
ER_UINT
can_act(ID tskid)
{
	TCB		*p_tcb;
	ER_UINT	ercd;
	PCB		*p_pcb;

	LOG_CAN_ACT_ENTER(tskid);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);

	t_lock_cpu();
	p_tcb = get_tcb_self(tskid, get_my_p_pcb());
	p_pcb = t_acquire_tsk_lock(p_tcb);
	ercd = p_tcb->actque ? 1 : 0;
	p_tcb->actque = false;
	p_tcb->actprc = TPRC_NONE;
	release_tsk_lock(p_pcb);
	t_unlock_cpu();

  error_exit:
	LOG_CAN_ACT_LEAVE(ercd);
	return(ercd);
}
ER
iact_tsk(ID tskid)
{
	TCB		*p_tcb;
	ER		ercd;
	PCB		*p_pcb;

	LOG_IACT_TSK_ENTER(tskid);
	CHECK_INTCTX_UNL();
	CHECK_TSKID(tskid);
	p_tcb = get_tcb(tskid);

	i_lock_cpu();
	p_pcb = i_acquire_tsk_lock(p_tcb);
	if (TSTAT_DORMANT(p_tcb->tstat)) {
		if (make_active(p_tcb)) {
			if (dispatch_request(p_pcb)) {
				p_pcb->reqflg = true;
			}
		}
		ercd = E_OK;
	}
	else if (!(p_tcb->actque)) {
		p_tcb->actque = true;
		ercd = E_OK;
	}
	else {
		ercd = E_QOVR;
	}
	release_tsk_lock(p_pcb);
	i_unlock_cpu();

  error_exit:
	LOG_IACT_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);
}
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
chg_pri(ID tskid, PRI tskpri)
{
	TCB		*p_tcb;
	uint_t	newpri;
	ER		ercd;
	bool_t	dspreq = false;
	PCB		*p_pcb;

	LOG_CHG_PRI_ENTER(tskid, tskpri);
	CHECK_TSKCTX_UNL();
	CHECK_TSKID_SELF(tskid);
	CHECK_TPRI_INI(tskpri);

	t_lock_cpu();
	p_tcb = get_tcb_self(tskid, get_my_p_pcb());
	newpri = (tskpri == TPRI_INI) ? p_tcb->p_tinib->ipriority
										: INT_PRIORITY(tskpri);
	p_pcb = t_acquire_tsk_lock(p_tcb);
	if (TSTAT_DORMANT(p_tcb->tstat)) {
		ercd = E_OBJ;
	}
	else {
#if TTYPE_KLOCK == G_KLOCK
		if (change_priority(p_tcb, newpri)) {
			dspreq = dispatch_request(p_pcb);
		}
#else /* TTYPE_KLOCK != G_KLOCK */
		if (!(TSTAT_WAITING(p_tcb->tstat) && TSTAT_WAIT_WOBJ(p_tcb->tstat))) {
			/* オブジェクト待ち以外の状態の場合 */
			if (change_priority(p_tcb, newpri)) {
				dspreq = dispatch_request(p_pcb);
			}
		}
		else {
			/*
			 * オブジェクト待ちの場合
			 * デッドロック回避のため,ロックを取得し直す 
			 */
			WOBJCB *p_wobjcb = p_tcb->p_wobjcb;
			p_tcb->pend_chgpri = true;
			p_tcb->pend_newpri = newpri;
			release_tsk_lock(p_pcb);

			/*
			 * あらためて
			 *   オブジェクトロック -> タスクロック
			 * の順でロックを取得 
			 */
			TEST_G_LABEL("_test_chg_pri");
		  retry:
			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 (!(p_tcb->pend_chgpri)) {
				/* 既に他の箇所で優先度変更処理がなされた */
				release_nested_tsk_lock(p_pcb);
				release_obj_lock(&GET_OBJLOCK(p_wobjcb));
				t_unlock_cpu();
				ercd = E_OK;
				goto error_exit;
			}

			p_tcb->priority = p_tcb->pend_newpri;
			p_tcb->pend_chgpri = false;
			change_priority(p_tcb, newpri);
			release_obj_lock(&GET_OBJLOCK(p_wobjcb));
		}
#endif /* TTYPE_KLOCK != G_KLOCK */
		ercd = E_OK;
	}
	release_tsk_lock(p_pcb);
	if (dspreq) {
		dispatch();
	}
	t_unlock_cpu();

  error_exit:
	LOG_CHG_PRI_LEAVE(ercd);
	return(ercd);
}