]> git.lizzy.rs Git - rust.git/blob - src/librustrt/task.rs
return &mut T from the arenas, not &T
[rust.git] / src / librustrt / task.rs
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.
4 //
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.
10
11 //! Language-level runtime services that should reasonably expected
12 //! to be available 'everywhere'. Unwinding, local storage, and logging.
13 //! Even a 'freestanding' Rust would likely want to implement this.
14
15 use alloc::arc::Arc;
16 use alloc::boxed::{BoxAny, Box};
17 use core::any::Any;
18 use core::atomic::{AtomicUint, SeqCst};
19 use core::iter::Take;
20 use core::kinds::marker;
21 use core::mem;
22 use core::prelude::{Clone, Drop, Err, Iterator, None, Ok, Option, Send, Some};
23 use core::prelude::{drop};
24 use core::raw;
25
26 use local_data;
27 use Runtime;
28 use local::Local;
29 use rtio::LocalIo;
30 use unwind;
31 use unwind::Unwinder;
32 use collections::str::SendStr;
33
34 /// State associated with Rust tasks.
35 ///
36 /// Rust tasks are primarily built with two separate components. One is this
37 /// structure which handles standard services such as TLD, unwinding support,
38 /// naming of a task, etc. The second component is the runtime of this task, a
39 /// `Runtime` trait object.
40 ///
41 /// The `Runtime` object instructs this task how it can perform critical
42 /// operations such as blocking, rescheduling, I/O constructors, etc. The two
43 /// halves are separately owned, but one is often found contained in the other.
44 /// A task's runtime can be reflected upon with the `maybe_take_runtime` method,
45 /// and otherwise its ownership is managed with `take_runtime` and
46 /// `put_runtime`.
47 ///
48 /// In general, this structure should not be used. This is meant to be an
49 /// unstable internal detail of the runtime itself. From time-to-time, however,
50 /// it is useful to manage tasks directly. An example of this would be
51 /// interoperating with the Rust runtime from FFI callbacks or such. For this
52 /// reason, there are two methods of note with the `Task` structure.
53 ///
54 /// * `run` - This function will execute a closure inside the context of a task.
55 ///           Failure is caught and handled via the task's on_exit callback. If
56 ///           this fails, the task is still returned, but it can no longer be
57 ///           used, it is poisoned.
58 ///
59 /// * `destroy` - This is a required function to call to destroy a task. If a
60 ///               task falls out of scope without calling `destroy`, its
61 ///               destructor bomb will go off, aborting the process.
62 ///
63 /// With these two methods, tasks can be re-used to execute code inside of its
64 /// context while having a point in the future where destruction is allowed.
65 /// More information can be found on these specific methods.
66 ///
67 /// # Example
68 ///
69 /// ```no_run
70 /// extern crate native;
71 /// use std::uint;
72 /// # fn main() {
73 ///
74 /// // Create a task using a native runtime
75 /// let task = native::task::new((0, uint::MAX), 0);
76 ///
77 /// // Run some code, catching any possible failures
78 /// let task = task.run(|| {
79 ///     // Run some code inside this task
80 ///     println!("Hello with a native runtime!");
81 /// });
82 ///
83 /// // Run some code again, catching the failure
84 /// let task = task.run(|| {
85 ///     fail!("oh no, what to do!");
86 /// });
87 ///
88 /// // Now that the task is failed, it can never be used again
89 /// assert!(task.is_destroyed());
90 ///
91 /// // Deallocate the resources associated with this task
92 /// task.destroy();
93 /// # }
94 /// ```
95 pub struct Task {
96     pub storage: LocalStorage,
97     pub unwinder: Unwinder,
98     pub death: Death,
99     pub name: Option<SendStr>,
100
101     state: TaskState,
102     imp: Option<Box<Runtime + Send + 'static>>,
103 }
104
105 // Once a task has entered the `Armed` state it must be destroyed via `drop`,
106 // and no other method. This state is used to track this transition.
107 #[deriving(PartialEq)]
108 enum TaskState {
109     New,
110     Armed,
111     Destroyed,
112 }
113
114 pub struct TaskOpts {
115     /// Invoke this procedure with the result of the task when it finishes.
116     pub on_exit: Option<proc(Result): Send>,
117     /// A name for the task-to-be, for identification in failure messages
118     pub name: Option<SendStr>,
119     /// The size of the stack for the spawned task
120     pub stack_size: Option<uint>,
121 }
122
123 /// Indicates the manner in which a task exited.
124 ///
125 /// A task that completes without failing is considered to exit successfully.
126 ///
127 /// If you wish for this result's delivery to block until all
128 /// children tasks complete, recommend using a result future.
129 pub type Result = ::core::result::Result<(), Box<Any + Send>>;
130
131 pub struct LocalStorage(pub Option<local_data::Map>);
132
133 /// A handle to a blocked task. Usually this means having the Box<Task>
134 /// pointer by ownership, but if the task is killable, a killer can steal it
135 /// at any time.
136 pub enum BlockedTask {
137     Owned(Box<Task>),
138     Shared(Arc<AtomicUint>),
139 }
140
141 /// Per-task state related to task death, killing, failure, etc.
142 pub struct Death {
143     pub on_exit: Option<proc(Result):Send>,
144     marker: marker::NoCopy,
145 }
146
147 pub struct BlockedTasks {
148     inner: Arc<AtomicUint>,
149 }
150
151 impl Task {
152     /// Creates a new uninitialized task.
153     ///
154     /// This method cannot be used to immediately invoke `run` because the task
155     /// itself will likely require a runtime to be inserted via `put_runtime`.
156     ///
157     /// Note that you likely don't want to call this function, but rather the
158     /// task creation functions through libnative or libgreen.
159     pub fn new() -> Task {
160         Task {
161             storage: LocalStorage(None),
162             unwinder: Unwinder::new(),
163             death: Death::new(),
164             state: New,
165             name: None,
166             imp: None,
167         }
168     }
169
170     /// Consumes ownership of a task, runs some code, and returns the task back.
171     ///
172     /// This function can be used as an emulated "try/catch" to interoperate
173     /// with the rust runtime at the outermost boundary. It is not possible to
174     /// use this function in a nested fashion (a try/catch inside of another
175     /// try/catch). Invoking this function is quite cheap.
176     ///
177     /// If the closure `f` succeeds, then the returned task can be used again
178     /// for another invocation of `run`. If the closure `f` fails then `self`
179     /// will be internally destroyed along with all of the other associated
180     /// resources of this task. The `on_exit` callback is invoked with the
181     /// cause of failure (not returned here). This can be discovered by querying
182     /// `is_destroyed()`.
183     ///
184     /// Note that it is possible to view partial execution of the closure `f`
185     /// because it is not guaranteed to run to completion, but this function is
186     /// guaranteed to return if it fails. Care should be taken to ensure that
187     /// stack references made by `f` are handled appropriately.
188     ///
189     /// It is invalid to call this function with a task that has been previously
190     /// destroyed via a failed call to `run`.
191     ///
192     /// # Example
193     ///
194     /// ```no_run
195     /// extern crate native;
196     /// use std::uint;
197     /// # fn main() {
198     ///
199     /// // Create a new native task
200     /// let task = native::task::new((0, uint::MAX), 0);
201     ///
202     /// // Run some code once and then destroy this task
203     /// task.run(|| {
204     ///     println!("Hello with a native runtime!");
205     /// }).destroy();
206     /// # }
207     /// ```
208     pub fn run(mut self: Box<Task>, f: ||) -> Box<Task> {
209         assert!(!self.is_destroyed(), "cannot re-use a destroyed task");
210
211         // First, make sure that no one else is in TLS. This does not allow
212         // recursive invocations of run(). If there's no one else, then
213         // relinquish ownership of ourselves back into TLS.
214         if Local::exists(None::<Task>) {
215             fail!("cannot run a task recursively inside another");
216         }
217         self.state = Armed;
218         Local::put(self);
219
220         // There are two primary reasons that general try/catch is unsafe. The
221         // first is that we do not support nested try/catch. The above check for
222         // an existing task in TLS is sufficient for this invariant to be
223         // upheld. The second is that unwinding while unwinding is not defined.
224         // We take care of that by having an 'unwinding' flag in the task
225         // itself. For these reasons, this unsafety should be ok.
226         let result = unsafe { unwind::try(f) };
227
228         // After running the closure given return the task back out if it ran
229         // successfully, or clean up the task if it failed.
230         let task: Box<Task> = Local::take();
231         match result {
232             Ok(()) => task,
233             Err(cause) => { task.cleanup(Err(cause)) }
234         }
235     }
236
237     /// Destroy all associated resources of this task.
238     ///
239     /// This function will perform any necessary clean up to prepare the task
240     /// for destruction. It is required that this is called before a `Task`
241     /// falls out of scope.
242     ///
243     /// The returned task cannot be used for running any more code, but it may
244     /// be used to extract the runtime as necessary.
245     pub fn destroy(self: Box<Task>) -> Box<Task> {
246         if self.is_destroyed() {
247             self
248         } else {
249             self.cleanup(Ok(()))
250         }
251     }
252
253     /// Cleans up a task, processing the result of the task as appropriate.
254     ///
255     /// This function consumes ownership of the task, deallocating it once it's
256     /// done being processed. It is assumed that TLD and the local heap have
257     /// already been destroyed and/or annihilated.
258     fn cleanup(self: Box<Task>, result: Result) -> Box<Task> {
259         // The first thing to do when cleaning up is to deallocate our local
260         // resources, such as TLD.
261         //
262         // FIXME: there are a number of problems with this code
263         //
264         // 1. If any TLD object fails destruction, then all of TLD will leak.
265         //    This appears to be a consequence of #14875.
266         //
267         // 2. Setting a TLD key while destroying TLD will abort the runtime #14807.
268         //
269         // 3. The order of destruction of TLD matters, but either way is
270         //    susceptible to leaks (see 2) #8302.
271         //
272         // That being said, there are a few upshots to this code
273         //
274         // 1. If TLD destruction fails, heap destruction will be attempted.
275         //    There is a test for this at fail-during-tld-destroy.rs.
276         //
277         // 2. One failure in destruction is tolerable, so long as the task
278         //    didn't originally fail while it was running.
279         //
280         // And with all that in mind, we attempt to clean things up!
281         let mut task = self.run(|| {
282             let mut task = Local::borrow(None::<Task>);
283             let tld = {
284                 let &LocalStorage(ref mut optmap) = &mut task.storage;
285                 optmap.take()
286             };
287             drop(task);
288
289             // First, destroy task-local storage. This may run user dtors.
290             drop(tld);
291         });
292
293         // If the above `run` block failed, then it must be the case that the
294         // task had previously succeeded. This also means that the code below
295         // was recursively run via the `run` method invoking this method. In
296         // this case, we just make sure the world is as we thought, and return.
297         if task.is_destroyed() {
298             rtassert!(result.is_ok())
299             return task
300         }
301
302         // After taking care of the data above, we need to transmit the result
303         // of this task.
304         let what_to_do = task.death.on_exit.take();
305         Local::put(task);
306
307         // FIXME: this is running in a seriously constrained context. If this
308         //        allocates TLD then it will likely abort the runtime. Similarly,
309         //        if this fails, this will also likely abort the runtime.
310         //
311         //        This closure is currently limited to a channel send via the
312         //        standard library's task interface, but this needs
313         //        reconsideration to whether it's a reasonable thing to let a
314         //        task to do or not.
315         match what_to_do {
316             Some(f) => { f(result) }
317             None => { drop(result) }
318         }
319
320         // Now that we're done, we remove the task from TLS and flag it for
321         // destruction.
322         let mut task: Box<Task> = Local::take();
323         task.state = Destroyed;
324         return task;
325     }
326
327     /// Queries whether this can be destroyed or not.
328     pub fn is_destroyed(&self) -> bool { self.state == Destroyed }
329
330     /// Inserts a runtime object into this task, transferring ownership to the
331     /// task. It is illegal to replace a previous runtime object in this task
332     /// with this argument.
333     pub fn put_runtime(&mut self, ops: Box<Runtime + Send + 'static>) {
334         assert!(self.imp.is_none());
335         self.imp = Some(ops);
336     }
337
338     /// Removes the runtime from this task, transferring ownership to the
339     /// caller.
340     pub fn take_runtime(&mut self) -> Box<Runtime + Send + 'static> {
341         assert!(self.imp.is_some());
342         self.imp.take().unwrap()
343     }
344
345     /// Attempts to extract the runtime as a specific type. If the runtime does
346     /// not have the provided type, then the runtime is not removed. If the
347     /// runtime does have the specified type, then it is removed and returned
348     /// (transfer of ownership).
349     ///
350     /// It is recommended to only use this method when *absolutely necessary*.
351     /// This function may not be available in the future.
352     pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<Box<T>> {
353         // This is a terrible, terrible function. The general idea here is to
354         // take the runtime, cast it to Box<Any>, check if it has the right
355         // type, and then re-cast it back if necessary. The method of doing
356         // this is pretty sketchy and involves shuffling vtables of trait
357         // objects around, but it gets the job done.
358         //
359         // FIXME: This function is a serious code smell and should be avoided at
360         //      all costs. I have yet to think of a method to avoid this
361         //      function, and I would be saddened if more usage of the function
362         //      crops up.
363         unsafe {
364             let imp = self.imp.take().unwrap();
365             let vtable = mem::transmute::<_, &raw::TraitObject>(&imp).vtable;
366             match imp.wrap().downcast::<T>() {
367                 Ok(t) => Some(t),
368                 Err(t) => {
369                     let data = mem::transmute::<_, raw::TraitObject>(t).data;
370                     let obj: Box<Runtime + Send + 'static> =
371                         mem::transmute(raw::TraitObject {
372                             vtable: vtable,
373                             data: data,
374                         });
375                     self.put_runtime(obj);
376                     None
377                 }
378             }
379         }
380     }
381
382     /// Spawns a sibling to this task. The newly spawned task is configured with
383     /// the `opts` structure and will run `f` as the body of its code.
384     pub fn spawn_sibling(mut self: Box<Task>,
385                          opts: TaskOpts,
386                          f: proc(): Send) {
387         let ops = self.imp.take().unwrap();
388         ops.spawn_sibling(self, opts, f)
389     }
390
391     /// Deschedules the current task, invoking `f` `amt` times. It is not
392     /// recommended to use this function directly, but rather communication
393     /// primitives in `std::comm` should be used.
394     pub fn deschedule(mut self: Box<Task>,
395                       amt: uint,
396                       f: |BlockedTask| -> ::core::result::Result<(), BlockedTask>) {
397         let ops = self.imp.take().unwrap();
398         ops.deschedule(amt, self, f)
399     }
400
401     /// Wakes up a previously blocked task, optionally specifying whether the
402     /// current task can accept a change in scheduling. This function can only
403     /// be called on tasks that were previously blocked in `deschedule`.
404     pub fn reawaken(mut self: Box<Task>) {
405         let ops = self.imp.take().unwrap();
406         ops.reawaken(self);
407     }
408
409     /// Yields control of this task to another task. This function will
410     /// eventually return, but possibly not immediately. This is used as an
411     /// opportunity to allow other tasks a chance to run.
412     pub fn yield_now(mut self: Box<Task>) {
413         let ops = self.imp.take().unwrap();
414         ops.yield_now(self);
415     }
416
417     /// Similar to `yield_now`, except that this function may immediately return
418     /// without yielding (depending on what the runtime decides to do).
419     pub fn maybe_yield(mut self: Box<Task>) {
420         let ops = self.imp.take().unwrap();
421         ops.maybe_yield(self);
422     }
423
424     /// Acquires a handle to the I/O factory that this task contains, normally
425     /// stored in the task's runtime. This factory may not always be available,
426     /// which is why the return type is `Option`
427     pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
428         self.imp.as_mut().unwrap().local_io()
429     }
430
431     /// Returns the stack bounds for this task in (lo, hi) format. The stack
432     /// bounds may not be known for all tasks, so the return value may be
433     /// `None`.
434     pub fn stack_bounds(&self) -> (uint, uint) {
435         self.imp.as_ref().unwrap().stack_bounds()
436     }
437
438     /// Returns whether it is legal for this task to block the OS thread that it
439     /// is running on.
440     pub fn can_block(&self) -> bool {
441         self.imp.as_ref().unwrap().can_block()
442     }
443
444     /// Consume this task, flagging it as a candidate for destruction.
445     ///
446     /// This function is required to be invoked to destroy a task. A task
447     /// destroyed through a normal drop will abort.
448     pub fn drop(mut self) {
449         self.state = Destroyed;
450     }
451 }
452
453 impl Drop for Task {
454     fn drop(&mut self) {
455         rtdebug!("called drop for a task: {}", self as *mut Task as uint);
456         rtassert!(self.state != Armed);
457     }
458 }
459
460 impl TaskOpts {
461     pub fn new() -> TaskOpts {
462         TaskOpts { on_exit: None, name: None, stack_size: None }
463     }
464 }
465
466 impl Iterator<BlockedTask> for BlockedTasks {
467     fn next(&mut self) -> Option<BlockedTask> {
468         Some(Shared(self.inner.clone()))
469     }
470 }
471
472 impl BlockedTask {
473     /// Returns Some if the task was successfully woken; None if already killed.
474     pub fn wake(self) -> Option<Box<Task>> {
475         match self {
476             Owned(task) => Some(task),
477             Shared(arc) => {
478                 match arc.swap(0, SeqCst) {
479                     0 => None,
480                     n => Some(unsafe { mem::transmute(n) }),
481                 }
482             }
483         }
484     }
485
486     /// Reawakens this task if ownership is acquired. If finer-grained control
487     /// is desired, use `wake` instead.
488     pub fn reawaken(self) {
489         self.wake().map(|t| t.reawaken());
490     }
491
492     // This assertion has two flavours because the wake involves an atomic op.
493     // In the faster version, destructors will fail dramatically instead.
494     #[cfg(not(test))] pub fn trash(self) { }
495     #[cfg(test)]      pub fn trash(self) { assert!(self.wake().is_none()); }
496
497     /// Create a blocked task, unless the task was already killed.
498     pub fn block(task: Box<Task>) -> BlockedTask {
499         Owned(task)
500     }
501
502     /// Converts one blocked task handle to a list of many handles to the same.
503     pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTasks> {
504         let arc = match self {
505             Owned(task) => {
506                 let flag = unsafe { AtomicUint::new(mem::transmute(task)) };
507                 Arc::new(flag)
508             }
509             Shared(arc) => arc.clone(),
510         };
511         BlockedTasks{ inner: arc }.take(num_handles)
512     }
513
514     /// Convert to an unsafe uint value. Useful for storing in a pipe's state
515     /// flag.
516     #[inline]
517     pub unsafe fn cast_to_uint(self) -> uint {
518         match self {
519             Owned(task) => {
520                 let blocked_task_ptr: uint = mem::transmute(task);
521                 rtassert!(blocked_task_ptr & 0x1 == 0);
522                 blocked_task_ptr
523             }
524             Shared(arc) => {
525                 let blocked_task_ptr: uint = mem::transmute(box arc);
526                 rtassert!(blocked_task_ptr & 0x1 == 0);
527                 blocked_task_ptr | 0x1
528             }
529         }
530     }
531
532     /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
533     /// flag.
534     #[inline]
535     pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
536         if blocked_task_ptr & 0x1 == 0 {
537             Owned(mem::transmute(blocked_task_ptr))
538         } else {
539             let ptr: Box<Arc<AtomicUint>> =
540                 mem::transmute(blocked_task_ptr & !1);
541             Shared(*ptr)
542         }
543     }
544 }
545
546 impl Death {
547     pub fn new() -> Death {
548         Death { on_exit: None, marker: marker::NoCopy }
549     }
550 }
551
552 #[cfg(test)]
553 mod test {
554     use super::*;
555     use std::prelude::*;
556     use std::task;
557
558     #[test]
559     fn tls() {
560         local_data_key!(key: String)
561         key.replace(Some("data".to_string()));
562         assert_eq!(key.get().unwrap().as_slice(), "data");
563         local_data_key!(key2: String)
564         key2.replace(Some("data".to_string()));
565         assert_eq!(key2.get().unwrap().as_slice(), "data");
566     }
567
568     #[test]
569     fn unwind() {
570         let result = task::try(proc()());
571         rtdebug!("trying first assert");
572         assert!(result.is_ok());
573         let result = task::try::<()>(proc() fail!());
574         rtdebug!("trying second assert");
575         assert!(result.is_err());
576     }
577
578     #[test]
579     fn rng() {
580         use std::rand::{StdRng, Rng};
581         let mut r = StdRng::new().ok().unwrap();
582         let _ = r.next_u32();
583     }
584
585     #[test]
586     fn comm_stream() {
587         let (tx, rx) = channel();
588         tx.send(10i);
589         assert!(rx.recv() == 10);
590     }
591
592     #[test]
593     fn comm_shared_chan() {
594         let (tx, rx) = channel();
595         tx.send(10i);
596         assert!(rx.recv() == 10);
597     }
598
599     #[test]
600     #[should_fail]
601     fn test_begin_unwind() {
602         use std::rt::unwind::begin_unwind;
603         begin_unwind("cause", &(file!(), line!()))
604     }
605
606     #[test]
607     fn drop_new_task_ok() {
608         drop(Task::new());
609     }
610
611     // Task blocking tests
612
613     #[test]
614     fn block_and_wake() {
615         let task = box Task::new();
616         let task = BlockedTask::block(task).wake().unwrap();
617         task.drop();
618     }
619 }