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.
57 // XXX: this should not be here.
58 #[allow(missing_doc)];
62 use container::Container;
64 use option::{Option, None, Some};
67 use rt::sched::{Scheduler, Shutdown};
68 use rt::sleeper_list::SleeperList;
69 use rt::task::{Task, SchedTask, GreenTask, Sched};
70 use rt::thread::Thread;
71 use rt::work_queue::WorkQueue;
72 use rt::uv::uvio::UvEventLoop;
73 use unstable::atomics::{AtomicInt, SeqCst};
74 use unstable::sync::UnsafeArc;
76 use vec::{OwnedVector, MutableVector, ImmutableVector};
78 /// The global (exchange) heap.
81 /// Implementations of language-critical runtime features like @.
84 /// Facilities related to task failure, killing, and death.
87 /// The coroutine task scheduler, built on the `io` event loop.
93 /// The EventLoop and internal synchronous I/O interface.
96 /// libuv and default rtio implementation.
99 /// The Local trait for types that are accessible via thread-local
100 /// or task-local storage.
103 /// A parallel work-stealing deque.
106 /// A parallel queue.
109 /// A parallel data structure for tracking sleeping schedulers.
112 /// Stack segments and caching.
115 /// CPU context swapping.
118 /// Bindings to system threading libraries.
121 /// The runtime configuration, read from environment variables.
124 /// The local, managed heap
127 /// The Logger trait and implementations
133 /// Tools for testing the runtime
136 /// Reference counting
139 /// A simple single-threaded channel type for passing buffered data between
140 /// scheduler and task context
143 /// Simple reimplementation of std::comm
148 // FIXME #5248 shouldn't be pub
149 /// The runtime needs to be able to put a pointer into thread-local storage.
152 // FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
153 /// Bindings to pthread/windows thread-local storage.
154 pub mod thread_local_storage;
156 // FIXME #5248 shouldn't be pub
160 // Global command line argument storage
163 // Support for dynamic borrowck
166 /// Set up a default runtime configuration, given compiler-supplied arguments.
168 /// This is invoked by the `start` _language item_ (unstable::lang) to
169 /// run a Rust executable.
173 /// * `argc` & `argv` - The argument vector. On Unix this information is used
178 /// The return value is used as the process return code. 0 on success, 101 on error.
180 pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
182 init(argc, argv, crate_map);
183 let exit_code = run(main);
189 pub fn start(argc: int, argv: **u8, main: ~fn()) -> int {
192 let exit_code = run(main);
198 /// Like `start` but creates an additional scheduler on the current thread,
199 /// which in most cases will be the 'main' thread, and pins the main task to it.
201 /// This is appropriate for running code that must execute on the main thread,
202 /// such as the platform event loop and GUI.
204 pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
205 init(argc, argv, crate_map);
206 let exit_code = run_on_main_thread(main);
212 pub fn start_on_main_thread(argc: int, argv: **u8, main: ~fn()) -> int {
214 let exit_code = run_on_main_thread(main);
220 /// One-time runtime initialization.
222 /// Initializes global state, including frobbing
223 /// the crate's logging flags, registering GC
224 /// metadata, and storing the process arguments.
226 pub fn init(argc: int, argv: **u8, crate_map: *u8) {
227 // XXX: Derefing these pointers is not safe.
228 // Need to propagate the unsafety to `start`.
230 args::init(argc, argv);
232 logging::init(crate_map);
236 pub fn init(argc: int, argv: **u8) {
237 // XXX: Derefing these pointers is not safe.
238 // Need to propagate the unsafety to `start`.
240 args::init(argc, argv);
246 /// One-time runtime cleanup.
251 /// Execute the main function in a scheduler.
253 /// Configures the runtime according to the environment, by default
254 /// using a task scheduler with the same number of threads as cores.
255 /// Returns a process exit code.
256 pub fn run(main: ~fn()) -> int {
260 pub fn run_on_main_thread(main: ~fn()) -> int {
264 fn run_(main: ~fn(), use_main_sched: bool) -> int {
265 static DEFAULT_ERROR_CODE: int = 101;
267 let nscheds = util::default_sched_threads();
269 let main = Cell::new(main);
271 // The shared list of sleeping schedulers.
272 let sleepers = SleeperList::new();
274 // Create a work queue for each scheduler, ntimes. Create an extra
275 // for the main thread if that flag is set. We won't steal from it.
276 let work_queues: ~[WorkQueue<~Task>] = vec::from_fn(nscheds, |_| WorkQueue::new());
279 let mut scheds = ~[];
280 // Handles to the schedulers. When the main task ends these will be
281 // sent the Shutdown message to terminate the schedulers.
282 let mut handles = ~[];
284 for work_queue in work_queues.iter() {
285 rtdebug!("inserting a regular scheduler");
287 // Every scheduler is driven by an I/O event loop.
288 let loop_ = ~UvEventLoop::new();
289 let mut sched = ~Scheduler::new(loop_,
293 let handle = sched.make_handle();
296 handles.push(handle);
299 // If we need a main-thread task then create a main thread scheduler
300 // that will reject any task that isn't pinned to it
301 let main_sched = if use_main_sched {
303 // Create a friend handle.
304 let mut friend_sched = scheds.pop();
305 let friend_handle = friend_sched.make_handle();
306 scheds.push(friend_sched);
308 // This scheduler needs a queue that isn't part of the stealee
310 let work_queue = WorkQueue::new();
312 let main_loop = ~UvEventLoop::new();
313 let mut main_sched = ~Scheduler::new_special(main_loop,
318 Some(friend_handle));
319 let main_handle = main_sched.make_handle();
320 handles.push(main_handle);
326 // Create a shared cell for transmitting the process exit
327 // code from the main task to this function.
328 let exit_code = UnsafeArc::new(AtomicInt::new(0));
329 let exit_code_clone = exit_code.clone();
331 // When the main task exits, after all the tasks in the main
332 // task tree, shut down the schedulers and set the exit code.
333 let handles = Cell::new(handles);
334 let on_exit: ~fn(bool) = |exit_success| {
335 assert_once_ever!("last task exiting");
337 let mut handles = handles.take();
338 for handle in handles.mut_iter() {
339 handle.send(Shutdown);
343 let exit_code = if exit_success {
346 // If we're exiting successfully, then return the global
347 // exit status, which can be set programmatically.
348 util::get_exit_status()
352 (*exit_code_clone.get()).store(exit_code, SeqCst);
356 let mut threads = ~[];
358 let on_exit = Cell::new(on_exit);
362 // In the case where we do not use a main_thread scheduler we
363 // run the main task in one of our threads.
365 let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take());
366 main_task.death.on_exit = Some(on_exit.take());
367 let main_task_cell = Cell::new(main_task);
369 let sched = scheds.pop();
370 let sched_cell = Cell::new(sched);
371 let thread = do Thread::start {
372 let sched = sched_cell.take();
373 sched.bootstrap(main_task_cell.take());
375 threads.push(thread);
378 // Run each remaining scheduler in a thread.
379 for sched in scheds.move_rev_iter() {
380 rtdebug!("creating regular schedulers");
381 let sched_cell = Cell::new(sched);
382 let thread = do Thread::start {
383 let mut sched = sched_cell.take();
384 let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
385 rtdebug!("boostraping a non-primary scheduler");
387 sched.bootstrap(bootstrap_task);
389 threads.push(thread);
392 // If we do have a main thread scheduler, run it now.
396 rtdebug!("about to create the main scheduler task");
398 let mut main_sched = main_sched.unwrap();
400 let home = Sched(main_sched.make_handle());
401 let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
403 main_task.death.on_exit = Some(on_exit.take());
404 rtdebug!("bootstrapping main_task");
406 main_sched.bootstrap(main_task);
409 rtdebug!("waiting for threads");
411 // Wait for schedulers
412 for thread in threads.move_iter() {
416 // Return the exit code
418 (*exit_code.get()).load(SeqCst)
422 pub fn in_sched_context() -> bool {
424 let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
427 match (*task).task_type {
437 pub fn in_green_task_context() -> bool {
439 let task: Option<*mut Task> = Local::try_unsafe_borrow();
442 match (*task).task_type {
443 GreenTask(_) => true,