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::UnwindResult;
70 use rt::task::{Task, SchedTask, GreenTask, Sched};
71 use send_str::SendStrStatic;
72 use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
73 use unstable::sync::UnsafeArc;
74 use vec::{OwnedVector, MutableVector, ImmutableVector};
77 use self::thread::Thread;
79 // the os module needs to reach into this helper, so allow general access
80 // through this reexport.
81 pub use self::util::set_exit_status;
83 // this is somewhat useful when a program wants to spawn a "reasonable" number
84 // of workers based on the constraints of the system that it's running on.
85 // Perhaps this shouldn't be a `pub use` though and there should be another
87 pub use self::util::default_sched_threads;
89 // Re-export of the functionality in the kill module
90 pub use self::kill::BlockedTask;
92 // XXX: these probably shouldn't be public...
94 pub mod shouldnt_be_public {
95 pub use super::select::SelectInner;
96 pub use super::select::{SelectInner, SelectPortInner};
97 pub use super::local_ptr::native::maybe_tls_key;
98 #[cfg(not(windows), not(target_os = "android"))]
99 pub use super::local_ptr::compiled::RT_TLS_PTR;
102 // Internal macros used by the runtime.
105 /// Basic implementation of an EventLoop, provides no I/O interfaces
108 /// The global (exchange) heap.
111 /// Implementations of language-critical runtime features like @.
114 /// Facilities related to task failure, killing, and death.
117 /// The coroutine task scheduler, built on the `io` event loop.
125 /// The EventLoop and internal synchronous I/O interface.
128 /// The Local trait for types that are accessible via thread-local
129 /// or task-local storage.
132 /// A parallel queue.
133 pub mod message_queue;
135 /// A mostly lock-free multi-producer, single consumer queue.
138 /// A lock-free multi-producer, multi-consumer bounded queue.
139 mod mpmc_bounded_queue;
141 /// A parallel work-stealing deque
144 /// A parallel data structure for tracking sleeping schedulers.
145 pub mod sleeper_list;
147 /// Stack segments and caching.
150 /// CPU context swapping.
153 /// Bindings to system threading libraries.
156 /// The runtime configuration, read from environment variables.
159 /// The local, managed heap
162 /// The Logger trait and implementations
168 /// Tools for testing the runtime
171 /// Reference counting
174 /// A simple single-threaded channel type for passing buffered data between
175 /// scheduler and task context
178 /// Simple reimplementation of std::comm
183 /// The runtime needs to be able to put a pointer into thread-local storage.
186 /// Bindings to pthread/windows thread-local storage.
187 mod thread_local_storage;
192 // Global command line argument storage
195 // Support for dynamic borrowck
198 /// Set up a default runtime configuration, given compiler-supplied arguments.
200 /// This is invoked by the `start` _language item_ (unstable::lang) to
201 /// run a Rust executable.
205 /// * `argc` & `argv` - The argument vector. On Unix this information is used
210 /// The return value is used as the process return code. 0 on success, 101 on error.
211 pub fn start(argc: int, argv: **u8, main: proc()) -> int {
214 let exit_code = run(main);
215 // unsafe is ok b/c we're sure that the runtime is gone
216 unsafe { cleanup(); }
221 /// Like `start` but creates an additional scheduler on the current thread,
222 /// which in most cases will be the 'main' thread, and pins the main task to it.
224 /// This is appropriate for running code that must execute on the main thread,
225 /// such as the platform event loop and GUI.
226 pub fn start_on_main_thread(argc: int, argv: **u8, main: proc()) -> int {
228 let exit_code = run_on_main_thread(main);
229 // unsafe is ok b/c we're sure that the runtime is gone
230 unsafe { cleanup(); }
235 /// One-time runtime initialization.
237 /// Initializes global state, including frobbing
238 /// the crate's logging flags, registering GC
239 /// metadata, and storing the process arguments.
240 pub fn init(argc: int, argv: **u8) {
241 // XXX: Derefing these pointers is not safe.
242 // Need to propagate the unsafety to `start`.
244 args::init(argc, argv);
250 /// One-time runtime cleanup.
252 /// This function is unsafe because it performs no checks to ensure that the
253 /// runtime has completely ceased running. It is the responsibility of the
254 /// caller to ensure that the runtime is entirely shut down and nothing will be
255 /// poking around at the internal components.
257 /// Invoking cleanup while portions of the runtime are still in use may cause
258 /// undefined behavior.
259 pub unsafe fn cleanup() {
261 local_ptr::cleanup();
264 /// Execute the main function in a scheduler.
266 /// Configures the runtime according to the environment, by default
267 /// using a task scheduler with the same number of threads as cores.
268 /// Returns a process exit code.
269 pub fn run(main: proc()) -> int {
273 pub fn run_on_main_thread(main: proc()) -> int {
277 fn run_(main: proc(), use_main_sched: bool) -> int {
278 static DEFAULT_ERROR_CODE: int = 101;
280 let nscheds = util::default_sched_threads();
282 let main = Cell::new(main);
284 // The shared list of sleeping schedulers.
285 let sleepers = SleeperList::new();
287 // Create a work queue for each scheduler, ntimes. Create an extra
288 // for the main thread if that flag is set. We won't steal from it.
289 let mut pool = deque::BufferPool::init();
290 let arr = vec::from_fn(nscheds, |_| pool.deque());
291 let (workers, stealers) = vec::unzip(arr.move_iter());
294 let mut scheds = ~[];
295 // Handles to the schedulers. When the main task ends these will be
296 // sent the Shutdown message to terminate the schedulers.
297 let mut handles = ~[];
299 for worker in workers.move_iter() {
300 rtdebug!("inserting a regular scheduler");
302 // Every scheduler is driven by an I/O event loop.
303 let loop_ = new_event_loop();
304 let mut sched = ~Scheduler::new(loop_,
308 let handle = sched.make_handle();
311 handles.push(handle);
314 // If we need a main-thread task then create a main thread scheduler
315 // that will reject any task that isn't pinned to it
316 let main_sched = if use_main_sched {
318 // Create a friend handle.
319 let mut friend_sched = scheds.pop();
320 let friend_handle = friend_sched.make_handle();
321 scheds.push(friend_sched);
323 // This scheduler needs a queue that isn't part of the stealee
325 let (worker, _) = pool.deque();
327 let main_loop = new_event_loop();
328 let mut main_sched = ~Scheduler::new_special(main_loop,
333 Some(friend_handle));
334 let mut main_handle = main_sched.make_handle();
335 // Allow the scheduler to exit when the main task exits.
336 // Note: sending the shutdown message also prevents the scheduler
337 // from pushing itself to the sleeper list, which is used for
338 // waking up schedulers for work stealing; since this is a
339 // non-work-stealing scheduler it should not be adding itself
341 main_handle.send(Shutdown);
347 // Create a shared cell for transmitting the process exit
348 // code from the main task to this function.
349 let exit_code = UnsafeArc::new(AtomicInt::new(0));
350 let exit_code_clone = exit_code.clone();
352 // Used to sanity check that the runtime only exits once
353 let exited_already = UnsafeArc::new(AtomicBool::new(false));
355 // When the main task exits, after all the tasks in the main
356 // task tree, shut down the schedulers and set the exit code.
357 let handles = handles;
358 let on_exit: proc(UnwindResult) = proc(exit_success) {
360 assert!(!(*exited_already.get()).swap(true, SeqCst),
361 "the runtime already exited");
364 let mut handles = handles;
365 for handle in handles.mut_iter() {
366 handle.send(Shutdown);
370 let exit_code = if exit_success.is_success() {
373 // If we're exiting successfully, then return the global
374 // exit status, which can be set programmatically.
375 util::get_exit_status()
379 (*exit_code_clone.get()).store(exit_code, SeqCst);
383 let mut threads = ~[];
385 let on_exit = Cell::new(on_exit);
389 // In the case where we do not use a main_thread scheduler we
390 // run the main task in one of our threads.
392 let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, None, main.take());
393 main_task.name = Some(SendStrStatic("<main>"));
394 main_task.death.on_exit = Some(on_exit.take());
395 let main_task_cell = Cell::new(main_task);
397 let sched = scheds.pop();
398 let sched_cell = Cell::new(sched);
399 let thread = do Thread::start {
400 let sched = sched_cell.take();
401 sched.bootstrap(main_task_cell.take());
403 threads.push(thread);
406 // Run each remaining scheduler in a thread.
407 for sched in scheds.move_rev_iter() {
408 rtdebug!("creating regular schedulers");
409 let sched_cell = Cell::new(sched);
410 let thread = do Thread::start {
411 let mut sched = sched_cell.take();
412 let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
413 rtdebug!("boostraping a non-primary scheduler");
415 sched.bootstrap(bootstrap_task);
417 threads.push(thread);
420 // If we do have a main thread scheduler, run it now.
424 rtdebug!("about to create the main scheduler task");
426 let mut main_sched = main_sched.unwrap();
428 let home = Sched(main_sched.make_handle());
429 let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
431 main_task.name = Some(SendStrStatic("<main>"));
432 main_task.death.on_exit = Some(on_exit.take());
433 rtdebug!("bootstrapping main_task");
435 main_sched.bootstrap(main_task);
438 rtdebug!("waiting for threads");
440 // Wait for schedulers
441 for thread in threads.move_iter() {
445 // Return the exit code
447 (*exit_code.get()).load(SeqCst)
451 pub fn in_sched_context() -> bool {
453 let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
456 match (*task).task_type {
466 pub fn in_green_task_context() -> bool {
468 let task: Option<*mut Task> = Local::try_unsafe_borrow();
471 match (*task).task_type {
472 GreenTask(_) => true,
481 pub fn new_event_loop() -> ~rtio::EventLoop {
482 match crate_map::get_crate_map() {
485 match map.event_loop_factory {
487 Some(factory) => return factory()
492 // If the crate map didn't specify a factory to create an event loop, then
493 // instead just use a basic event loop missing all I/O services to at least
494 // get the scheduler running.
495 return basic::event_loop();