diff --git a/src/lib/comm.rs b/src/lib/comm.rs index 44c1a2ce341..f6d150bc295 100644 --- a/src/lib/comm.rs +++ b/src/lib/comm.rs @@ -7,6 +7,12 @@ Communication between tasks is facilitated by ports (in the receiving task), and channels (in the sending task). Any number of channels may feed into a single port. +Ports and channels may only transmit values of unique types; that is, +values that are statically guaranteed to be accessed by a single +'owner' at a time. Unique types include scalars, vectors, strings, +and records, tags, tuples and unique boxes (~T) thereof. Most notably, +shared boxes (@T) may not be transmitted across channels. + Example: > use std::task; diff --git a/src/lib/task.rs b/src/lib/task.rs index f90ebe45ed9..41585684720 100644 --- a/src/lib/task.rs +++ b/src/lib/task.rs @@ -2,6 +2,29 @@ Module: task Task management. + +An executing Rust program consists of a tree of tasks, each with their own +stack, and sole ownership of their allocated heap data. Tasks communicate +with each other using ports and channels. + +When a task fails, that failure will propagate to its parent (the task +that spawned it) and the parent will fail as well. The reverse is not +true: when a parent task fails its children will continue executing. When +the root (main) task fails, all tasks fail, and then so does the entire +process. + +A task may remove itself from this failure propagation mechanism by +calling the function, after which failure will only +result in the termination of that task. + +Tasks may execute in parallel and are scheduled automatically by the runtime. + +Example: + +> spawn("Hello, World", fn (&&msg: str) { +> log msg; +> }); + */ import cast = unsafe::reinterpret_cast; import comm; @@ -49,6 +72,8 @@ native "c-stack-cdecl" mod rustrt2 = "rustrt" { fn migrate_alloc(alloc: *u8, target: task_id); } +/* Section: Types */ + type rust_task = {id: task, mutable notify_enabled: u32, @@ -58,24 +83,85 @@ type rust_task = resource rust_task_ptr(task: *rust_task) { rustrt2::drop_task(task); } type task_id = int; + +/* +Type: task + +A handle to a task +*/ type task = task_id; + +/* +Type: joinable_task + +A task that sends notification upon termination +*/ type joinable_task = (task, comm::port); +/* +Tag: task_result + +Indicates the manner in which a task exited +*/ +tag task_result { + /* Variant: tr_success */ + tr_success; + /* Variant: tr_failure */ + tr_failure; +} + +/* +Tag: task_notification + +Message sent upon task exit to indicate normal or abnormal termination +*/ +tag task_notification { + /* Variant: exit */ + exit(task, task_result); +} + +/* Section: Operations */ + +/* +Type: get_task + +Retreives a handle to the currently executing task +*/ fn get_task() -> task { rustrt2::get_task_id() } -/** - * Hints the scheduler to yield this task for a specified ammount of time. - * - * arg: time_in_us maximum number of microseconds to yield control for - */ +/* +Function: sleep + +Hints the scheduler to yield this task for a specified ammount of time. + +Parameters: + +time_in_us - maximum number of microseconds to yield control for +*/ fn sleep(time_in_us: uint) { ret rustrt::task_sleep(time_in_us); } +/* +Function: yield + +Yield control to the task scheduler + +The scheduler may schedule another task to execute. +*/ fn yield() { ret rustrt::task_yield(); } -tag task_result { tr_success; tr_failure; } +/* +Function: join -tag task_notification { exit(task, task_result); } +Wait for a child task to exit +The child task must have been spawned with , which +produces a notification port that the child uses to communicate its +exit status. + +Returns: + +A task_result indicating whether the task terminated normally or failed +*/ fn join(task_port: joinable_task) -> task_result { let (id, port) = task_port; alt comm::recv::(port) { @@ -87,23 +173,88 @@ fn join(task_port: joinable_task) -> task_result { } } +/* +Function: unsupervise + +Detaches this task from its parent in the task tree + +An unsupervised task will not propagate its failure up the task tree +*/ fn unsupervise() { ret sys::unsupervise(); } +/* +Function: pin + +Pins the current task and future child tasks to a single scheduler thread +*/ fn pin() { rustrt2::pin_task(); } +/* +Function: unpin + +Unpin the current task and future child tasks +*/ fn unpin() { rustrt2::unpin_task(); } +/* +Function: set_min_stack + +Set the minimum stack size (in bytes) for tasks spawned in the future. + +This function has global effect and should probably not be used. +*/ fn set_min_stack(stack_size: uint) { rustrt2::set_min_stack(stack_size); } +/* +Function: spawn + +Creates and executes a new child task + +Sets up a new task with its own call stack and schedules it to be executed. +Upon execution the new task will call function `f` with the provided +argument `data`. + +Function `f` is a bare function, meaning it may not close over any data, as do +shared functions (fn@) and lambda blocks. `data` must be a uniquely owned +type; it is moved into the new task and thus can no longer be accessed +locally. + +Parameters: + +data - A unique-type value to pass to the new task +f - A function to execute in the new task + +Returns: + +A handle to the new task +*/ fn spawn(-data: T, f: fn(T)) -> task { spawn_inner(data, f, none) } +/* +Function: spawn_notify + +Create and execute a new child task, requesting notification upon its +termination + +Immediately before termination, either on success or failure, the spawned +task will send a message on the provided channel. +*/ fn spawn_notify(-data: T, f: fn(T), notify: comm::chan) -> task { spawn_inner(data, f, some(notify)) } +/* +Function: spawn_joinable + +Create and execute a task which can later be joined with the function + +This is a convenience wrapper around spawn_notify which, when paired +with can be easily used to spawn a task then wait for it to +complete. +*/ fn spawn_joinable(-data: T, f: fn(T)) -> joinable_task { let p = comm::port::(); let id = spawn_notify(data, f, comm::chan::(p));