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 * `core::task` - The user-facing interface to the Rust task model.
44 * `core::task::local_data` - The interface to local data.
45 * `core::gc` - The garbage collector.
46 * `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
47 * `core::condition` - Uses local data.
48 * `core::cleanup` - Local heap destruction.
49 * `core::io` - In the future `core::io` will use an `rt` implementation.
58 #[deny(unused_imports)];
60 #[deny(unused_variable)];
61 #[deny(unused_unsafe)];
65 use container::Container;
67 use iterator::{Iterator, IteratorUtil};
68 use option::{Some, None};
71 use rt::sched::{Scheduler, Shutdown};
72 use rt::sleeper_list::SleeperList;
73 use rt::task::{Task, SchedTask, GreenTask, Sched};
74 use rt::thread::Thread;
75 use rt::work_queue::WorkQueue;
76 use rt::uv::uvio::UvEventLoop;
77 use unstable::atomics::{AtomicInt, SeqCst};
78 use unstable::sync::UnsafeAtomicRcBox;
79 use vec::{OwnedVector, MutableVector};
81 /// The global (exchange) heap.
84 /// Implementations of language-critical runtime features like @.
87 /// Facilities related to task failure, killing, and death.
90 /// The coroutine task scheduler, built on the `io` event loop.
96 /// The EventLoop and internal synchronous I/O interface.
99 /// libuv and default rtio implementation.
102 /// The Local trait for types that are accessible via thread-local
103 /// or task-local storage.
106 /// A parallel work-stealing deque.
109 /// A parallel queue.
112 /// A parallel data structure for tracking sleeping schedulers.
115 /// Stack segments and caching.
118 /// CPU context swapping.
121 /// Bindings to system threading libraries.
124 /// The runtime configuration, read from environment variables
127 /// The local, managed heap
130 /// 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 core::comm
146 /// Routines for select()ing on pipes.
149 // FIXME #5248 shouldn't be pub
150 /// The runtime needs to be able to put a pointer into thread-local storage.
153 // FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
154 /// Bindings to pthread/windows thread-local storage.
155 pub mod thread_local_storage;
159 // FIXME #5248 shouldn't be pub
163 // Global command line argument storage
166 // Support for dynamic borrowck
169 /// Set up a default runtime configuration, given compiler-supplied arguments.
171 /// This is invoked by the `start` _language item_ (unstable::lang) to
172 /// run a Rust executable.
176 /// * `argc` & `argv` - The argument vector. On Unix this information is used
178 /// * `crate_map` - Runtime information about the executing crate, mostly for logging
182 /// The return value is used as the process return code. 0 on success, 101 on error.
183 pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
185 init(argc, argv, crate_map);
186 let exit_code = run(main);
192 /// Like `start` but creates an additional scheduler on the current thread,
193 /// which in most cases will be the 'main' thread, and pins the main task to it.
195 /// This is appropriate for running code that must execute on the main thread,
196 /// such as the platform event loop and GUI.
197 pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
198 init(argc, argv, crate_map);
199 let exit_code = run_on_main_thread(main);
205 /// One-time runtime initialization.
207 /// Initializes global state, including frobbing
208 /// the crate's logging flags, registering GC
209 /// metadata, and storing the process arguments.
210 pub fn init(argc: int, argv: **u8, crate_map: *u8) {
211 // XXX: Derefing these pointers is not safe.
212 // Need to propagate the unsafety to `start`.
214 args::init(argc, argv);
215 logging::init(crate_map);
216 rust_update_gc_metadata(crate_map);
220 fn rust_update_gc_metadata(crate_map: *u8);
224 /// One-time runtime cleanup.
229 /// Execute the main function in a scheduler.
231 /// Configures the runtime according to the environment, by default
232 /// using a task scheduler with the same number of threads as cores.
233 /// Returns a process exit code.
234 pub fn run(main: ~fn()) -> int {
238 pub fn run_on_main_thread(main: ~fn()) -> int {
242 fn run_(main: ~fn(), use_main_sched: bool) -> int {
243 static DEFAULT_ERROR_CODE: int = 101;
245 let nscheds = util::default_sched_threads();
247 let main = Cell::new(main);
249 // The shared list of sleeping schedulers. Schedulers wake each other
250 // occassionally to do new work.
251 let sleepers = SleeperList::new();
252 // The shared work queue. Temporary until work stealing is implemented.
253 let work_queue = WorkQueue::new();
256 let mut scheds = ~[];
257 // Handles to the schedulers. When the main task ends these will be
258 // sent the Shutdown message to terminate the schedulers.
259 let mut handles = ~[];
262 rtdebug!("inserting a regular scheduler");
264 // Every scheduler is driven by an I/O event loop.
265 let loop_ = ~UvEventLoop::new();
266 let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
267 let handle = sched.make_handle();
270 handles.push(handle);
273 // If we need a main-thread task then create a main thread scheduler
274 // that will reject any task that isn't pinned to it
275 let main_sched = if use_main_sched {
277 // Create a friend handle.
278 let mut friend_sched = scheds.pop();
279 let friend_handle = friend_sched.make_handle();
280 scheds.push(friend_sched);
282 let main_loop = ~UvEventLoop::new();
283 let mut main_sched = ~Scheduler::new_special(main_loop,
287 Some(friend_handle));
288 let main_handle = main_sched.make_handle();
289 handles.push(main_handle);
295 // Create a shared cell for transmitting the process exit
296 // code from the main task to this function.
297 let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
298 let exit_code_clone = exit_code.clone();
300 // When the main task exits, after all the tasks in the main
301 // task tree, shut down the schedulers and set the exit code.
302 let handles = Cell::new(handles);
303 let on_exit: ~fn(bool) = |exit_success| {
305 let mut handles = handles.take();
306 for handle in handles.mut_iter() {
307 handle.send(Shutdown);
311 let exit_code = if exit_success {
314 // If we're exiting successfully, then return the global
315 // exit status, which can be set programmatically.
316 util::get_exit_status()
320 (*exit_code_clone.get()).store(exit_code, SeqCst);
324 let mut threads = ~[];
326 let on_exit = Cell::new(on_exit);
330 // In the case where we do not use a main_thread scheduler we
331 // run the main task in one of our threads.
333 let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
335 main_task.death.on_exit = Some(on_exit.take());
336 let main_task_cell = Cell::new(main_task);
338 let sched = scheds.pop();
339 let sched_cell = Cell::new(sched);
340 let thread = do Thread::start {
341 let sched = sched_cell.take();
342 sched.bootstrap(main_task_cell.take());
344 threads.push(thread);
347 // Run each remaining scheduler in a thread.
348 while !scheds.is_empty() {
349 rtdebug!("creating regular schedulers");
350 let sched = scheds.pop();
351 let sched_cell = Cell::new(sched);
352 let thread = do Thread::start {
353 let mut sched = sched_cell.take();
354 let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
355 rtdebug!("boostraping a non-primary scheduler");
357 sched.bootstrap(bootstrap_task);
359 threads.push(thread);
362 // If we do have a main thread scheduler, run it now.
366 rtdebug!("about to create the main scheduler task");
368 let mut main_sched = main_sched.unwrap();
370 let home = Sched(main_sched.make_handle());
371 let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
373 main_task.death.on_exit = Some(on_exit.take());
374 rtdebug!("boostrapping main_task");
376 main_sched.bootstrap(main_task);
379 rtdebug!("waiting for threads");
381 // Wait for schedulers
382 for thread in threads.consume_iter() {
386 // Return the exit code
388 (*exit_code.get()).load(SeqCst)
392 /// Possible contexts in which Rust code may be executing.
393 /// Different runtime services are available depending on context.
394 /// Mostly used for determining if we're using the new scheduler
395 /// or the old scheduler.
397 pub enum RuntimeContext {
398 // Only the exchange heap is available
400 // The scheduler may be accessed
402 // Full task services, e.g. local heap, unwinding
404 // Running in an old-style task
408 /// Determine the current RuntimeContext
409 pub fn context() -> RuntimeContext {
411 use task::rt::rust_task;
413 if unsafe { rust_try_get_task().is_not_null() } {
414 return OldTaskContext;
415 } else if Local::exists::<Task>() {
416 // In this case we know it is a new runtime context, but we
417 // need to check which one. Going to try borrowing task to
418 // check. Task should always be in TLS, so hopefully this
419 // doesn't conflict with other ops that borrow.
420 return do Local::borrow::<Task,RuntimeContext> |task| {
421 match task.task_type {
422 SchedTask => SchedulerContext,
423 GreenTask(_) => TaskContext
427 return GlobalContext;
432 pub fn rust_try_get_task() -> *rust_task;