このページを編集する際は、編集に関する方針に従ってください。

概要

  • kernel/sched.cにて定義
  • タスクを起床する
    • 起床に成功した場合1を、失敗した場合0を返す

引数

  • p--起床するタスクディスクリプタ
  • state--起床するタスクのステータス(TASK_STOPPED、TASK_TRACED、TASK_INTERRUPTIBLE、TASK_UNINTERRUPTIBLEなど)
  • sync--0ならタスクを起床後、このタスクがカレントタスクより優先度が高いか調べ、高い場合は再スケジュール要求を行う
    • 1ならタスクを起床後、カレントタスクとの優先度の比較は行わない(つまり再スケジュール要求を行わない)

実装

/***

* try_to_wake_up - wake up a thread
* @p: the to-be-woken-up thread
* @state: the mask of task states that can be woken
* @sync: do a synchronous wakeup?
*
* Put it on the run-queue if it's not already there. The "current"
* thread is always on the run-queue (except when the actual
* re-schedule is in progress), and as such you're allowed to do
* the simpler "current->state = TASK_RUNNING" to mark yourself
* runnable without the overhead of this.
*
* returns failure only if the task is already active.
*/

static int try_to_wake_up(task_t * p, unsigned int state, int sync) {

	int cpu, this_cpu, success = 0;
	unsigned long flags;
	long old_state;
	runqueue_t *rq;

#ifdef CONFIG_SMP

	unsigned long load, this_load;
	struct sched_domain *sd;
	int new_cpu;

#endif

	rq = task_rq_lock(p, &flags);
  • 起床させるタスクpにマッピングされた、CPUのランキューのロックを取得する
	schedstat_inc(rq, ttwu_cnt);
	old_state = p->state;
	if (!(old_state & state))
		goto out;
  • TASK_RUNNING(0で定義)ならoutへジャンプ
	if (p->array)
		goto out_running;
  • pが属している優先度スロットに他のタスクがあるならout_runningへジャンプ
    • 他のタスクが無い場合は以下を実行
	cpu = task_cpu(p);
  • タスクpがマッピングされているCPU識別子を返す
	this_cpu = smp_processor_id();

#ifdef CONFIG_SMP

	if (unlikely(task_running(rq, p)))
		goto out_activate;
  • ランキューrqにおいてタスクpが現在実行中であるか調べる
  • rq上のカレントプロセスがpである場合 out_activate へジャンプ
	new_cpu = cpu;
	if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
		goto out_set_cpu;
  • p->cpus_allowedのthis_cpu番目のビット位置のビットがセットされていない場合は1を返す
  • pのCPUと現在使用中のCPUが同一、またはpが実行CPUに現在使用中のCPUを指定している場合は out_set_cpu にジャンプ
	load = source_load(cpu);
  • タスクpが使用しているCPUのロード値を取得(移行元(ソース)のロード値を計算する)
	this_load = target_load(this_cpu);
  • 現在のCPUのロード値を取得(移行先(ターゲット)のロード値を計算する)
	/*
	 * If sync wakeup then subtract the (maximum possible) effect of
	 * the currently running task from the load of the current CPU:
	 */
	if (sync)
		this_load -= SCHED_LOAD_SCALE;
  • syncがfalseの場合は、起床したプロセスの優先度がカレントプロセスのものより高いか調べ、必要ならschedule()関数を呼び出す
  • syncがtrueの場合は、優先度のこの比較処理はしない
	/* Don't pull the task off an idle CPU to a busy one */
	if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
		goto out_set_cpu;
  • 忙しいCPUにアイドルCPUからタスクを移動させないようにする
	new_cpu = this_cpu; /* Wake to this CPU if we can */
	/*
	 * Scan domains for affine wakeup and passive balancing
	 * possibilities.
	 */
	for_each_domain(this_cpu, sd) {
  • スケジュールドメインのflagsは以下のようなマクロをANDした値で初期化されている
    ノードのスケジュールドメイン物理CPUのスケジュールドメイン論理CPUのスケジュールドメイン
    SD_LOAD_BALANCESD_LOAD_BALANCESD_LOAD_BALANCE
    SD_BALANCE_EXECSD_BALANCE_NEWIDLESD_BALANCE_NEWIDLE
    SD_WAKE_BALANCESD_BALANCE_EXECSD_BALANCE_EXEC
    SD_WAKE_AFFINESD_WAKE_AFFINE
    SD_WAKE_BALANCESD_WAKE_IDLE
    SD_SHARE_CPUPOWER
		unsigned int imbalance;
		/*
		 * Start passive balancing when half the imbalance_pct
		 * limit is reached.
		 */
		imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;
		if ((sd->flags & SD_WAKE_AFFINE) &&
				!task_hot(p, rq->timestamp_last_tick, sd)) {
  • キャッシュが有効なタスクかどうかを返す
  • SD_WAKE_AFFINE:CPUがタスクを起こす
  • sdが物理CPUか論理CPUのドメインの場合で、キャッシュが有効で無い場合:
			/*
			 * This domain has SD_WAKE_AFFINE and p is cache cold
			 * in this domain.
			 */
			if (cpu_isset(cpu, sd->span)) {
  • sd->spanのcpu番目のビット位置のビットがセットされている場合は1を返す
				schedstat_inc(sd, ttwu_wake_affine);
				goto out_set_cpu;
			}
		} else if ((sd->flags & SD_WAKE_BALANCE) &&
				imbalance*this_load <= 100*load) {
  • SD_WAKE_BALANCE:タスク起床時パフォーマンスのバランスを取る
  • sdが物理CPUかノードのドメインの場合で、this_loadよりloadの方が25%以上大きい場合:
			/*
			 * This domain has SD_WAKE_BALANCE and there is
			 * an imbalance.
			 */
			if (cpu_isset(cpu, sd->span)) {
  • sd->spanのcpu番目のビット位置のビットがセットされている場合は1を返す
				schedstat_inc(sd, ttwu_wake_balance);
				goto out_set_cpu;
			}
		}
	}
	new_cpu = cpu; /* Could not wake to this_cpu. Wake to cpu instead */
  • this_cpu(カレントCPU)で起床させることはできなかった。代わりにcpu(引数で与えられたpのCPU)で起床させる。

out_set_cpu:

	schedstat_inc(rq, ttwu_attempts);
	new_cpu = wake_idle(new_cpu, p);
  • new_cpuの属するドメインからアイドルプロセスを実行中のCPUを返す
	if (new_cpu != cpu && cpu_isset(new_cpu, p->cpus_allowed)) {
  • p->cpus_allowedのnew_cpu番目のビット位置のビットがセットされている場合は1を返す
  • ※どのような場合にこの条件が成り立つのか?
    • 要調査
		schedstat_inc(rq, ttwu_moved);
		set_task_cpu(p, new_cpu);
		task_rq_unlock(rq, &flags);
  • ランキューrqのロックをアンロックし、可能であればプリエンプションする
		/* might preempt at this point */
		rq = task_rq_lock(p, &flags);
  • タスクpにマッピングされたCPUのランキューのロックを取得する
		old_state = p->state;
		if (!(old_state & state))
			goto out;
		if (p->array)
			goto out_running;
		this_cpu = smp_processor_id();
		cpu = task_cpu(p);
  • 引数で渡されたタスクがマッピングされているCPU識別子を返す
	}

out_activate:

#endif /* CONFIG_SMP */

	if (old_state == TASK_UNINTERRUPTIBLE) {
  • 起床させたいプロセス(この関数呼び出し時のプロセスpのstate)のstateがTASK_UNINTERRUPTIBLEである場合:
		rq->nr_uninterruptible--;
  • ランキューのTASK_UNINTERRUPTIBLEなエントリのカウンタをデクリメントする
		/*
		 * Tasks on involuntary sleep don't earn
		 * sleep_avg beyond just interactive state.
		 */
		p->activated = -1;
  • TASK_UNINTERRUPTIBLE状態からの起床
	}
	/*
	 * Sync wakeups (i.e. those types of wakeups where the waker
	 * has indicated that it will leave the CPU in short order)
	 * don't trigger a preemption, if the woken up task will run on
	 * this cpu. (in this case the 'I will reschedule' promise of
	 * the waker guarantees that the freshly woken up task is going
	 * to be considered on this CPU.)
	 */
	activate_task(p, rq, cpu == this_cpu);
	if (!sync || cpu != this_cpu) {
		if (TASK_PREEMPTS_CURR(p, rq))
			resched_task(rq->curr);
  • ローカルAPICのフラグを調査&設定し、必要であればプロセッサ間通信(IPI)を行い再スケジュールを要求する
  • pの優先度が、rqのカレントタスクの優先度より高い場合、1を返す。
	}
	success = 1;

out_running:

	p->state = TASK_RUNNING;
  • タスクを実行可能状態に遷移させる

out:

	task_rq_unlock(rq, &flags);
  • ランキューrqのロックをアンロックし、可能であればプリエンプションする
	return success;

}

呼出元


履歴

  • 作者:ひら
  • 日付:2005/2/24
  • 対象:2.6.10
    更新日更新者更新内容

コメント



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-11-24 (火) 07:19:57 (3129d)