1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Language-level runtime services that should reasonably expected
12 //! to be available 'everywhere'. Local heaps, GC, unwinding,
13 //! local storage, and logging. Even a 'freestanding' Rust would likely want
14 //! to implement this.
19 use alloc::boxed::{BoxAny, Box};
21 use core::atomics::{AtomicUint, SeqCst};
23 use core::kinds::marker;
30 use local_heap::LocalHeap;
34 use collections::str::SendStr;
36 /// State associated with Rust tasks.
38 /// Rust tasks are primarily built with two separate components. One is this
39 /// structure which handles standard services such as TLD, unwinding support,
40 /// naming of a task, etc. The second component is the runtime of this task, a
41 /// `Runtime` trait object.
43 /// The `Runtime` object instructs this task how it can perform critical
44 /// operations such as blocking, rescheduling, I/O constructors, etc. The two
45 /// halves are separately owned, but one is often found contained in the other.
46 /// A task's runtime can be reflected upon with the `maybe_take_runtime` method,
47 /// and otherwise its ownership is managed with `take_runtime` and
50 /// In general, this structure should not be used. This is meant to be an
51 /// unstable internal detail of the runtime itself. From time-to-time, however,
52 /// it is useful to manage tasks directly. An example of this would be
53 /// interoperating with the Rust runtime from FFI callbacks or such. For this
54 /// reason, there are two methods of note with the `Task` structure.
56 /// * `run` - This function will execute a closure inside the context of a task.
57 /// Failure is caught and handled via the task's on_exit callback. If
58 /// this fails, the task is still returned, but it can no longer be
59 /// used, it is poisoned.
61 /// * `destroy` - This is a required function to call to destroy a task. If a
62 /// task falls out of scope without calling `destroy`, its
63 /// destructor bomb will go off, aborting the process.
65 /// With these two methods, tasks can be re-used to execute code inside of its
66 /// context while having a point in the future where destruction is allowed.
67 /// More information can be found on these specific methods.
72 /// extern crate native;
76 /// // Create a task using a native runtime
77 /// let task = native::task::new((0, uint::MAX));
79 /// // Run some code, catching any possible failures
80 /// let task = task.run(|| {
81 /// // Run some code inside this task
82 /// println!("Hello with a native runtime!");
85 /// // Run some code again, catching the failure
86 /// let task = task.run(|| {
87 /// fail!("oh no, what to do!");
90 /// // Now that the task is failed, it can never be used again
91 /// assert!(task.is_destroyed());
93 /// // Deallocate the resources associated with this task
99 pub gc: GarbageCollector,
100 pub storage: LocalStorage,
101 pub unwinder: Unwinder,
104 pub name: Option<SendStr>,
106 imp: Option<Box<Runtime + Send>>,
109 pub struct TaskOpts {
110 /// Invoke this procedure with the result of the task when it finishes.
111 pub on_exit: Option<proc(Result): Send>,
112 /// A name for the task-to-be, for identification in failure messages
113 pub name: Option<SendStr>,
114 /// The size of the stack for the spawned task
115 pub stack_size: Option<uint>,
118 /// Indicates the manner in which a task exited.
120 /// A task that completes without failing is considered to exit successfully.
122 /// If you wish for this result's delivery to block until all
123 /// children tasks complete, recommend using a result future.
124 pub type Result = ::core::result::Result<(), Box<Any + Send>>;
126 pub struct GarbageCollector;
127 pub struct LocalStorage(pub Option<local_data::Map>);
129 /// A handle to a blocked task. Usually this means having the Box<Task>
130 /// pointer by ownership, but if the task is killable, a killer can steal it
132 pub enum BlockedTask {
134 Shared(Arc<AtomicUint>),
137 /// Per-task state related to task death, killing, failure, etc.
139 pub on_exit: Option<proc(Result):Send>,
140 marker: marker::NoCopy,
143 pub struct BlockedTasks {
144 inner: Arc<AtomicUint>,
148 /// Creates a new uninitialized task.
150 /// This method cannot be used to immediately invoke `run` because the task
151 /// itself will likely require a runtime to be inserted via `put_runtime`.
153 /// Note that you likely don't want to call this function, but rather the
154 /// task creation functions through libnative or libgreen.
155 pub fn new() -> Task {
157 heap: LocalHeap::new(),
158 gc: GarbageCollector,
159 storage: LocalStorage(None),
160 unwinder: Unwinder::new(),
168 /// Consumes ownership of a task, runs some code, and returns the task back.
170 /// This function can be used as an emulated "try/catch" to interoperate
171 /// with the rust runtime at the outermost boundary. It is not possible to
172 /// use this function in a nested fashion (a try/catch inside of another
173 /// try/catch). Invoking this function is quite cheap.
175 /// If the closure `f` succeeds, then the returned task can be used again
176 /// for another invocation of `run`. If the closure `f` fails then `self`
177 /// will be internally destroyed along with all of the other associated
178 /// resources of this task. The `on_exit` callback is invoked with the
179 /// cause of failure (not returned here). This can be discovered by querying
180 /// `is_destroyed()`.
182 /// Note that it is possible to view partial execution of the closure `f`
183 /// because it is not guaranteed to run to completion, but this function is
184 /// guaranteed to return if it fails. Care should be taken to ensure that
185 /// stack references made by `f` are handled appropriately.
187 /// It is invalid to call this function with a task that has been previously
188 /// destroyed via a failed call to `run`.
193 /// extern crate native;
197 /// // Create a new native task
198 /// let task = native::task::new((0, uint::MAX));
200 /// // Run some code once and then destroy this task
202 /// println!("Hello with a native runtime!");
206 pub fn run(~self, f: ||) -> Box<Task> {
207 assert!(!self.is_destroyed(), "cannot re-use a destroyed task");
209 // First, make sure that no one else is in TLS. This does not allow
210 // recursive invocations of run(). If there's no one else, then
211 // relinquish ownership of ourselves back into TLS.
212 if Local::exists(None::<Task>) {
213 fail!("cannot run a task recursively inside another");
217 // There are two primary reasons that general try/catch is unsafe. The
218 // first is that we do not support nested try/catch. The above check for
219 // an existing task in TLS is sufficient for this invariant to be
220 // upheld. The second is that unwinding while unwinding is not defined.
221 // We take care of that by having an 'unwinding' flag in the task
222 // itself. For these reasons, this unsafety should be ok.
223 let result = unsafe { unwind::try(f) };
225 // After running the closure given return the task back out if it ran
226 // successfully, or clean up the task if it failed.
227 let task: Box<Task> = Local::take();
230 Err(cause) => { task.cleanup(Err(cause)) }
234 /// Destroy all associated resources of this task.
236 /// This function will perform any necessary clean up to prepare the task
237 /// for destruction. It is required that this is called before a `Task`
238 /// falls out of scope.
240 /// The returned task cannot be used for running any more code, but it may
241 /// be used to extract the runtime as necessary.
242 pub fn destroy(~self) -> Box<Task> {
243 if self.is_destroyed() {
250 /// Cleans up a task, processing the result of the task as appropriate.
252 /// This function consumes ownership of the task, deallocating it once it's
253 /// done being processed. It is assumed that TLD and the local heap have
254 /// already been destroyed and/or annihilated.
255 fn cleanup(~self, result: Result) -> Box<Task> {
256 // The first thing to do when cleaning up is to deallocate our local
257 // resources, such as TLD and GC data.
259 // FIXME: there are a number of problems with this code
261 // 1. If any TLD object fails destruction, then all of TLD will leak.
262 // This appears to be a consequence of #14875.
264 // 2. Failing during GC annihilation aborts the runtime #14876.
266 // 3. Setting a TLD key while destroying TLD or while destroying GC will
267 // abort the runtime #14807.
269 // 4. Invoking GC in GC destructors will abort the runtime #6996.
271 // 5. The order of destruction of TLD and GC matters, but either way is
272 // susceptible to leaks (see 3/4) #8302.
274 // That being said, there are a few upshots to this code
276 // 1. If TLD destruction fails, heap destruction will be attempted.
277 // There is a test for this at fail-during-tld-destroy.rs. Sadly the
278 // other way can't be tested due to point 2 above. Note that we must
279 // immortalize the heap first because if any deallocations are
280 // attempted while TLD is being dropped it will attempt to free the
281 // allocation from the wrong heap (because the current one has been
284 // 2. One failure in destruction is tolerable, so long as the task
285 // didn't originally fail while it was running.
287 // And with all that in mind, we attempt to clean things up!
288 let mut task = self.run(|| {
289 let mut task = Local::borrow(None::<Task>);
291 let &LocalStorage(ref mut optmap) = &mut task.storage;
294 let mut heap = mem::replace(&mut task.heap, LocalHeap::new());
295 unsafe { heap.immortalize() }
298 // First, destroy task-local storage. This may run user dtors.
301 // Destroy remaining boxes. Also may run user dtors.
305 // If the above `run` block failed, then it must be the case that the
306 // task had previously succeeded. This also means that the code below
307 // was recursively run via the `run` method invoking this method. In
308 // this case, we just make sure the world is as we thought, and return.
309 if task.is_destroyed() {
310 rtassert!(result.is_ok())
314 // After taking care of the data above, we need to transmit the result
316 let what_to_do = task.death.on_exit.take();
319 // FIXME: this is running in a seriously constrained context. If this
320 // allocates GC or allocates TLD then it will likely abort the
321 // runtime. Similarly, if this fails, this will also likely abort
324 // This closure is currently limited to a channel send via the
325 // standard library's task interface, but this needs
326 // reconsideration to whether it's a reasonable thing to let a
327 // task to do or not.
329 Some(f) => { f(result) }
330 None => { drop(result) }
333 // Now that we're done, we remove the task from TLS and flag it for
335 let mut task: Box<Task> = Local::take();
336 task.destroyed = true;
340 /// Queries whether this can be destroyed or not.
341 pub fn is_destroyed(&self) -> bool { self.destroyed }
343 /// Inserts a runtime object into this task, transferring ownership to the
344 /// task. It is illegal to replace a previous runtime object in this task
345 /// with this argument.
346 pub fn put_runtime(&mut self, ops: Box<Runtime + Send>) {
347 assert!(self.imp.is_none());
348 self.imp = Some(ops);
351 /// Removes the runtime from this task, transferring ownership to the
353 pub fn take_runtime(&mut self) -> Box<Runtime + Send> {
354 assert!(self.imp.is_some());
355 self.imp.take().unwrap()
358 /// Attempts to extract the runtime as a specific type. If the runtime does
359 /// not have the provided type, then the runtime is not removed. If the
360 /// runtime does have the specified type, then it is removed and returned
361 /// (transfer of ownership).
363 /// It is recommended to only use this method when *absolutely necessary*.
364 /// This function may not be available in the future.
365 pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<Box<T>> {
366 // This is a terrible, terrible function. The general idea here is to
367 // take the runtime, cast it to Box<Any>, check if it has the right
368 // type, and then re-cast it back if necessary. The method of doing
369 // this is pretty sketchy and involves shuffling vtables of trait
370 // objects around, but it gets the job done.
372 // FIXME: This function is a serious code smell and should be avoided at
373 // all costs. I have yet to think of a method to avoid this
374 // function, and I would be saddened if more usage of the function
377 let imp = self.imp.take_unwrap();
378 let vtable = mem::transmute::<_, &raw::TraitObject>(&imp).vtable;
379 match imp.wrap().downcast::<T>() {
382 let data = mem::transmute::<_, raw::TraitObject>(t).data;
383 let obj: Box<Runtime + Send> =
384 mem::transmute(raw::TraitObject {
388 self.put_runtime(obj);
395 /// Spawns a sibling to this task. The newly spawned task is configured with
396 /// the `opts` structure and will run `f` as the body of its code.
397 pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc(): Send) {
398 let ops = self.imp.take_unwrap();
399 ops.spawn_sibling(self, opts, f)
402 /// Deschedules the current task, invoking `f` `amt` times. It is not
403 /// recommended to use this function directly, but rather communication
404 /// primitives in `std::comm` should be used.
405 pub fn deschedule(mut ~self, amt: uint,
406 f: |BlockedTask| -> ::core::result::Result<(), BlockedTask>) {
407 let ops = self.imp.take_unwrap();
408 ops.deschedule(amt, self, f)
411 /// Wakes up a previously blocked task, optionally specifying whether the
412 /// current task can accept a change in scheduling. This function can only
413 /// be called on tasks that were previously blocked in `deschedule`.
414 pub fn reawaken(mut ~self) {
415 let ops = self.imp.take_unwrap();
419 /// Yields control of this task to another task. This function will
420 /// eventually return, but possibly not immediately. This is used as an
421 /// opportunity to allow other tasks a chance to run.
422 pub fn yield_now(mut ~self) {
423 let ops = self.imp.take_unwrap();
427 /// Similar to `yield_now`, except that this function may immediately return
428 /// without yielding (depending on what the runtime decides to do).
429 pub fn maybe_yield(mut ~self) {
430 let ops = self.imp.take_unwrap();
431 ops.maybe_yield(self);
434 /// Acquires a handle to the I/O factory that this task contains, normally
435 /// stored in the task's runtime. This factory may not always be available,
436 /// which is why the return type is `Option`
437 pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
438 self.imp.get_mut_ref().local_io()
441 /// Returns the stack bounds for this task in (lo, hi) format. The stack
442 /// bounds may not be known for all tasks, so the return value may be
444 pub fn stack_bounds(&self) -> (uint, uint) {
445 self.imp.get_ref().stack_bounds()
448 /// Returns whether it is legal for this task to block the OS thread that it
450 pub fn can_block(&self) -> bool {
451 self.imp.get_ref().can_block()
457 rtdebug!("called drop for a task: {}", self as *mut Task as uint);
458 rtassert!(self.destroyed);
463 pub fn new() -> TaskOpts {
464 TaskOpts { on_exit: None, name: None, stack_size: None }
468 impl Iterator<BlockedTask> for BlockedTasks {
469 fn next(&mut self) -> Option<BlockedTask> {
470 Some(Shared(self.inner.clone()))
475 /// Returns Some if the task was successfully woken; None if already killed.
476 pub fn wake(self) -> Option<Box<Task>> {
478 Owned(task) => Some(task),
480 match arc.swap(0, SeqCst) {
482 n => Some(unsafe { mem::transmute(n) }),
488 /// Reawakens this task if ownership is acquired. If finer-grained control
489 /// is desired, use `wake` instead.
490 pub fn reawaken(self) {
491 self.wake().map(|t| t.reawaken());
494 // This assertion has two flavours because the wake involves an atomic op.
495 // In the faster version, destructors will fail dramatically instead.
496 #[cfg(not(test))] pub fn trash(self) { }
497 #[cfg(test)] pub fn trash(self) { assert!(self.wake().is_none()); }
499 /// Create a blocked task, unless the task was already killed.
500 pub fn block(task: Box<Task>) -> BlockedTask {
504 /// Converts one blocked task handle to a list of many handles to the same.
505 pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTasks> {
506 let arc = match self {
508 let flag = unsafe { AtomicUint::new(mem::transmute(task)) };
511 Shared(arc) => arc.clone(),
513 BlockedTasks{ inner: arc }.take(num_handles)
516 /// Convert to an unsafe uint value. Useful for storing in a pipe's state
519 pub unsafe fn cast_to_uint(self) -> uint {
522 let blocked_task_ptr: uint = mem::transmute(task);
523 rtassert!(blocked_task_ptr & 0x1 == 0);
527 let blocked_task_ptr: uint = mem::transmute(box arc);
528 rtassert!(blocked_task_ptr & 0x1 == 0);
529 blocked_task_ptr | 0x1
534 /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
537 pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
538 if blocked_task_ptr & 0x1 == 0 {
539 Owned(mem::transmute(blocked_task_ptr))
541 let ptr: Box<Arc<AtomicUint>> =
542 mem::transmute(blocked_task_ptr & !1);
549 pub fn new() -> Death {
550 Death { on_exit: None, marker: marker::NoCopy }
559 use std::gc::{Gc, GC};
571 local_data_key!(key: Gc<String>)
572 key.replace(Some(box(GC) "data".to_string()));
573 assert_eq!(key.get().unwrap().as_slice(), "data");
574 local_data_key!(key2: Gc<String>)
575 key2.replace(Some(box(GC) "data".to_string()));
576 assert_eq!(key2.get().unwrap().as_slice(), "data");
581 let result = task::try(proc()());
582 rtdebug!("trying first assert");
583 assert!(result.is_ok());
584 let result = task::try::<()>(proc() fail!());
585 rtdebug!("trying second assert");
586 assert!(result.is_err());
591 use std::rand::{StdRng, Rng};
592 let mut r = StdRng::new().ok().unwrap();
593 let _ = r.next_u32();
598 let (tx, rx) = channel();
600 assert!(rx.recv() == 10);
604 fn comm_shared_chan() {
605 let (tx, rx) = channel();
607 assert!(rx.recv() == 10);
612 use std::cell::RefCell;
615 next: Option<Gc<RefCell<List>>>,
618 let a = box(GC) RefCell::new(List { next: None });
619 let b = box(GC) RefCell::new(List { next: Some(a) });
622 let mut a = a.borrow_mut();
629 fn test_begin_unwind() {
630 use std::rt::unwind::begin_unwind;
631 begin_unwind("cause", file!(), line!())
634 // Task blocking tests
637 fn block_and_wake() {
638 let task = box Task::new();
639 let mut task = BlockedTask::block(task).wake().unwrap();
640 task.destroyed = true;