added functionality to tell schedulers to refuse to run tasks that are not pinned to them

This commit is contained in:
toddaaro 2013-06-12 14:55:32 -07:00
parent 8428081958
commit 4224fc7aad
2 changed files with 60 additions and 18 deletions

View File

@ -70,7 +70,9 @@ pub struct Scheduler {
/// An action performed after a context switch on behalf of the
/// code running before the context switch
priv cleanup_job: Option<CleanupJob>,
metrics: SchedMetrics
metrics: SchedMetrics,
/// Should this scheduler run any task, or only pinned tasks?
run_anything: bool
}
pub struct SchedHandle {
@ -136,6 +138,16 @@ pub impl Scheduler {
sleeper_list: SleeperList)
-> Scheduler {
Scheduler::new_special(event_loop, work_queue, sleeper_list, true)
}
fn new_special(event_loop: ~EventLoopObject,
work_queue: WorkQueue<~Coroutine>,
sleeper_list: SleeperList,
run_anything: bool)
-> Scheduler {
// Lazily initialize the runtime TLS key
local_ptr::init_tls_key();
@ -150,7 +162,8 @@ pub impl Scheduler {
saved_context: Context::empty(),
current_task: None,
cleanup_job: None,
metrics: SchedMetrics::new()
metrics: SchedMetrics::new(),
run_anything: run_anything
}
}
@ -429,19 +442,28 @@ pub impl Scheduler {
assert!(!self.in_task_context());
rtdebug!("looking in work queue for task to schedule");
let mut this = self;
match this.work_queue.pop() {
Some(task) => {
rtdebug!("resuming task from work queue");
this.resume_task_immediately(task);
return true;
}
None => {
rtdebug!("no tasks in queue");
Local::put(this);
return false;
if this.run_anything {
match this.work_queue.pop() {
Some(task) => {
rtdebug!("resuming task from work queue");
this.resume_task_immediately(task);
return true;
}
None => {
rtdebug!("no tasks in queue");
Local::put(this);
return false;
}
}
} else {
// In this branch we have a scheduler that is not allowed
// to run unpinned tasks. As such it will only get tasks
// to run from the message queue.
rtdebug!("skipping resume_task_from_queue");
Local::put(this);
return false;
}
}

View File

@ -157,23 +157,43 @@ pub fn run_in_mt_newsched_task_random_homed() {
let mut handles = ~[];
let mut scheds = ~[];
for uint::range(0, nthreads) |_| {
// create a few special schedulers, those with even indicies
// will be pinned-only
for uint::range(0, nthreads) |i| {
let special = (i % 2) == 0;
let loop_ = ~UvEventLoop::new();
let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
let mut sched = ~Scheduler::new_special(loop_, work_queue.clone(), sleepers.clone(), special);
let handle = sched.make_handle();
handles.push(handle);
scheds.push(sched);
}
}
// Schedule a pile o tasks
let n = 120*stress_factor();
let n = 5*stress_factor();
for uint::range(0,n) |_i| {
rtdebug!("creating task: %u", _i);
let hf: ~fn() = || { assert!(true) };
spawntask_homed(&mut scheds, hf);
}
let f: ~fn() = || { assert!(true); };
// Now we want another pile o tasks that do not ever run on a
// special scheduler, because they are normal tasks. Because
// we can we put these in the "main" task.
let n = 5*stress_factor();
let f: ~fn() = || {
for uint::range(0,n) |_| {
let f: ~fn() = || {
// Borrow the scheduler we run on and check if it is
// privliged.
do Local::borrow::<Scheduler,()> |sched| {
assert!(sched.run_anything);
};
};
spawntask_random(f);
};
};
let f_cell = Cell(f);
let handles = Cell(handles);