struct csched2_runqueue_data {
spinlock_t lock; /* Lock for this runqueue */
+ struct list_head rql; /* List of runqueues */
struct list_head runq; /* Ordered list of runnable vms */
+ unsigned int refcnt; /* How many CPUs reference this runqueue */
+ /* (including not yet active ones) */
unsigned int nr_cpus; /* How many CPUs are sharing this runqueue */
+ /* (only active ones) */
int id; /* ID of this runqueue (-1 if invalid) */
int load; /* Instantaneous load (num of non-idle units) */
unsigned int load_window_shift; /* Lenght of load decaying window */
unsigned int ratelimit_us; /* Rate limiting for this scheduler */
- cpumask_t active_queues; /* Runqueues with (maybe) active cpus */
- struct csched2_runqueue_data *rqd; /* Data of the various runqueues */
+ unsigned int active_queues; /* Number of active runqueues */
+ struct list_head rql; /* List of runqueues */
cpumask_t initialized; /* CPUs part of this scheduler */
struct list_head sdom; /* List of domains (for debug key) */
*/
struct csched2_pcpu {
cpumask_t sibling_mask; /* Siblings in the same runqueue */
- int runq_id;
+ struct csched2_runqueue_data *rqd; /* Runqueue for this CPU */
};
/*
/* CPU to runq_id macro */
static inline int c2r(unsigned int cpu)
{
- return csched2_pcpu(cpu)->runq_id;
+ return csched2_pcpu(cpu)->rqd->id;
}
/* CPU to runqueue struct macro */
-static inline struct csched2_runqueue_data *c2rqd(const struct scheduler *ops,
- unsigned int cpu)
+static inline struct csched2_runqueue_data *c2rqd(unsigned int cpu)
{
- return &csched2_priv(ops)->rqd[c2r(cpu)];
+ return csched2_pcpu(cpu)->rqd;
}
/* Does the domain of this unit have a cap? */
return list_entry(elem, struct csched2_unit, runq_elem);
}
-static void activate_runqueue(struct csched2_private *prv, int rqi)
-{
- struct csched2_runqueue_data *rqd;
-
- rqd = prv->rqd + rqi;
-
- BUG_ON(!cpumask_empty(&rqd->active));
-
- rqd->max_weight = 1;
- rqd->id = rqi;
- INIT_LIST_HEAD(&rqd->svc);
- INIT_LIST_HEAD(&rqd->runq);
- spin_lock_init(&rqd->lock);
-
- __cpumask_set_cpu(rqi, &prv->active_queues);
-}
-
-static void deactivate_runqueue(struct csched2_private *prv, int rqi)
-{
- struct csched2_runqueue_data *rqd;
-
- rqd = prv->rqd + rqi;
-
- BUG_ON(!cpumask_empty(&rqd->active));
-
- rqd->id = -1;
-
- __cpumask_clear_cpu(rqi, &prv->active_queues);
-}
-
static inline bool same_node(unsigned int cpua, unsigned int cpub)
{
return cpu_to_node(cpua) == cpu_to_node(cpub);
cpu_to_core(cpua) == cpu_to_core(cpub);
}
-static unsigned int
-cpu_to_runqueue(const struct csched2_private *prv, unsigned int cpu)
+static struct csched2_runqueue_data *
+cpu_add_to_runqueue(struct csched2_private *prv, unsigned int cpu)
{
- const struct csched2_runqueue_data *rqd;
- unsigned int rqi;
+ struct csched2_runqueue_data *rqd, *rqd_new;
+ struct list_head *rqd_ins;
+ unsigned long flags;
+ int rqi = 0;
+ bool rqi_unused = false, rqd_valid = false;
- for ( rqi = 0; rqi < nr_cpu_ids; rqi++ )
+ /* Prealloc in case we need it - not allowed with interrupts off. */
+ rqd_new = xzalloc(struct csched2_runqueue_data);
+
+ write_lock_irqsave(&prv->lock, flags);
+
+ rqd_ins = &prv->rql;
+ list_for_each_entry ( rqd, &prv->rql, rql )
{
unsigned int peer_cpu;
- /*
- * As soon as we come across an uninitialized runqueue, use it.
- * In fact, either:
- * - we are initializing the first cpu, and we assign it to
- * runqueue 0. This is handy, especially if we are dealing
- * with the boot cpu (if credit2 is the default scheduler),
- * as we would not be able to use cpu_to_socket() and similar
- * helpers anyway (they're result of which is not reliable yet);
- * - we have gone through all the active runqueues, and have not
- * found anyone whose cpus' topology matches the one we are
- * dealing with, so activating a new runqueue is what we want.
- */
- if ( prv->rqd[rqi].id == -1 )
- break;
-
- rqd = prv->rqd + rqi;
- BUG_ON(cpumask_empty(&rqd->active));
+ /* Remember first unused queue index. */
+ if ( !rqi_unused && rqd->id > rqi )
+ rqi_unused = true;
- peer_cpu = cpumask_first(&rqd->active);
+ peer_cpu = rqd->pick_bias;
BUG_ON(cpu_to_socket(cpu) == XEN_INVALID_SOCKET_ID ||
cpu_to_socket(peer_cpu) == XEN_INVALID_SOCKET_ID);
- if (opt_runqueue == OPT_RUNQUEUE_CPU)
- continue;
+ /* OPT_RUNQUEUE_CPU will never find an existing runqueue. */
if ( opt_runqueue == OPT_RUNQUEUE_ALL ||
(opt_runqueue == OPT_RUNQUEUE_CORE && same_core(peer_cpu, cpu)) ||
(opt_runqueue == OPT_RUNQUEUE_SOCKET && same_socket(peer_cpu, cpu)) ||
(opt_runqueue == OPT_RUNQUEUE_NODE && same_node(peer_cpu, cpu)) )
+ {
+ rqd_valid = true;
break;
+ }
+
+ if ( !rqi_unused )
+ {
+ rqi++;
+ rqd_ins = &rqd->rql;
+ }
+ }
+
+ if ( !rqd_valid )
+ {
+ if ( !rqd_new )
+ {
+ rqd = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+ rqd = rqd_new;
+ rqd_new = NULL;
+
+ list_add(&rqd->rql, rqd_ins);
+ rqd->pick_bias = cpu;
+ rqd->id = rqi;
}
- /* We really expect to be able to assign each cpu to a runqueue. */
- BUG_ON(rqi >= nr_cpu_ids);
+ rqd->refcnt++;
- return rqi;
+ out:
+ write_unlock_irqrestore(&prv->lock, flags);
+
+ xfree(rqd_new);
+
+ return rqd;
}
/* Find the domain with the highest weight. */
}
static void
-runq_assign(const struct scheduler *ops, const struct sched_unit *unit)
+runq_assign(const struct sched_unit *unit)
{
struct csched2_unit *svc = unit->priv;
ASSERT(svc->rqd == NULL);
- _runq_assign(svc, c2rqd(ops, sched_unit_master(unit)));
+ _runq_assign(svc, c2rqd(sched_unit_master(unit)));
}
static void
}
static void
-runq_deassign(const struct scheduler *ops, const struct sched_unit *unit)
+runq_deassign(const struct sched_unit *unit)
{
struct csched2_unit *svc = unit->priv;
- ASSERT(svc->rqd == c2rqd(ops, sched_unit_master(unit)));
+ ASSERT(svc->rqd == c2rqd(sched_unit_master(unit)));
_runq_deassign(svc);
}
update_svc_load(ops, svc, change, now);
}
-static void
-runq_insert(const struct scheduler *ops, struct csched2_unit *svc)
+static void runq_insert(struct csched2_unit *svc)
{
struct list_head *iter;
unsigned int cpu = sched_unit_master(svc->unit);
- struct list_head * runq = &c2rqd(ops, cpu)->runq;
+ struct list_head *runq = &c2rqd(cpu)->runq;
int pos = 0;
ASSERT(spin_is_locked(get_sched_res(cpu)->schedule_lock));
static s_time_t tickle_score(const struct scheduler *ops, s_time_t now,
const struct csched2_unit *new, unsigned int cpu)
{
- struct csched2_runqueue_data *rqd = c2rqd(ops, cpu);
+ struct csched2_runqueue_data *rqd = c2rqd(cpu);
struct csched2_unit * cur = csched2_unit(curr_on_cpu(cpu));
const struct csched2_private *prv = csched2_priv(ops);
s_time_t score;
s_time_t max = 0;
struct sched_unit *unit = new->unit;
unsigned int bs, cpu = sched_unit_master(unit);
- struct csched2_runqueue_data *rqd = c2rqd(ops, cpu);
+ struct csched2_runqueue_data *rqd = c2rqd(cpu);
const cpumask_t *online = cpupool_domain_master_cpumask(unit->domain);
cpumask_t mask;
/*
* Credit-related code
*/
-static void reset_credit(const struct scheduler *ops, int cpu, s_time_t now,
- struct csched2_unit *snext)
+static void reset_credit(int cpu, s_time_t now, struct csched2_unit *snext)
{
- struct csched2_runqueue_data *rqd = c2rqd(ops, cpu);
+ struct csched2_runqueue_data *rqd = c2rqd(cpu);
struct list_head *iter;
int m;
* for the newly replenished budget.
*/
ASSERT( svc->rqd != NULL );
- ASSERT( c2rqd(ops, sched_unit_master(svc->unit)) == svc->rqd );
+ ASSERT( c2rqd(sched_unit_master(svc->unit)) == svc->rqd );
__set_bit(__CSFLAG_delayed_runq_add, &svc->flags);
}
else if ( unit_runnable(svc->unit) )
*/
now = NOW();
update_load(ops, svc->rqd, svc, 1, now);
- runq_insert(ops, svc);
+ runq_insert(svc);
runq_tickle(ops, svc, now);
}
list_del_init(&svc->parked_elem);
}
else if ( unit_on_runq(svc) )
{
- ASSERT(svc->rqd == c2rqd(ops, sched_unit_master(unit)));
+ ASSERT(svc->rqd == c2rqd(sched_unit_master(unit)));
update_load(ops, svc->rqd, svc, -1, NOW());
runq_remove(svc);
}
/* Add into the new runqueue if necessary */
if ( svc->rqd == NULL )
- runq_assign(ops, unit);
+ runq_assign(unit);
else
- ASSERT(c2rqd(ops, sched_unit_master(unit)) == svc->rqd );
+ ASSERT(c2rqd(sched_unit_master(unit)) == svc->rqd );
now = NOW();
update_load(ops, svc->rqd, svc, 1, now);
/* Put the UNIT on the runq */
- runq_insert(ops, svc);
+ runq_insert(svc);
runq_tickle(ops, svc, now);
out:
LIST_HEAD(were_parked);
ASSERT(is_idle_unit(unit) ||
- svc->rqd == c2rqd(ops, sched_unit_master(unit)));
+ svc->rqd == c2rqd(sched_unit_master(unit)));
/* This unit is now eligible to be put on the runqueue again */
__clear_bit(__CSFLAG_scheduled, &svc->flags);
{
ASSERT(!unit_on_runq(svc));
- runq_insert(ops, svc);
+ runq_insert(svc);
runq_tickle(ops, svc, now);
}
else if ( !is_idle_unit(unit) )
csched2_res_pick(const struct scheduler *ops, const struct sched_unit *unit)
{
struct csched2_private *prv = csched2_priv(ops);
- int i, min_rqi = -1, min_s_rqi = -1;
unsigned int new_cpu, cpu = sched_unit_master(unit);
struct csched2_unit *svc = csched2_unit(unit);
s_time_t min_avgload = MAX_LOAD, min_s_avgload = MAX_LOAD;
bool has_soft;
+ struct csched2_runqueue_data *rqd, *min_rqd = NULL, *min_s_rqd = NULL;
- ASSERT(!cpumask_empty(&prv->active_queues));
+ ASSERT(!list_empty(&prv->rql));
SCHED_STAT_CRANK(pick_resource);
* Find both runqueues in one pass.
*/
has_soft = has_soft_affinity(unit);
- for_each_cpu(i, &prv->active_queues)
+ list_for_each_entry ( rqd, &prv->rql, rql )
{
- struct csched2_runqueue_data *rqd;
s_time_t rqd_avgload = MAX_LOAD;
- rqd = prv->rqd + i;
-
/*
* If none of the cpus of this runqueue is in svc's hard-affinity,
* skip the runqueue.
if ( cpumask_intersects(&mask, unit->cpu_soft_affinity) )
{
min_s_avgload = rqd_avgload;
- min_s_rqi = i;
+ min_s_rqd = rqd;
}
}
/* In any case, keep the "hard-affinity minimum" updated too. */
if ( rqd_avgload < min_avgload )
{
min_avgload = rqd_avgload;
- min_rqi = i;
+ min_rqd = rqd;
}
}
- if ( has_soft && min_s_rqi != -1 )
+ if ( has_soft && min_s_rqd )
{
/*
* We have soft affinity, and we have a candidate runq, so go for it.
cpumask_and(cpumask_scratch_cpu(cpu), cpumask_scratch_cpu(cpu),
unit->cpu_soft_affinity);
cpumask_and(cpumask_scratch_cpu(cpu), cpumask_scratch_cpu(cpu),
- &prv->rqd[min_s_rqi].active);
+ &min_s_rqd->active);
}
- else if ( min_rqi != -1 )
+ else if ( min_rqd )
{
/*
* Either we don't have soft-affinity, or we do, but we did not find
* with the cpus of the runq.
*/
cpumask_and(cpumask_scratch_cpu(cpu), cpumask_scratch_cpu(cpu),
- &prv->rqd[min_rqi].active);
+ &min_rqd->active);
}
else
{
* contention).
*/
new_cpu = get_fallback_cpu(svc);
- min_rqi = c2r(new_cpu);
- min_avgload = prv->rqd[min_rqi].b_avgload;
+ min_rqd = c2rqd(new_cpu);
+ min_avgload = min_rqd->b_avgload;
goto out_up;
}
- new_cpu = cpumask_cycle(prv->rqd[min_rqi].pick_bias,
- cpumask_scratch_cpu(cpu));
- prv->rqd[min_rqi].pick_bias = new_cpu;
+ new_cpu = cpumask_cycle(min_rqd->pick_bias, cpumask_scratch_cpu(cpu));
+ min_rqd->pick_bias = new_cpu;
BUG_ON(new_cpu >= nr_cpu_ids);
out_up:
} d;
d.dom = unit->domain->domain_id;
d.unit = unit->unit_id;
- d.rq_id = min_rqi;
+ d.rq_id = min_rqd->id;
d.b_avgload = min_avgload;
d.new_cpu = new_cpu;
__trace_var(TRC_CSCHED2_PICKED_CPU, 1,
if ( on_runq )
{
update_load(ops, svc->rqd, NULL, 1, now);
- runq_insert(ops, svc);
+ runq_insert(svc);
runq_tickle(ops, svc, now);
SCHED_STAT_CRANK(migrate_on_runq);
}
static void balance_load(const struct scheduler *ops, int cpu, s_time_t now)
{
struct csched2_private *prv = csched2_priv(ops);
- int i, max_delta_rqi;
struct list_head *push_iter, *pull_iter;
bool inner_load_updated = 0;
+ struct csched2_runqueue_data *rqd, *max_delta_rqd;
balance_state_t st = { .best_push_svc = NULL, .best_pull_svc = NULL };
*/
ASSERT(spin_is_locked(get_sched_res(cpu)->schedule_lock));
- st.lrqd = c2rqd(ops, cpu);
+ st.lrqd = c2rqd(cpu);
update_runq_load(ops, st.lrqd, 0, now);
retry:
- max_delta_rqi = -1;
+ max_delta_rqd = NULL;
if ( !read_trylock(&prv->lock) )
return;
st.load_delta = 0;
- for_each_cpu(i, &prv->active_queues)
+ list_for_each_entry ( rqd, &prv->rql, rql )
{
s_time_t delta;
- st.orqd = prv->rqd + i;
+ st.orqd = rqd;
if ( st.orqd == st.lrqd
|| !spin_trylock(&st.orqd->lock) )
if ( delta > st.load_delta )
{
st.load_delta = delta;
- max_delta_rqi = i;
+ max_delta_rqd = rqd;
}
spin_unlock(&st.orqd->lock);
/* Minimize holding the private scheduler lock. */
read_unlock(&prv->lock);
- if ( max_delta_rqi == -1 )
+ if ( !max_delta_rqd )
goto out;
{
if ( st.orqd->b_avgload > load_max )
load_max = st.orqd->b_avgload;
- cpus_max = st.lrqd->nr_cpus;
- i = st.orqd->nr_cpus;
- if ( i > cpus_max )
- cpus_max = i;
+ cpus_max = max(st.lrqd->nr_cpus, st.orqd->nr_cpus);
if ( unlikely(tb_init_done) )
{
* meantime, try the process over again. This can't deadlock
* because if it doesn't get any other rqd locks, it will simply
* give up and return. */
- st.orqd = prv->rqd + max_delta_rqi;
+ st.orqd = max_delta_rqd;
if ( !spin_trylock(&st.orqd->lock) )
goto retry;
ASSERT(cpumask_test_cpu(new_cpu, &csched2_priv(ops)->initialized));
ASSERT(cpumask_test_cpu(new_cpu, unit->cpu_hard_affinity));
- trqd = c2rqd(ops, new_cpu);
+ trqd = c2rqd(new_cpu);
/*
* Do the actual movement toward new_cpu, and update vc->processor.
struct csched2_unit *svc = csched2_unit(unit);
spinlock_t *lock = unit_schedule_lock(unit);
- ASSERT(svc->rqd == c2rqd(ops, sched_unit_master(unit)));
+ ASSERT(svc->rqd == c2rqd(sched_unit_master(unit)));
svc->weight = sdom->weight;
update_max_weight(svc->rqd, svc->weight, old_weight);
if ( unit->is_running )
{
unsigned int cpu = sched_unit_master(unit);
- struct csched2_runqueue_data *rqd = c2rqd(ops, cpu);
+ struct csched2_runqueue_data *rqd = c2rqd(cpu);
ASSERT(curr_on_cpu(cpu) == unit);
lock = unit_schedule_lock_irq(unit);
/* Add unit to runqueue of initial processor */
- runq_assign(ops, unit);
+ runq_assign(unit);
unit_schedule_unlock_irq(lock, unit);
/* Remove from runqueue */
lock = unit_schedule_lock_irq(unit);
- runq_deassign(ops, unit);
+ runq_deassign(unit);
unit_schedule_unlock_irq(lock, unit);
{
s_time_t time, min_time;
int rt_credit; /* Proposed runtime measured in credits */
- struct csched2_runqueue_data *rqd = c2rqd(ops, cpu);
+ struct csched2_runqueue_data *rqd = c2rqd(cpu);
struct list_head *runq = &rqd->runq;
const struct csched2_private *prv = csched2_priv(ops);
BUG_ON(!cpumask_test_cpu(sched_cpu, &csched2_priv(ops)->initialized));
- rqd = c2rqd(ops, sched_cpu);
+ rqd = c2rqd(sched_cpu);
BUG_ON(!cpumask_test_cpu(sched_cpu, &rqd->active));
ASSERT(spin_is_locked(get_sched_res(sched_cpu)->schedule_lock));
*/
if ( skipped_units == 0 && snext->credit <= CSCHED2_CREDIT_RESET )
{
- reset_credit(ops, sched_cpu, now, snext);
+ reset_credit(sched_cpu, now, snext);
balance_load(ops, sched_cpu, now);
}
struct list_head *iter_sdom;
struct csched2_private *prv = csched2_priv(ops);
unsigned long flags;
- unsigned int i, j, loop;
+ unsigned int j, loop;
+ struct csched2_runqueue_data *rqd;
/*
* We need the private scheduler lock as we access global
printk("Active queues: %d\n"
"\tdefault-weight = %d\n",
- cpumask_weight(&prv->active_queues),
+ prv->active_queues,
CSCHED2_DEFAULT_WEIGHT);
- for_each_cpu(i, &prv->active_queues)
+ list_for_each_entry ( rqd, &prv->rql, rql )
{
s_time_t fraction;
- fraction = (prv->rqd[i].avgload * 100) >> prv->load_precision_shift;
+ fraction = (rqd->avgload * 100) >> prv->load_precision_shift;
printk("Runqueue %d:\n"
"\tncpus = %u\n"
"\tpick_bias = %u\n"
"\tinstload = %d\n"
"\taveload = %"PRI_stime" (~%"PRI_stime"%%)\n",
- i,
- prv->rqd[i].nr_cpus,
- CPUMASK_PR(&prv->rqd[i].active),
- prv->rqd[i].max_weight,
- prv->rqd[i].pick_bias,
- prv->rqd[i].load,
- prv->rqd[i].avgload,
+ rqd->id,
+ rqd->nr_cpus,
+ CPUMASK_PR(&rqd->active),
+ rqd->max_weight,
+ rqd->pick_bias,
+ rqd->load,
+ rqd->avgload,
fraction);
printk("\tidlers: %*pb\n"
"\ttickled: %*pb\n"
"\tfully idle cores: %*pb\n",
- CPUMASK_PR(&prv->rqd[i].idle),
- CPUMASK_PR(&prv->rqd[i].tickled),
- CPUMASK_PR(&prv->rqd[i].smt_idle));
+ CPUMASK_PR(&rqd->idle),
+ CPUMASK_PR(&rqd->tickled),
+ CPUMASK_PR(&rqd->smt_idle));
}
printk("Domain info:\n");
}
}
- for_each_cpu(i, &prv->active_queues)
+ list_for_each_entry ( rqd, &prv->rql, rql )
{
- struct csched2_runqueue_data *rqd = prv->rqd + i;
struct list_head *iter, *runq = &rqd->runq;
int loop = 0;
/* We need the lock to scan the runqueue. */
spin_lock(&rqd->lock);
- printk("Runqueue %d:\n", i);
+ printk("Runqueue %d:\n", rqd->id);
for_each_cpu(j, &rqd->active)
dump_pcpu(ops, j);
static void *
csched2_alloc_pdata(const struct scheduler *ops, int cpu)
{
+ struct csched2_private *prv = csched2_priv(ops);
struct csched2_pcpu *spc;
+ struct csched2_runqueue_data *rqd;
spc = xzalloc(struct csched2_pcpu);
if ( spc == NULL )
return ERR_PTR(-ENOMEM);
- /* Not in any runqueue yet */
- spc->runq_id = -1;
+ rqd = cpu_add_to_runqueue(prv, cpu);
+ if ( IS_ERR(rqd) )
+ {
+ xfree(spc);
+ return rqd;
+ }
+
+ spc->rqd = rqd;
return spc;
}
/* Returns the ID of the runqueue the cpu is assigned to. */
-static unsigned
+static struct csched2_runqueue_data *
init_pdata(struct csched2_private *prv, struct csched2_pcpu *spc,
unsigned int cpu)
{
ASSERT(rw_is_write_locked(&prv->lock));
ASSERT(!cpumask_test_cpu(cpu, &prv->initialized));
/* CPU data needs to be allocated, but still uninitialized. */
- ASSERT(spc && spc->runq_id == -1);
+ ASSERT(spc);
- /* Figure out which runqueue to put it in */
- spc->runq_id = cpu_to_runqueue(prv, cpu);
+ rqd = spc->rqd;
- rqd = prv->rqd + spc->runq_id;
+ ASSERT(rqd && !cpumask_test_cpu(cpu, &spc->rqd->active));
- printk(XENLOG_INFO "Adding cpu %d to runqueue %d\n", cpu, spc->runq_id);
- if ( ! cpumask_test_cpu(spc->runq_id, &prv->active_queues) )
+ printk(XENLOG_INFO "Adding cpu %d to runqueue %d\n", cpu, rqd->id);
+ if ( !rqd->nr_cpus )
{
printk(XENLOG_INFO " First cpu on runqueue, activating\n");
- activate_runqueue(prv, spc->runq_id);
+
+ BUG_ON(!cpumask_empty(&rqd->active));
+ rqd->max_weight = 1;
+ INIT_LIST_HEAD(&rqd->svc);
+ INIT_LIST_HEAD(&rqd->runq);
+ spin_lock_init(&rqd->lock);
+ prv->active_queues++;
}
__cpumask_set_cpu(cpu, &spc->sibling_mask);
if ( rqd->nr_cpus == 1 )
rqd->pick_bias = cpu;
- return spc->runq_id;
+ return rqd;
}
/* Change the scheduler of cpu to us (Credit2). */
{
struct csched2_private *prv = csched2_priv(new_ops);
struct csched2_unit *svc = vdata;
- unsigned rqi;
+ struct csched2_runqueue_data *rqd;
ASSERT(pdata && svc && is_idle_unit(svc->unit));
sched_idle_unit(cpu)->priv = vdata;
- rqi = init_pdata(prv, pdata, cpu);
+ rqd = init_pdata(prv, pdata, cpu);
/*
* Now that we know what runqueue we'll go in, double check what's said
* this scheduler, and so it's safe to have taken it /before/ our
* private global lock.
*/
- ASSERT(get_sched_res(cpu)->schedule_lock != &prv->rqd[rqi].lock);
+ ASSERT(get_sched_res(cpu)->schedule_lock != &rqd->lock);
write_unlock(&prv->lock);
- return &prv->rqd[rqi].lock;
+ return &rqd->lock;
}
static void
write_lock_irqsave(&prv->lock, flags);
- /*
- * alloc_pdata is not implemented, so pcpu must be NULL. On the other
- * hand, init_pdata must have been called for this pCPU.
- */
/*
* Scheduler specific data for this pCPU must still be there and and be
* valid. In fact, if we are here:
* 2. init_pdata must have been called on this cpu, and deinit_pdata
* (us!) must not have been called on it already.
*/
- ASSERT(spc && spc->runq_id != -1);
+ ASSERT(spc && spc->rqd);
ASSERT(cpumask_test_cpu(cpu, &prv->initialized));
/* Find the old runqueue and remove this cpu from it */
- rqd = prv->rqd + spc->runq_id;
+ rqd = spc->rqd;
/* No need to save IRQs here, they're already disabled */
spin_lock(&rqd->lock);
- printk(XENLOG_INFO "Removing cpu %d from runqueue %d\n", cpu, spc->runq_id);
+ printk(XENLOG_INFO "Removing cpu %d from runqueue %d\n", cpu, rqd->id);
__cpumask_clear_cpu(cpu, &rqd->idle);
__cpumask_clear_cpu(cpu, &rqd->smt_idle);
__cpumask_clear_cpu(cpu, &rqd->active);
+ __cpumask_clear_cpu(cpu, &rqd->tickled);
for_each_cpu ( rcpu, &rqd->active )
__cpumask_clear_cpu(cpu, &csched2_pcpu(rcpu)->sibling_mask);
if ( rqd->nr_cpus == 0 )
{
printk(XENLOG_INFO " No cpus left on runqueue, disabling\n");
- deactivate_runqueue(prv, spc->runq_id);
+
+ BUG_ON(!cpumask_empty(&rqd->active));
+ prv->active_queues--;
}
else if ( rqd->pick_bias == cpu )
rqd->pick_bias = cpumask_first(&rqd->active);
- spc->runq_id = -1;
-
spin_unlock(&rqd->lock);
__cpumask_clear_cpu(cpu, &prv->initialized);
static void
csched2_free_pdata(const struct scheduler *ops, void *pcpu, int cpu)
{
+ struct csched2_private *prv = csched2_priv(ops);
struct csched2_pcpu *spc = pcpu;
+ struct csched2_runqueue_data *rqd;
+ unsigned long flags;
- /*
- * pcpu either points to a valid struct csched2_pcpu, or is NULL (if
- * CPU bringup failed, and we're beeing called from CPU_UP_CANCELLED).
- * xfree() does not really mind, but we want to be sure that either
- * init_pdata has never been called, or deinit_pdata has been called
- * already.
- */
- ASSERT(!pcpu || spc->runq_id == -1);
- ASSERT(!cpumask_test_cpu(cpu, &csched2_priv(ops)->initialized));
+ if ( !spc )
+ return;
+
+ write_lock_irqsave(&prv->lock, flags);
+
+ rqd = spc->rqd;
+ ASSERT(rqd && rqd->refcnt);
+ ASSERT(!cpumask_test_cpu(cpu, &prv->initialized));
+
+ rqd->refcnt--;
+ if ( !rqd->refcnt )
+ list_del(&rqd->rql);
+ else
+ rqd = NULL;
+
+ write_unlock_irqrestore(&prv->lock, flags);
+ xfree(rqd);
xfree(pcpu);
}
static int
csched2_init(struct scheduler *ops)
{
- int i;
struct csched2_private *prv;
printk("Initializing Credit2 scheduler\n");
ops->sched_data = prv;
rwlock_init(&prv->lock);
+ INIT_LIST_HEAD(&prv->rql);
INIT_LIST_HEAD(&prv->sdom);
- /* Allocate all runqueues and mark them as un-initialized */
- prv->rqd = xzalloc_array(struct csched2_runqueue_data, nr_cpu_ids);
- if ( !prv->rqd )
- {
- xfree(prv);
- return -ENOMEM;
- }
- for ( i = 0; i < nr_cpu_ids; i++ )
- prv->rqd[i].id = -1;
-
/* initialize ratelimit */
prv->ratelimit_us = sched_ratelimit_us;
prv = csched2_priv(ops);
ops->sched_data = NULL;
- if ( prv )
- xfree(prv->rqd);
xfree(prv);
}