]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/task.rs
Honor hidden doc attribute of derivable trait methods
[rust.git] / src / libstd / rt / 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'. Local heaps, GC, unwinding,
13 //! local storage, and logging. Even a 'freestanding' Rust would likely want
14 //! to implement this.
15
16 use any::AnyOwnExt;
17 use cast;
18 use cleanup;
19 use clone::Clone;
20 use comm::Sender;
21 use io::Writer;
22 use iter::{Iterator, Take};
23 use kinds::Send;
24 use local_data;
25 use ops::Drop;
26 use option::{Option, Some, None};
27 use prelude::drop;
28 use result::{Result, Ok, Err};
29 use rt::Runtime;
30 use rt::local::Local;
31 use rt::local_heap::LocalHeap;
32 use rt::rtio::LocalIo;
33 use rt::unwind::Unwinder;
34 use str::SendStr;
35 use sync::arc::UnsafeArc;
36 use sync::atomics::{AtomicUint, SeqCst};
37 use task::{TaskResult, TaskOpts};
38 use unstable::finally::Finally;
39
40 /// The Task struct represents all state associated with a rust
41 /// task. There are at this point two primary "subtypes" of task,
42 /// however instead of using a subtype we just have a "task_type" field
43 /// in the struct. This contains a pointer to another struct that holds
44 /// the type-specific state.
45 pub struct Task {
46     pub heap: LocalHeap,
47     pub gc: GarbageCollector,
48     pub storage: LocalStorage,
49     pub unwinder: Unwinder,
50     pub death: Death,
51     pub destroyed: bool,
52     pub name: Option<SendStr>,
53
54     pub stdout: Option<~Writer:Send>,
55     pub stderr: Option<~Writer:Send>,
56
57     imp: Option<~Runtime:Send>,
58 }
59
60 pub struct GarbageCollector;
61 pub struct LocalStorage(pub Option<local_data::Map>);
62
63 /// A handle to a blocked task. Usually this means having the ~Task pointer by
64 /// ownership, but if the task is killable, a killer can steal it at any time.
65 pub enum BlockedTask {
66     Owned(~Task),
67     Shared(UnsafeArc<AtomicUint>),
68 }
69
70 pub enum DeathAction {
71     /// Action to be done with the exit code. If set, also makes the task wait
72     /// until all its watched children exit before collecting the status.
73     Execute(proc(TaskResult):Send),
74     /// A channel to send the result of the task on when the task exits
75     SendMessage(Sender<TaskResult>),
76 }
77
78 /// Per-task state related to task death, killing, failure, etc.
79 pub struct Death {
80     pub on_exit: Option<DeathAction>,
81 }
82
83 pub struct BlockedTasks {
84     inner: UnsafeArc<AtomicUint>,
85 }
86
87 impl Task {
88     pub fn new() -> Task {
89         Task {
90             heap: LocalHeap::new(),
91             gc: GarbageCollector,
92             storage: LocalStorage(None),
93             unwinder: Unwinder::new(),
94             death: Death::new(),
95             destroyed: false,
96             name: None,
97             stdout: None,
98             stderr: None,
99             imp: None,
100         }
101     }
102
103     /// Executes the given closure as if it's running inside this task. The task
104     /// is consumed upon entry, and the destroyed task is returned from this
105     /// function in order for the caller to free. This function is guaranteed to
106     /// not unwind because the closure specified is run inside of a `rust_try`
107     /// block. (this is the only try/catch block in the world).
108     ///
109     /// This function is *not* meant to be abused as a "try/catch" block. This
110     /// is meant to be used at the absolute boundaries of a task's lifetime, and
111     /// only for that purpose.
112     pub fn run(~self, f: ||) -> ~Task {
113         // Need to put ourselves into TLS, but also need access to the unwinder.
114         // Unsafely get a handle to the task so we can continue to use it after
115         // putting it in tls (so we can invoke the unwinder).
116         let handle: *mut Task = unsafe {
117             *cast::transmute::<&~Task, &*mut Task>(&self)
118         };
119         Local::put(self);
120
121         // The only try/catch block in the world. Attempt to run the task's
122         // client-specified code and catch any failures.
123         let try_block = || {
124
125             // Run the task main function, then do some cleanup.
126             f.finally(|| {
127                 #[allow(unused_must_use)]
128                 fn close_outputs() {
129                     let mut task = Local::borrow(None::<Task>);
130                     let stderr = task.stderr.take();
131                     let stdout = task.stdout.take();
132                     drop(task);
133                     match stdout { Some(mut w) => { w.flush(); }, None => {} }
134                     match stderr { Some(mut w) => { w.flush(); }, None => {} }
135                 }
136
137                 // First, flush/destroy the user stdout/logger because these
138                 // destructors can run arbitrary code.
139                 close_outputs();
140
141                 // First, destroy task-local storage. This may run user dtors.
142                 //
143                 // FIXME #8302: Dear diary. I'm so tired and confused.
144                 // There's some interaction in rustc between the box
145                 // annihilator and the TLS dtor by which TLS is
146                 // accessed from annihilated box dtors *after* TLS is
147                 // destroyed. Somehow setting TLS back to null, as the
148                 // old runtime did, makes this work, but I don't currently
149                 // understand how. I would expect that, if the annihilator
150                 // reinvokes TLS while TLS is uninitialized, that
151                 // TLS would be reinitialized but never destroyed,
152                 // but somehow this works. I have no idea what's going
153                 // on but this seems to make things magically work. FML.
154                 //
155                 // (added after initial comment) A possible interaction here is
156                 // that the destructors for the objects in TLS themselves invoke
157                 // TLS, or possibly some destructors for those objects being
158                 // annihilated invoke TLS. Sadly these two operations seemed to
159                 // be intertwined, and miraculously work for now...
160                 let mut task = Local::borrow(None::<Task>);
161                 let storage_map = {
162                     let &LocalStorage(ref mut optmap) = &mut task.storage;
163                     optmap.take()
164                 };
165                 drop(task);
166                 drop(storage_map);
167
168                 // Destroy remaining boxes. Also may run user dtors.
169                 unsafe { cleanup::annihilate(); }
170
171                 // Finally, just in case user dtors printed/logged during TLS
172                 // cleanup and annihilation, re-destroy stdout and the logger.
173                 // Note that these will have been initialized with a
174                 // runtime-provided type which we have control over what the
175                 // destructor does.
176                 close_outputs();
177             })
178         };
179
180         unsafe { (*handle).unwinder.try(try_block); }
181
182         // Here we must unsafely borrow the task in order to not remove it from
183         // TLS. When collecting failure, we may attempt to send on a channel (or
184         // just run aribitrary code), so we must be sure to still have a local
185         // task in TLS.
186         unsafe {
187             let me: *mut Task = Local::unsafe_borrow();
188             (*me).death.collect_failure((*me).unwinder.result());
189         }
190         let mut me: ~Task = Local::take();
191         me.destroyed = true;
192         return me;
193     }
194
195     /// Inserts a runtime object into this task, transferring ownership to the
196     /// task. It is illegal to replace a previous runtime object in this task
197     /// with this argument.
198     pub fn put_runtime(&mut self, ops: ~Runtime:Send) {
199         assert!(self.imp.is_none());
200         self.imp = Some(ops);
201     }
202
203     /// Attempts to extract the runtime as a specific type. If the runtime does
204     /// not have the provided type, then the runtime is not removed. If the
205     /// runtime does have the specified type, then it is removed and returned
206     /// (transfer of ownership).
207     ///
208     /// It is recommended to only use this method when *absolutely necessary*.
209     /// This function may not be available in the future.
210     pub fn maybe_take_runtime<T: 'static>(&mut self) -> Option<~T> {
211         // This is a terrible, terrible function. The general idea here is to
212         // take the runtime, cast it to ~Any, check if it has the right type,
213         // and then re-cast it back if necessary. The method of doing this is
214         // pretty sketchy and involves shuffling vtables of trait objects
215         // around, but it gets the job done.
216         //
217         // FIXME: This function is a serious code smell and should be avoided at
218         //      all costs. I have yet to think of a method to avoid this
219         //      function, and I would be saddened if more usage of the function
220         //      crops up.
221         unsafe {
222             let imp = self.imp.take_unwrap();
223             let &(vtable, _): &(uint, uint) = cast::transmute(&imp);
224             match imp.wrap().move::<T>() {
225                 Ok(t) => Some(t),
226                 Err(t) => {
227                     let (_, obj): (uint, uint) = cast::transmute(t);
228                     let obj: ~Runtime:Send = cast::transmute((vtable, obj));
229                     self.put_runtime(obj);
230                     None
231                 }
232             }
233         }
234     }
235
236     /// Spawns a sibling to this task. The newly spawned task is configured with
237     /// the `opts` structure and will run `f` as the body of its code.
238     pub fn spawn_sibling(mut ~self, opts: TaskOpts, f: proc():Send) {
239         let ops = self.imp.take_unwrap();
240         ops.spawn_sibling(self, opts, f)
241     }
242
243     /// Deschedules the current task, invoking `f` `amt` times. It is not
244     /// recommended to use this function directly, but rather communication
245     /// primitives in `std::comm` should be used.
246     pub fn deschedule(mut ~self, amt: uint,
247                       f: |BlockedTask| -> Result<(), BlockedTask>) {
248         let ops = self.imp.take_unwrap();
249         ops.deschedule(amt, self, f)
250     }
251
252     /// Wakes up a previously blocked task, optionally specifying whether the
253     /// current task can accept a change in scheduling. This function can only
254     /// be called on tasks that were previously blocked in `deschedule`.
255     pub fn reawaken(mut ~self) {
256         let ops = self.imp.take_unwrap();
257         ops.reawaken(self);
258     }
259
260     /// Yields control of this task to another task. This function will
261     /// eventually return, but possibly not immediately. This is used as an
262     /// opportunity to allow other tasks a chance to run.
263     pub fn yield_now(mut ~self) {
264         let ops = self.imp.take_unwrap();
265         ops.yield_now(self);
266     }
267
268     /// Similar to `yield_now`, except that this function may immediately return
269     /// without yielding (depending on what the runtime decides to do).
270     pub fn maybe_yield(mut ~self) {
271         let ops = self.imp.take_unwrap();
272         ops.maybe_yield(self);
273     }
274
275     /// Acquires a handle to the I/O factory that this task contains, normally
276     /// stored in the task's runtime. This factory may not always be available,
277     /// which is why the return type is `Option`
278     pub fn local_io<'a>(&'a mut self) -> Option<LocalIo<'a>> {
279         self.imp.get_mut_ref().local_io()
280     }
281
282     /// Returns the stack bounds for this task in (lo, hi) format. The stack
283     /// bounds may not be known for all tasks, so the return value may be
284     /// `None`.
285     pub fn stack_bounds(&self) -> (uint, uint) {
286         self.imp.get_ref().stack_bounds()
287     }
288
289     /// Returns whether it is legal for this task to block the OS thread that it
290     /// is running on.
291     pub fn can_block(&self) -> bool {
292         self.imp.get_ref().can_block()
293     }
294 }
295
296 impl Drop for Task {
297     fn drop(&mut self) {
298         rtdebug!("called drop for a task: {}", self as *mut Task as uint);
299         rtassert!(self.destroyed);
300     }
301 }
302
303 impl Iterator<BlockedTask> for BlockedTasks {
304     fn next(&mut self) -> Option<BlockedTask> {
305         Some(Shared(self.inner.clone()))
306     }
307 }
308
309 impl BlockedTask {
310     /// Returns Some if the task was successfully woken; None if already killed.
311     pub fn wake(self) -> Option<~Task> {
312         match self {
313             Owned(task) => Some(task),
314             Shared(arc) => unsafe {
315                 match (*arc.get()).swap(0, SeqCst) {
316                     0 => None,
317                     n => Some(cast::transmute(n)),
318                 }
319             }
320         }
321     }
322
323     // This assertion has two flavours because the wake involves an atomic op.
324     // In the faster version, destructors will fail dramatically instead.
325     #[cfg(not(test))] pub fn trash(self) { }
326     #[cfg(test)]      pub fn trash(self) { assert!(self.wake().is_none()); }
327
328     /// Create a blocked task, unless the task was already killed.
329     pub fn block(task: ~Task) -> BlockedTask {
330         Owned(task)
331     }
332
333     /// Converts one blocked task handle to a list of many handles to the same.
334     pub fn make_selectable(self, num_handles: uint) -> Take<BlockedTasks> {
335         let arc = match self {
336             Owned(task) => {
337                 let flag = unsafe { AtomicUint::new(cast::transmute(task)) };
338                 UnsafeArc::new(flag)
339             }
340             Shared(arc) => arc.clone(),
341         };
342         BlockedTasks{ inner: arc }.take(num_handles)
343     }
344
345     /// Convert to an unsafe uint value. Useful for storing in a pipe's state
346     /// flag.
347     #[inline]
348     pub unsafe fn cast_to_uint(self) -> uint {
349         match self {
350             Owned(task) => {
351                 let blocked_task_ptr: uint = cast::transmute(task);
352                 rtassert!(blocked_task_ptr & 0x1 == 0);
353                 blocked_task_ptr
354             }
355             Shared(arc) => {
356                 let blocked_task_ptr: uint = cast::transmute(~arc);
357                 rtassert!(blocked_task_ptr & 0x1 == 0);
358                 blocked_task_ptr | 0x1
359             }
360         }
361     }
362
363     /// Convert from an unsafe uint value. Useful for retrieving a pipe's state
364     /// flag.
365     #[inline]
366     pub unsafe fn cast_from_uint(blocked_task_ptr: uint) -> BlockedTask {
367         if blocked_task_ptr & 0x1 == 0 {
368             Owned(cast::transmute(blocked_task_ptr))
369         } else {
370             let ptr: ~UnsafeArc<AtomicUint> =
371                 cast::transmute(blocked_task_ptr & !1);
372             Shared(*ptr)
373         }
374     }
375 }
376
377 impl Death {
378     pub fn new() -> Death {
379         Death { on_exit: None, }
380     }
381
382     /// Collect failure exit codes from children and propagate them to a parent.
383     pub fn collect_failure(&mut self, result: TaskResult) {
384         match self.on_exit.take() {
385             Some(Execute(f)) => f(result),
386             Some(SendMessage(ch)) => { let _ = ch.send_opt(result); }
387             None => {}
388         }
389     }
390 }
391
392 impl Drop for Death {
393     fn drop(&mut self) {
394         // make this type noncopyable
395     }
396 }
397
398 #[cfg(test)]
399 mod test {
400     use super::*;
401     use prelude::*;
402     use task;
403
404     #[test]
405     fn local_heap() {
406         let a = @5;
407         let b = a;
408         assert!(*a == 5);
409         assert!(*b == 5);
410     }
411
412     #[test]
413     fn tls() {
414         use local_data;
415         local_data_key!(key: @~str)
416         local_data::set(key, @"data".to_owned());
417         assert!(*local_data::get(key, |k| k.map(|k| *k)).unwrap() == "data".to_owned());
418         local_data_key!(key2: @~str)
419         local_data::set(key2, @"data".to_owned());
420         assert!(*local_data::get(key2, |k| k.map(|k| *k)).unwrap() == "data".to_owned());
421     }
422
423     #[test]
424     fn unwind() {
425         let result = task::try(proc()());
426         rtdebug!("trying first assert");
427         assert!(result.is_ok());
428         let result = task::try::<()>(proc() fail!());
429         rtdebug!("trying second assert");
430         assert!(result.is_err());
431     }
432
433     #[test]
434     fn rng() {
435         use rand::{StdRng, Rng};
436         let mut r = StdRng::new().unwrap();
437         let _ = r.next_u32();
438     }
439
440     #[test]
441     fn logging() {
442         info!("here i am. logging in a newsched task");
443     }
444
445     #[test]
446     fn comm_stream() {
447         let (tx, rx) = channel();
448         tx.send(10);
449         assert!(rx.recv() == 10);
450     }
451
452     #[test]
453     fn comm_shared_chan() {
454         let (tx, rx) = channel();
455         tx.send(10);
456         assert!(rx.recv() == 10);
457     }
458
459     #[test]
460     fn heap_cycles() {
461         use cell::RefCell;
462         use option::{Option, Some, None};
463
464         struct List {
465             next: Option<@RefCell<List>>,
466         }
467
468         let a = @RefCell::new(List { next: None });
469         let b = @RefCell::new(List { next: Some(a) });
470
471         {
472             let mut a = a.borrow_mut();
473             a.next = Some(b);
474         }
475     }
476
477     #[test]
478     #[should_fail]
479     fn test_begin_unwind() {
480         use rt::unwind::begin_unwind;
481         begin_unwind("cause", file!(), line!())
482     }
483
484     // Task blocking tests
485
486     #[test]
487     fn block_and_wake() {
488         let task = ~Task::new();
489         let mut task = BlockedTask::block(task).wake().unwrap();
490         task.destroyed = true;
491     }
492 }