/* * Debug related code, dump vcpu/cpu information */ static void rt_dump_vcpu(const struct scheduler *ops, const struct rt_vcpu *svc) { char cpustr[1024]; cpumask_t *cpupool_mask; ASSERT(svc != NULL); /* idle vcpu */ if( svc->sdom == NULL ) { printk("\n"); return; } cpumask_scnprintf(cpustr, sizeof(cpustr), svc->vcpu->cpu_hard_affinity); printk("[%5d.%-2u] cpu %u, (%"PRI_stime", %"PRI_stime")," " cur_b=%"PRI_stime" cur_d=%"PRI_stime" last_start=%"PRI_stime"\n" " \t\t onQ=%d runnable=%d cpu_hard_affinity=%s ", svc->vcpu->domain->domain_id, svc->vcpu->vcpu_id, svc->vcpu->processor, svc->period, svc->budget, svc->cur_budget, svc->cur_deadline, svc->last_start, __vcpu_on_q(svc), vcpu_runnable(svc->vcpu), cpustr); memset(cpustr, 0, sizeof(cpustr)); cpupool_mask = cpupool_scheduler_cpumask(svc->vcpu->domain->cpupool); cpumask_scnprintf(cpustr, sizeof(cpustr), cpupool_mask); printk("cpupool=%s\n", cpustr); }
/* * Debug related code, dump vcpu/cpu information */ static void rt_dump_vcpu(struct rt_vcpu *svc) { char *cpustr = keyhandler_scratch; if ( svc == NULL ) { printk("NULL!\n"); return; } cpumask_scnprintf(cpustr, sizeof(cpustr), svc->vcpu->cpu_hard_affinity); printk("OCBP:_dumpP: [%5d.%-2d] cpu %d, Period %"PRId64", Budget_low %"PRId64", Budget_high %"PRId64", Deadline %"PRId64",Criticality %d,Offline_flag %d, cur_b=%"PRId64",onR=%d runnable=%d cpu_hard_affinity=%s", svc->vcpu->domain->domain_id, svc->vcpu->vcpu_id, svc->vcpu->processor, svc->period, svc->budget_low, svc->budget_high, svc->deadline, svc->criticality_vcpu, svc->offl_flag, svc->cur_budget, __vcpu_on_runq(svc), vcpu_runnable(svc->vcpu), cpustr); memset(cpustr, 0, sizeof(char)*1024); cpumask_scnprintf(cpustr, sizeof(cpustr), cpupool_scheduler_cpumask(svc->vcpu->domain->cpupool)); printk("cpupool=%s\n", cpustr); }
void vcpu_sleep_sync(struct vcpu *v) { vcpu_sleep_nosync(v); while ( !vcpu_runnable(v) && v->is_running ) cpu_relax(); sync_vcpu_execstate(v); }
void vcpu_sleep_nosync(struct vcpu *v) { unsigned long flags; vcpu_schedule_lock_irqsave(v, flags); if ( likely(!vcpu_runnable(v)) ) { if ( v->runstate.state == RUNSTATE_runnable ) vcpu_runstate_change(v, RUNSTATE_offline, NOW()); SCHED_OP(sleep, v); } vcpu_schedule_unlock_irqrestore(v, flags); TRACE_2D(TRC_SCHED_SLEEP, v->domain->domain_id, v->vcpu_id); }
/* * Debug related code, dump vcpu/cpu information */ static void rt_dump_vcpu(const struct scheduler *ops, const struct rt_vcpu *svc) { cpumask_t *cpupool_mask, *mask; ASSERT(svc != NULL); /* idle vcpu */ if( svc->sdom == NULL ) { printk("\n"); return; } /* * We can't just use 'cpumask_scratch' because the dumping can * happen from a pCPU outside of this scheduler's cpupool, and * hence it's not right to use the pCPU's scratch mask (which * may even not exist!). On the other hand, it is safe to use * svc->vcpu->processor's own scratch space, since we hold the * runqueue lock. */ mask = _cpumask_scratch[svc->vcpu->processor]; cpupool_mask = cpupool_domain_cpumask(svc->vcpu->domain); cpumask_and(mask, cpupool_mask, svc->vcpu->cpu_hard_affinity); cpulist_scnprintf(keyhandler_scratch, sizeof(keyhandler_scratch), mask); printk("[%5d.%-2u] cpu %u, (%"PRI_stime", %"PRI_stime")," " cur_b=%"PRI_stime" cur_d=%"PRI_stime" last_start=%"PRI_stime"\n" " \t\t onQ=%d runnable=%d flags=%x effective hard_affinity=%s\n", svc->vcpu->domain->domain_id, svc->vcpu->vcpu_id, svc->vcpu->processor, svc->period, svc->budget, svc->cur_budget, svc->cur_deadline, svc->last_start, __vcpu_on_q(svc), vcpu_runnable(svc->vcpu), svc->flags, keyhandler_scratch); }
void vcpu_wake(struct vcpu *v) { unsigned long flags; vcpu_schedule_lock_irqsave(v, flags); if ( likely(vcpu_runnable(v)) ) { if ( v->runstate.state >= RUNSTATE_blocked ) vcpu_runstate_change(v, RUNSTATE_runnable, NOW()); SCHED_OP(wake, v); } else if ( !test_bit(_VPF_blocked, &v->pause_flags) ) { if ( v->runstate.state == RUNSTATE_blocked ) vcpu_runstate_change(v, RUNSTATE_offline, NOW()); } vcpu_schedule_unlock_irqrestore(v, flags); TRACE_2D(TRC_SCHED_WAKE, v->domain->domain_id, v->vcpu_id); }
/** * Xen scheduler callback function to select a VCPU to run. * This is the main scheduler routine. * * @param ops Pointer to this instance of the scheduler structure * @param now Current time * * @return Address of the VCPU structure scheduled to be run next * Amount of time to execute the returned VCPU * Flag for whether the VCPU was migrated */ static struct task_slice a653sched_do_schedule( const struct scheduler *ops, s_time_t now, bool_t tasklet_work_scheduled) { struct task_slice ret; /* hold the chosen domain */ struct vcpu * new_task = NULL; static unsigned int sched_index = 0; static s_time_t next_switch_time; a653sched_priv_t *sched_priv = SCHED_PRIV(ops); const unsigned int cpu = smp_processor_id(); unsigned long flags; spin_lock_irqsave(&sched_priv->lock, flags); if ( sched_priv->num_schedule_entries < 1 ) sched_priv->next_major_frame = now + DEFAULT_TIMESLICE; else if ( now >= sched_priv->next_major_frame ) { /* time to enter a new major frame * the first time this function is called, this will be true */ /* start with the first domain in the schedule */ sched_index = 0; sched_priv->next_major_frame = now + sched_priv->major_frame; next_switch_time = now + sched_priv->schedule[0].runtime; } else { while ( (now >= next_switch_time) && (sched_index < sched_priv->num_schedule_entries) ) { /* time to switch to the next domain in this major frame */ sched_index++; next_switch_time += sched_priv->schedule[sched_index].runtime; } } /* * If we exhausted the domains in the schedule and still have time left * in the major frame then switch next at the next major frame. */ if ( sched_index >= sched_priv->num_schedule_entries ) next_switch_time = sched_priv->next_major_frame; /* * If there are more domains to run in the current major frame, set * new_task equal to the address of next domain's VCPU structure. * Otherwise, set new_task equal to the address of the idle task's VCPU * structure. */ new_task = (sched_index < sched_priv->num_schedule_entries) ? sched_priv->schedule[sched_index].vc : IDLETASK(cpu); /* Check to see if the new task can be run (awake & runnable). */ if ( !((new_task != NULL) && (AVCPU(new_task) != NULL) && AVCPU(new_task)->awake && vcpu_runnable(new_task)) ) new_task = IDLETASK(cpu); BUG_ON(new_task == NULL); /* * Check to make sure we did not miss a major frame. * This is a good test for robust partitioning. */ BUG_ON(now >= sched_priv->next_major_frame); spin_unlock_irqrestore(&sched_priv->lock, flags); /* Tasklet work (which runs in idle VCPU context) overrides all else. */ if ( tasklet_work_scheduled ) new_task = IDLETASK(cpu); /* Running this task would result in a migration */ if ( !is_idle_vcpu(new_task) && (new_task->processor != cpu) ) new_task = IDLETASK(cpu); /* * Return the amount of time the next domain has to run and the address * of the selected task's VCPU structure. */ ret.time = next_switch_time - now; ret.task = new_task; ret.migrated = 0; BUG_ON(ret.time <= 0); return ret; }