Linux 2.6.12 内核 进程 1 的创建(五)
现在进程 1 所需要的我们都已经创建好了。可以说是万事俱备只欠东风!
那么怎么能让进程1运行呢,我们必须把进程1的进程描述符插入到 cpu 的活动运行队列中去,这样只要再调用 schedule() 那么进程1便可运行啦!废话少说马上进入 wake_up_new_task() 函数!
void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
{
把新创建进程添加到 cpu 运行队列中去
unsigned long flags;
int this_cpu, cpu;
runqueue_t *rq, *this_rq;
rq = task_rq_lock(p, &flags);
锁住运行队列结构。并获得cpu运行队列指针!
cpu = task_cpu(p);
获得新创建进程的 cpu 编号
this_cpu = smp_processor_id();
获得当前cpu编号
BUG_ON(p->state != TASK_RUNNING);
/*
* We decrease the sleep average of forking parents
* and children as well, to keep max-interactive tasks
* from forking tasks that are max-interactive. The parent
* (current) is done further down, under its lock.
*/
p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) *
CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
计算进程的平均睡眠值
p->prio = effective_prio(p);
设置进程的动态优先权(100-139)
进程的静态优先级 static_prio 用于计算进程的时间片,而动态优先级作为调度器选择合适的进程的依据!
if (likely(cpu == this_cpu)) {
if (!(clone_flags & CLONE_VM)) {
/*
* The VM isn't cloned, so we're in a good position to
* do child-runs-first in anticipation of an exec. This
* usually avoids a lot of COW overhead.
*/
if (unlikely(!current->array))
__activate_task(p, rq);
else {
p->prio = current->prio;
list_add_tail(&p->run_list, ¤t->run_list);
p->array = current->array;
p->array->nr_active++;
rq->nr_running++;
}
set_need_resched();
} else
/* Run child last */
__activate_task(p, rq);
添加到runqueue中
/*
* We skip the following code due to cpu == this_cpu
*
* task_rq_unlock(rq, &flags);
* this_rq = task_rq_lock(current, &flags);
*/
this_rq = rq;
} else {
this_rq = cpu_rq(this_cpu);
/*
* Not the local CPU - must adjust timestamp. This should
* get optimised away in the !CONFIG_SMP case.
*/
p->timestamp = (p->timestamp - this_rq->timestamp_last_tick)
+ rq->timestamp_last_tick;
__activate_task(p, rq);
if (TASK_PREEMPTS_CURR(p, rq))
resched_task(rq->curr);
/*
* Parent and child are on different CPUs, now get the
* parent runqueue to update the parent's ->sleep_avg:
*/
task_rq_unlock(rq, &flags);
this_rq = task_rq_lock(current, &flags);
}
current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *
PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);
task_rq_unlock(this_rq, &flags);
}</pre>
<p></p>
<pre class="brush: cpp; title: ; notranslate" title=""> static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
__acquires(rq->lock) {
struct runqueue *rq;
repeat_lock_task:
local_irq_save(*flags);
rq = task_rq(p);
spin_lock(&rq->lock);
if (unlikely(rq != task_rq(p))) {
spin_unlock_irqrestore(&rq->lock, *flags);
goto repeat_lock_task;
}
return rq; }
</pre>
<pre class="brush: cpp; title: ; notranslate" title=""> #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
</pre>
取得每cpu变量per_cpu_runqueues本地拷贝的地址
</p>
<pre>
static inline unsigned int task_cpu(const struct task_struct *p)
{
return p->thread_info->cpu;
}</pre>
</p>
<pre>
static int effective_prio(task_t *p)
{
int bonus, prio;
if (rt_task(p))
return p->prio;
首先判断是否为实时进程!(prio<100)
bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;
获得创建进程的奖惩
prio = p->static_prio - bonus;
if (prio < MAX_RT_PRIO)
prio = MAX_RT_PRIO;
if (prio > MAX_PRIO-1)
prio = MAX_PRIO-1;
return prio;
}</pre>
</p>
<pre>
static inline void __activate_task(task_t *p, runqueue_t *rq)
{
enqueue_task(p, rq->active);
rq->nr_running++;
更新队列中可运行进程数!
}</pre>
</p>
<pre>
static void enqueue_task(struct task_struct *p, prio_array_t *array)
{
sched_info_queued(p);
list_add_tail(&p->run_list, array->queue + p->prio);
根据进程的动态优先级,把进程描述符添加到活动链表中!
__set_bit(p->prio, array->bitmap);
根据 prio 把 active 链表中相应进程位图置 1!位数代表优先级,表示此优先级有活动的进程!schedule() 函数正是根据位图中的哪位是1,到相应数组链表中去选择下一个要运行的进程!
array->nr_active++;
更新优先级链表中可运行进程数目!
p->array = array;
进程描述符中的array字段指向活动进程链表
}</pre>
至此,进程 1 成功创建完毕,但是创建归创建(只是创建了一些数据结构,并且添加到 cpu 运行队列中去),此时新创建的进程还没有运行,接下来就是 schedule() 这个主调度器的事情了 。。。。。。