]> git.lizzy.rs Git - rust.git/blob - src/libnative/lib.rs
Revamp TaskBuilder API
[rust.git] / src / libnative / lib.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 //! The native I/O and threading crate
12 //!
13 //! This crate contains an implementation of 1:1 scheduling for a "native"
14 //! runtime. In addition, all I/O provided by this crate is the thread blocking
15 //! version of I/O.
16 //!
17 //! # Starting with libnative
18 //!
19 //! ```rust
20 //! extern crate native;
21 //!
22 //! #[start]
23 //! fn start(argc: int, argv: **u8) -> int { native::start(argc, argv, main) }
24 //!
25 //! fn main() {
26 //!     // this code is running on the main OS thread
27 //! }
28 //! ```
29 //!
30 //! # Force spawning a native task
31 //!
32 //! ```rust
33 //! extern crate native;
34 //!
35 //! use std::task::TaskBuilder;
36 //! use native::NativeTaskBuilder;
37 //!
38 //! fn main() {
39 //!     // We're not sure whether this main function is run in 1:1 or M:N mode.
40 //!
41 //!     TaskBuilder::new().native().spawn(proc() {
42 //!         // this code is guaranteed to be run on a native thread
43 //!     });
44 //! }
45 //! ```
46
47 #![crate_id = "native#0.11.0-pre"]
48 #![license = "MIT/ASL2"]
49 #![crate_type = "rlib"]
50 #![crate_type = "dylib"]
51 #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
52        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
53        html_root_url = "http://doc.rust-lang.org/")]
54 #![deny(unused_result, unused_must_use)]
55 #![allow(non_camel_case_types)]
56 #![allow(deprecated)]
57 #![feature(default_type_params)]
58
59 // NB this crate explicitly does *not* allow glob imports, please seriously
60 //    consider whether they're needed before adding that feature here (the
61 //    answer is that you don't need them)
62 #![feature(macro_rules)]
63
64 extern crate alloc;
65 extern crate libc;
66 #[cfg(test)] extern crate debug;
67
68 use std::os;
69 use std::rt;
70 use std::str;
71
72 pub use task::NativeTaskBuilder;
73
74 pub mod io;
75 pub mod task;
76
77 #[cfg(windows)]
78 #[cfg(android)]
79 static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20;
80 #[cfg(unix, not(android))]
81 static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20);
82
83 #[lang = "start"]
84 #[cfg(not(test))]
85 pub fn lang_start(main: *u8, argc: int, argv: **u8) -> int {
86     use std::mem;
87     start(argc, argv, proc() {
88         let main: extern "Rust" fn() = unsafe { mem::transmute(main) };
89         main();
90     })
91 }
92
93 /// Executes the given procedure after initializing the runtime with the given
94 /// argc/argv.
95 ///
96 /// This procedure is guaranteed to run on the thread calling this function, but
97 /// the stack bounds for this rust task will *not* be set. Care must be taken
98 /// for this function to not overflow its stack.
99 ///
100 /// This function will only return once *all* native threads in the system have
101 /// exited.
102 pub fn start(argc: int, argv: **u8, main: proc()) -> int {
103     let something_around_the_top_of_the_stack = 1;
104     let addr = &something_around_the_top_of_the_stack as *int;
105     let my_stack_top = addr as uint;
106
107     // FIXME #11359 we just assume that this thread has a stack of a
108     // certain size, and estimate that there's at most 20KB of stack
109     // frames above our current position.
110     let my_stack_bottom = my_stack_top + 20000 - OS_DEFAULT_STACK_ESTIMATE;
111
112     // When using libgreen, one of the first things that we do is to turn off
113     // the SIGPIPE signal (set it to ignore). By default, some platforms will
114     // send a *signal* when a EPIPE error would otherwise be delivered. This
115     // runtime doesn't install a SIGPIPE handler, causing it to kill the
116     // program, which isn't exactly what we want!
117     //
118     // Hence, we set SIGPIPE to ignore when the program starts up in order to
119     // prevent this problem.
120     #[cfg(windows)] fn ignore_sigpipe() {}
121     #[cfg(unix)] fn ignore_sigpipe() {
122         use libc;
123         use libc::funcs::posix01::signal::signal;
124         unsafe {
125             assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != -1);
126         }
127     }
128     ignore_sigpipe();
129
130     rt::init(argc, argv);
131     let mut exit_code = None;
132     let mut main = Some(main);
133     let mut task = task::new((my_stack_bottom, my_stack_top));
134     task.name = Some(str::Slice("<main>"));
135     let t = task.run(|| {
136         unsafe {
137             rt::stack::record_stack_bounds(my_stack_bottom, my_stack_top);
138         }
139         exit_code = Some(run(main.take_unwrap()));
140     });
141     drop(t);
142     unsafe { rt::cleanup(); }
143     // If the exit code wasn't set, then the task block must have failed.
144     return exit_code.unwrap_or(rt::DEFAULT_ERROR_CODE);
145 }
146
147 /// Executes a procedure on the current thread in a Rust task context.
148 ///
149 /// This function has all of the same details as `start` except for a different
150 /// number of arguments.
151 pub fn run(main: proc()) -> int {
152     main();
153     os::get_exit_status()
154 }