Xen Guest Domain中的Idle Process
在traditional operating system中,有一个Idle Process:当OS里面没有任何task的时候,就靠Idle Process来空转CPU在virtualization的环境下,如果还这么“空转”,显然是对CPU cycles的一种浪费。很自然的想法:当Guest Domain不需要CPU的时候,自动让出CPU给其他domain使用。这也是work-conserving的一种methodology。
Xen对Guest Domain里的Idle Process进行了改写,调用hypercall来代替原来的while (1)。 Follow me:-)
------------------------------------------------------------------
cpu_idle
xen_idle
safe_halt
raw_safe_halt
HYPERVISOR_block
HYPERVISOR_sched_op(SCHEDOP_block, NULL)
SCHEDOP_block
do_block: 这个函数只有在SCHEDOP_block时才被调用,也就是说,只有Guest Domain的Idle Process可以引发do_block
-------------------------------------------------------------------
总这么block住也不行是吧,那啥时候被wake up呢?
容我再想想...
(1) ...
(2) ...
...
看看do_block哈:)
/* Block the currently-executing domain until a pertinent event occurs. */
static long do_block(void)
{
struct vcpu *v = current;
local_event_delivery_enable();
set_bit(_VPF_blocked, &v->pause_flags);
/* Check for events /after/ blocking: avoids wakeup waiting race. */
if ( local_events_need_delivery() ) {
clear_bit(_VPF_blocked, &v->pause_flags);
} else {
raise_softirq(SCHEDULE_SOFTIRQ); //哥决定让出CPU啦...
}
return 0;
}
static void schedule(void)
{
struct vcpu *prev = current, *next = NULL;
s_time_t now = NOW();
struct schedule_data *sd =sd = &this_cpu(schedule_data);
struct task_slice next_slice;
/* get policy-specific decision on scheduling... */
next_slice = ops.do_schedule(now);
next = next_slice.task;
sd->curr = next;
... ...
ASSERT(prev->runstate.state == RUNSTATE_running);
if (test_bit(_VPF_blocked, &prev->pause_flags)) { // do_block之后,应该跑到这里就对啦
vcpu_runstate_change(prev, RUNSTATE_blocked, now);
} else {
if (vcpu_runnable(prev))
vcpu_runstate_change(prev, RUNSTATE_runnable, now);
else
vcpu_runstate_change(prev, RUNSTATE_offline, now);
}
prev->last_run_time = now;
.........
context_switch(prev, next);
}
static struct task_slicecsched_schedule(s_time_t now)
{
const int cpu = smp_processor_id();
struct list_head * const runq = RUNQ(cpu);
struct csched_vcpu * const scurr = CSCHED_VCPU(current);
if ( vcpu_runnable(current) ) { // current如果还runnable,就继续插入runq;否则就已经不在runq里了
__runq_insert(cpu, scurr);
} else {
BUG_ON(is_idle_vcpu(current));
BUG_ON(list_empty(runq));
}
... ...
}
static inline int vcpu_runnable(struct vcpu *v)
{
if ( (v->pause_flags == 0) &&
(atomic_read(&v->pause_count) == 0) &&
(atomic_read(&v->domain->pause_count) == 0)) {
return true;
} else {
return false;
}
}
页:
[1]