Give tasks useful names. #2891
This commit is contained in:
@@ -316,12 +316,14 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
|
|||||||
// Just put an unpinned task onto one of the default schedulers.
|
// Just put an unpinned task onto one of the default schedulers.
|
||||||
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, main);
|
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, main);
|
||||||
main_task.death.on_exit = Some(on_exit);
|
main_task.death.on_exit = Some(on_exit);
|
||||||
|
main_task.name = Some(~"main");
|
||||||
scheds[0].enqueue_task(main_task);
|
scheds[0].enqueue_task(main_task);
|
||||||
}
|
}
|
||||||
Some(ref mut main_sched) => {
|
Some(ref mut main_sched) => {
|
||||||
let home = Sched(main_sched.make_handle());
|
let home = Sched(main_sched.make_handle());
|
||||||
let mut main_task = ~Task::new_root_homed(&mut scheds[0].stack_pool, home, main);
|
let mut main_task = ~Task::new_root_homed(&mut scheds[0].stack_pool, home, main);
|
||||||
main_task.death.on_exit = Some(on_exit);
|
main_task.death.on_exit = Some(on_exit);
|
||||||
|
main_task.name = Some(~"main");
|
||||||
main_sched.enqueue_task(main_task);
|
main_sched.enqueue_task(main_task);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,7 +40,9 @@ pub struct Task {
|
|||||||
taskgroup: Option<Taskgroup>,
|
taskgroup: Option<Taskgroup>,
|
||||||
death: Death,
|
death: Death,
|
||||||
destroyed: bool,
|
destroyed: bool,
|
||||||
coroutine: Option<~Coroutine>
|
coroutine: Option<~Coroutine>,
|
||||||
|
// FIXME(#6874/#7599) use StringRef to save on allocations
|
||||||
|
name: Option<~str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Coroutine {
|
pub struct Coroutine {
|
||||||
@@ -90,7 +92,8 @@ impl Task {
|
|||||||
taskgroup: None,
|
taskgroup: None,
|
||||||
death: Death::new(),
|
death: Death::new(),
|
||||||
destroyed: false,
|
destroyed: false,
|
||||||
coroutine: Some(~Coroutine::new(stack_pool, start))
|
coroutine: Some(~Coroutine::new(stack_pool, start)),
|
||||||
|
name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +112,8 @@ impl Task {
|
|||||||
// FIXME(#7544) make watching optional
|
// FIXME(#7544) make watching optional
|
||||||
death: self.death.new_child(),
|
death: self.death.new_child(),
|
||||||
destroyed: false,
|
destroyed: false,
|
||||||
coroutine: Some(~Coroutine::new(stack_pool, start))
|
coroutine: Some(~Coroutine::new(stack_pool, start)),
|
||||||
|
name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,12 +137,13 @@ impl FailWithCause for &'static str {
|
|||||||
|
|
||||||
// FIXME #4427: Temporary until rt::rt_fail_ goes away
|
// FIXME #4427: Temporary until rt::rt_fail_ goes away
|
||||||
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
|
pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
|
||||||
use cell::Cell;
|
|
||||||
use either::Left;
|
use either::Left;
|
||||||
|
use option::{Some, None};
|
||||||
use rt::{context, OldTaskContext, TaskContext};
|
use rt::{context, OldTaskContext, TaskContext};
|
||||||
use rt::task::Task;
|
use rt::task::Task;
|
||||||
use rt::local::Local;
|
use rt::local::Local;
|
||||||
use rt::logging::Logger;
|
use rt::logging::Logger;
|
||||||
|
use str::Str;
|
||||||
|
|
||||||
let context = context();
|
let context = context();
|
||||||
match context {
|
match context {
|
||||||
@@ -159,20 +160,26 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
|
|||||||
let msg = str::raw::from_c_str(msg);
|
let msg = str::raw::from_c_str(msg);
|
||||||
let file = str::raw::from_c_str(file);
|
let file = str::raw::from_c_str(file);
|
||||||
|
|
||||||
let outmsg = fmt!("task failed at '%s', %s:%i",
|
|
||||||
msg, file, line as int);
|
|
||||||
|
|
||||||
// XXX: Logging doesn't work correctly in non-task context because it
|
// XXX: Logging doesn't work correctly in non-task context because it
|
||||||
// invokes the local heap
|
// invokes the local heap
|
||||||
if context == TaskContext {
|
if context == TaskContext {
|
||||||
// XXX: Logging doesn't work here - the check to call the log
|
// XXX: Logging doesn't work here - the check to call the log
|
||||||
// function never passes - so calling the log function directly.
|
// function never passes - so calling the log function directly.
|
||||||
let outmsg = Cell::new(outmsg);
|
|
||||||
do Local::borrow::<Task, ()> |task| {
|
do Local::borrow::<Task, ()> |task| {
|
||||||
task.logger.log(Left(outmsg.take()));
|
let msg = match task.name {
|
||||||
|
Some(ref name) =>
|
||||||
|
fmt!("task '%s' failed at '%s', %s:%i",
|
||||||
|
name.as_slice(), msg, file, line as int),
|
||||||
|
None =>
|
||||||
|
fmt!("task <unnamed> failed at '%s', %s:%i",
|
||||||
|
msg, file, line as int)
|
||||||
|
};
|
||||||
|
|
||||||
|
task.logger.log(Left(msg));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rterrln!("%s", outmsg);
|
rterrln!("failed in non-task context at '%s', %s:%i",
|
||||||
|
msg, file, line as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
gc::cleanup_stack_for_failure();
|
gc::cleanup_stack_for_failure();
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ pub struct SchedOpts {
|
|||||||
*
|
*
|
||||||
* * notify_chan - Enable lifecycle notifications on the given channel
|
* * notify_chan - Enable lifecycle notifications on the given channel
|
||||||
*
|
*
|
||||||
|
* * name - A name for the task-to-be, for identification in failure messages.
|
||||||
|
*
|
||||||
* * sched - Specify the configuration of a new scheduler to create the task
|
* * sched - Specify the configuration of a new scheduler to create the task
|
||||||
* in
|
* in
|
||||||
*
|
*
|
||||||
@@ -139,6 +141,7 @@ pub struct TaskOpts {
|
|||||||
watched: bool,
|
watched: bool,
|
||||||
indestructible: bool,
|
indestructible: bool,
|
||||||
notify_chan: Option<Chan<TaskResult>>,
|
notify_chan: Option<Chan<TaskResult>>,
|
||||||
|
name: Option<~str>,
|
||||||
sched: SchedOpts
|
sched: SchedOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +188,7 @@ impl TaskBuilder {
|
|||||||
self.consumed = true;
|
self.consumed = true;
|
||||||
let gen_body = self.gen_body.take();
|
let gen_body = self.gen_body.take();
|
||||||
let notify_chan = self.opts.notify_chan.take();
|
let notify_chan = self.opts.notify_chan.take();
|
||||||
|
let name = self.opts.name.take();
|
||||||
TaskBuilder {
|
TaskBuilder {
|
||||||
opts: TaskOpts {
|
opts: TaskOpts {
|
||||||
linked: self.opts.linked,
|
linked: self.opts.linked,
|
||||||
@@ -192,6 +196,7 @@ impl TaskBuilder {
|
|||||||
watched: self.opts.watched,
|
watched: self.opts.watched,
|
||||||
indestructible: self.opts.indestructible,
|
indestructible: self.opts.indestructible,
|
||||||
notify_chan: notify_chan,
|
notify_chan: notify_chan,
|
||||||
|
name: name,
|
||||||
sched: self.opts.sched
|
sched: self.opts.sched
|
||||||
},
|
},
|
||||||
gen_body: gen_body,
|
gen_body: gen_body,
|
||||||
@@ -199,9 +204,7 @@ impl TaskBuilder {
|
|||||||
consumed: false
|
consumed: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TaskBuilder {
|
|
||||||
/// Decouple the child task's failure from the parent's. If either fails,
|
/// Decouple the child task's failure from the parent's. If either fails,
|
||||||
/// the other will not be killed.
|
/// the other will not be killed.
|
||||||
pub fn unlinked(&mut self) {
|
pub fn unlinked(&mut self) {
|
||||||
@@ -281,6 +284,12 @@ impl TaskBuilder {
|
|||||||
self.opts.notify_chan = Some(notify_pipe_ch);
|
self.opts.notify_chan = Some(notify_pipe_ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Name the task-to-be. Currently the name is used for identification
|
||||||
|
/// only in failure messages.
|
||||||
|
pub fn name(&mut self, name: ~str) {
|
||||||
|
self.opts.name = Some(name);
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure a custom scheduler mode for the task.
|
/// Configure a custom scheduler mode for the task.
|
||||||
pub fn sched_mode(&mut self, mode: SchedMode) {
|
pub fn sched_mode(&mut self, mode: SchedMode) {
|
||||||
self.opts.sched.mode = mode;
|
self.opts.sched.mode = mode;
|
||||||
@@ -333,6 +342,7 @@ impl TaskBuilder {
|
|||||||
pub fn spawn(&mut self, f: ~fn()) {
|
pub fn spawn(&mut self, f: ~fn()) {
|
||||||
let gen_body = self.gen_body.take();
|
let gen_body = self.gen_body.take();
|
||||||
let notify_chan = self.opts.notify_chan.take();
|
let notify_chan = self.opts.notify_chan.take();
|
||||||
|
let name = self.opts.name.take();
|
||||||
let x = self.consume();
|
let x = self.consume();
|
||||||
let opts = TaskOpts {
|
let opts = TaskOpts {
|
||||||
linked: x.opts.linked,
|
linked: x.opts.linked,
|
||||||
@@ -340,6 +350,7 @@ impl TaskBuilder {
|
|||||||
watched: x.opts.watched,
|
watched: x.opts.watched,
|
||||||
indestructible: x.opts.indestructible,
|
indestructible: x.opts.indestructible,
|
||||||
notify_chan: notify_chan,
|
notify_chan: notify_chan,
|
||||||
|
name: name,
|
||||||
sched: x.opts.sched
|
sched: x.opts.sched
|
||||||
};
|
};
|
||||||
let f = match gen_body {
|
let f = match gen_body {
|
||||||
@@ -408,6 +419,7 @@ pub fn default_task_opts() -> TaskOpts {
|
|||||||
watched: true,
|
watched: true,
|
||||||
indestructible: false,
|
indestructible: false,
|
||||||
notify_chan: None,
|
notify_chan: None,
|
||||||
|
name: None,
|
||||||
sched: SchedOpts {
|
sched: SchedOpts {
|
||||||
mode: DefaultScheduler,
|
mode: DefaultScheduler,
|
||||||
}
|
}
|
||||||
@@ -507,6 +519,21 @@ pub fn try<T:Send>(f: ~fn() -> T) -> Result<T,()> {
|
|||||||
|
|
||||||
/* Lifecycle functions */
|
/* Lifecycle functions */
|
||||||
|
|
||||||
|
/// Read the name of the current task.
|
||||||
|
pub fn with_task_name<U>(blk: &fn(Option<&str>) -> U) -> U {
|
||||||
|
use rt::task::Task;
|
||||||
|
|
||||||
|
match context() {
|
||||||
|
TaskContext => do Local::borrow::<Task, U> |task| {
|
||||||
|
match task.name {
|
||||||
|
Some(ref name) => blk(Some(name.as_slice())),
|
||||||
|
None => blk(None)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => fail!("no task name exists in %?", context()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn yield() {
|
pub fn yield() {
|
||||||
//! Yield control to the task scheduler
|
//! Yield control to the task scheduler
|
||||||
|
|
||||||
@@ -805,6 +832,34 @@ fn test_spawn_linked_sup_propagate_sibling() {
|
|||||||
fail!();
|
fail!();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_unnamed_task() {
|
||||||
|
use rt::test::run_in_newsched_task;
|
||||||
|
|
||||||
|
do run_in_newsched_task {
|
||||||
|
do spawn {
|
||||||
|
do with_task_name |name| {
|
||||||
|
assert!(name.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_named_task() {
|
||||||
|
use rt::test::run_in_newsched_task;
|
||||||
|
|
||||||
|
do run_in_newsched_task {
|
||||||
|
let mut t = task();
|
||||||
|
t.name(~"ada lovelace");
|
||||||
|
do t.spawn {
|
||||||
|
do with_task_name |name| {
|
||||||
|
assert!(name.get() == "ada lovelace");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_run_basic() {
|
fn test_run_basic() {
|
||||||
let (po, ch) = stream::<()>();
|
let (po, ch) = stream::<()>();
|
||||||
|
|||||||
@@ -726,6 +726,8 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) {
|
|||||||
task.death.on_exit = Some(on_exit);
|
task.death.on_exit = Some(on_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task.name = opts.name.take();
|
||||||
|
|
||||||
rtdebug!("spawn about to take scheduler");
|
rtdebug!("spawn about to take scheduler");
|
||||||
|
|
||||||
let sched = Local::take::<Scheduler>();
|
let sched = Local::take::<Scheduler>();
|
||||||
|
|||||||
Reference in New Issue
Block a user