1 // Copyright 2013 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 /*! The Rust Runtime, including the task scheduler and I/O
13 The `rt` module provides the private runtime infrastructure necessary
14 to support core language features like the exchange and local heap,
15 the garbage collector, logging, local data and unwinding. It also
16 implements the default task scheduler and task model. Initialization
17 routines are provided for setting up runtime resources in common
18 configurations, including that used by `rustc` when generating
21 It is intended that the features provided by `rt` can be factored in a
22 way such that the core library can be built with different 'profiles'
23 for different use cases, e.g. excluding the task scheduler. A number
24 of runtime features though are critical to the functioning of the
25 language and an implementation must be provided regardless of the
26 execution environment.
28 Of foremost importance is the global exchange heap, in the module
29 `global_heap`. Very little practical Rust code can be written without
30 access to the global heap. Unlike most of `rt` the global heap is
31 truly a global resource and generally operates independently of the
34 All other runtime features are task-local, including the local heap,
35 the garbage collector, local storage, logging and the stack unwinder.
37 The relationship between `rt` and the rest of the core library is
38 not entirely clear yet and some modules will be moving into or
39 out of `rt` as development proceeds.
41 Several modules in `core` are clients of `rt`:
43 * `std::task` - The user-facing interface to the Rust task model.
44 * `std::task::local_data` - The interface to local data.
45 * `std::gc` - The garbage collector.
46 * `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`.
47 * `std::condition` - Uses local data.
48 * `std::cleanup` - Local heap destruction.
49 * `std::io` - In the future `std::io` will use an `rt` implementation.
58 #[deny(unused_imports)];
60 #[deny(unused_variable)];
61 #[deny(unused_unsafe)];
65 use container::Container;
66 use iterator::{Iterator, range};
67 use option::{Some, None};
70 use rt::sched::{Scheduler, Shutdown};
71 use rt::sleeper_list::SleeperList;
72 use rt::task::{Task, SchedTask, GreenTask, Sched};
73 use rt::thread::Thread;
74 use rt::work_queue::WorkQueue;
75 use rt::uv::uvio::UvEventLoop;
76 use unstable::atomics::{AtomicInt, SeqCst};
77 use unstable::sync::UnsafeAtomicRcBox;
78 use vec::{OwnedVector, MutableVector};
80 /// The global (exchange) heap.
83 /// Implementations of language-critical runtime features like @.
86 /// Facilities related to task failure, killing, and death.
89 /// The coroutine task scheduler, built on the `io` event loop.
95 /// The EventLoop and internal synchronous I/O interface.
98 /// libuv and default rtio implementation.
101 /// The Local trait for types that are accessible via thread-local
102 /// or task-local storage.
105 /// A parallel work-stealing deque.
108 /// A parallel queue.
111 /// A parallel data structure for tracking sleeping schedulers.
114 /// Stack segments and caching.
117 /// CPU context swapping.
120 /// Bindings to system threading libraries.
123 /// The runtime configuration, read from environment variables.
126 /// The local, managed heap
129 /// The Logger trait and implementations
132 /// Tools for testing the runtime
135 /// Reference counting
138 /// A simple single-threaded channel type for passing buffered data between
139 /// scheduler and task context
142 /// Simple reimplementation of std::comm
147 // FIXME #5248 shouldn't be pub
148 /// The runtime needs to be able to put a pointer into thread-local storage.
151 // FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
152 /// Bindings to pthread/windows thread-local storage.
153 pub mod thread_local_storage;
157 // FIXME #5248 shouldn't be pub
161 // Global command line argument storage
164 // Support for dynamic borrowck
167 /// Set up a default runtime configuration, given compiler-supplied arguments.
169 /// This is invoked by the `start` _language item_ (unstable::lang) to
170 /// run a Rust executable.
174 /// * `argc` & `argv` - The argument vector. On Unix this information is used
176 /// * `crate_map` - Runtime information about the executing crate, mostly for logging
180 /// The return value is used as the process return code. 0 on success, 101 on error.
181 pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
183 init(argc, argv, crate_map);
184 let exit_code = run(main);
190 /// Like `start` but creates an additional scheduler on the current thread,
191 /// which in most cases will be the 'main' thread, and pins the main task to it.
193 /// This is appropriate for running code that must execute on the main thread,
194 /// such as the platform event loop and GUI.
195 pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
196 init(argc, argv, crate_map);
197 let exit_code = run_on_main_thread(main);
203 /// One-time runtime initialization.
205 /// Initializes global state, including frobbing
206 /// the crate's logging flags, registering GC
207 /// metadata, and storing the process arguments.
208 pub fn init(argc: int, argv: **u8, crate_map: *u8) {
209 // XXX: Derefing these pointers is not safe.
210 // Need to propagate the unsafety to `start`.
212 args::init(argc, argv);
214 logging::init(crate_map);
215 rust_update_gc_metadata(crate_map);
219 fn rust_update_gc_metadata(crate_map: *u8);
223 /// One-time runtime cleanup.
228 /// Execute the main function in a scheduler.
230 /// Configures the runtime according to the environment, by default
231 /// using a task scheduler with the same number of threads as cores.
232 /// Returns a process exit code.
233 pub fn run(main: ~fn()) -> int {
237 pub fn run_on_main_thread(main: ~fn()) -> int {
241 fn run_(main: ~fn(), use_main_sched: bool) -> int {
242 static DEFAULT_ERROR_CODE: int = 101;
244 let nscheds = util::default_sched_threads();
246 let main = Cell::new(main);
248 // The shared list of sleeping schedulers.
249 let sleepers = SleeperList::new();
251 // Create a work queue for each scheduler, ntimes. Create an extra
252 // for the main thread if that flag is set. We won't steal from it.
253 let mut work_queues = ~[];
254 for _ in range(0u, nscheds) {
255 let work_queue: WorkQueue<~Task> = WorkQueue::new();
256 work_queues.push(work_queue);
260 let mut scheds = ~[];
261 // Handles to the schedulers. When the main task ends these will be
262 // sent the Shutdown message to terminate the schedulers.
263 let mut handles = ~[];
265 for i in range(0u, nscheds) {
266 rtdebug!("inserting a regular scheduler");
268 // Every scheduler is driven by an I/O event loop.
269 let loop_ = ~UvEventLoop::new();
270 let mut sched = ~Scheduler::new(loop_,
271 work_queues[i].clone(),
274 let handle = sched.make_handle();
277 handles.push(handle);
280 // If we need a main-thread task then create a main thread scheduler
281 // that will reject any task that isn't pinned to it
282 let main_sched = if use_main_sched {
284 // Create a friend handle.
285 let mut friend_sched = scheds.pop();
286 let friend_handle = friend_sched.make_handle();
287 scheds.push(friend_sched);
289 // This scheduler needs a queue that isn't part of the stealee
291 let work_queue = WorkQueue::new();
293 let main_loop = ~UvEventLoop::new();
294 let mut main_sched = ~Scheduler::new_special(main_loop,
299 Some(friend_handle));
300 let main_handle = main_sched.make_handle();
301 handles.push(main_handle);
307 // Create a shared cell for transmitting the process exit
308 // code from the main task to this function.
309 let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
310 let exit_code_clone = exit_code.clone();
312 // When the main task exits, after all the tasks in the main
313 // task tree, shut down the schedulers and set the exit code.
314 let handles = Cell::new(handles);
315 let on_exit: ~fn(bool) = |exit_success| {
317 let mut handles = handles.take();
318 for handle in handles.mut_iter() {
319 handle.send(Shutdown);
323 let exit_code = if exit_success {
326 // If we're exiting successfully, then return the global
327 // exit status, which can be set programmatically.
328 util::get_exit_status()
332 (*exit_code_clone.get()).store(exit_code, SeqCst);
336 let mut threads = ~[];
338 let on_exit = Cell::new(on_exit);
342 // In the case where we do not use a main_thread scheduler we
343 // run the main task in one of our threads.
345 let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take());
346 main_task.death.on_exit = Some(on_exit.take());
347 let main_task_cell = Cell::new(main_task);
349 let sched = scheds.pop();
350 let sched_cell = Cell::new(sched);
351 let thread = do Thread::start {
352 let sched = sched_cell.take();
353 sched.bootstrap(main_task_cell.take());
355 threads.push(thread);
358 // Run each remaining scheduler in a thread.
359 while !scheds.is_empty() {
360 rtdebug!("creating regular schedulers");
361 let sched = scheds.pop();
362 let sched_cell = Cell::new(sched);
363 let thread = do Thread::start {
364 let mut sched = sched_cell.take();
365 let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
366 rtdebug!("boostraping a non-primary scheduler");
368 sched.bootstrap(bootstrap_task);
370 threads.push(thread);
373 // If we do have a main thread scheduler, run it now.
377 rtdebug!("about to create the main scheduler task");
379 let mut main_sched = main_sched.unwrap();
381 let home = Sched(main_sched.make_handle());
382 let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
384 main_task.death.on_exit = Some(on_exit.take());
385 rtdebug!("bootstrapping main_task");
387 main_sched.bootstrap(main_task);
390 rtdebug!("waiting for threads");
392 // Wait for schedulers
393 for thread in threads.move_iter() {
397 // Return the exit code
399 (*exit_code.get()).load(SeqCst)
403 pub fn in_sched_context() -> bool {
405 match Local::try_unsafe_borrow::<Task>() {
407 match (*task).task_type {
417 pub fn in_green_task_context() -> bool {
419 match Local::try_unsafe_borrow::<Task>() {
421 match (*task).task_type {
422 GreenTask(_) => true,