]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/mod.rs
58e86f97f71e16c4893c5e3cf5daee1c8c87b6d3
[rust.git] / src / libstd / rt / mod.rs
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.
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 Rust Runtime, including the task scheduler and I/O
12
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
19 executables.
20
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.
27
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
32 rest of the runtime.
33
34 All other runtime features are task-local, including the local heap,
35 the garbage collector, local storage, logging and the stack unwinder.
36
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.
40
41 Several modules in `core` are clients of `rt`:
42
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.
50 * `std::logging`
51 * `std::pipes`
52 * `std::comm`
53 * `std::stackwalk`
54
55 */
56
57 #[doc(hidden)];
58 #[deny(unused_imports)];
59 #[deny(unused_mut)];
60 #[deny(unused_variable)];
61 #[deny(unused_unsafe)];
62
63 use cell::Cell;
64 use clone::Clone;
65 use container::Container;
66 use iterator::{Iterator, range};
67 use option::{Some, None};
68 use ptr::RawPtr;
69 use rt::local::Local;
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};
79
80 /// The global (exchange) heap.
81 pub mod global_heap;
82
83 /// Implementations of language-critical runtime features like @.
84 pub mod task;
85
86 /// Facilities related to task failure, killing, and death.
87 mod kill;
88
89 /// The coroutine task scheduler, built on the `io` event loop.
90 mod sched;
91
92 /// Synchronous I/O.
93 pub mod io;
94
95 /// The EventLoop and internal synchronous I/O interface.
96 mod rtio;
97
98 /// libuv and default rtio implementation.
99 pub mod uv;
100
101 /// The Local trait for types that are accessible via thread-local
102 /// or task-local storage.
103 pub mod local;
104
105 /// A parallel work-stealing deque.
106 mod work_queue;
107
108 /// A parallel queue.
109 mod message_queue;
110
111 /// A parallel data structure for tracking sleeping schedulers.
112 mod sleeper_list;
113
114 /// Stack segments and caching.
115 pub mod stack;
116
117 /// CPU context swapping.
118 mod context;
119
120 /// Bindings to system threading libraries.
121 mod thread;
122
123 /// The runtime configuration, read from environment variables.
124 pub mod env;
125
126 /// The local, managed heap
127 pub mod local_heap;
128
129 /// The Logger trait and implementations
130 pub mod logging;
131
132 /// Tools for testing the runtime
133 pub mod test;
134
135 /// Reference counting
136 pub mod rc;
137
138 /// A simple single-threaded channel type for passing buffered data between
139 /// scheduler and task context
140 pub mod tube;
141
142 /// Simple reimplementation of std::comm
143 pub mod comm;
144
145 mod select;
146
147 // FIXME #5248 shouldn't be pub
148 /// The runtime needs to be able to put a pointer into thread-local storage.
149 pub mod local_ptr;
150
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;
154
155 pub mod metrics;
156
157 // FIXME #5248 shouldn't be pub
158 /// Just stuff
159 pub mod util;
160
161 // Global command line argument storage
162 pub mod args;
163
164 // Support for dynamic borrowck
165 pub mod borrowck;
166
167 /// Set up a default runtime configuration, given compiler-supplied arguments.
168 ///
169 /// This is invoked by the `start` _language item_ (unstable::lang) to
170 /// run a Rust executable.
171 ///
172 /// # Arguments
173 ///
174 /// * `argc` & `argv` - The argument vector. On Unix this information is used
175 ///   by os::args.
176 /// * `crate_map` - Runtime information about the executing crate, mostly for logging
177 ///
178 /// # Return value
179 ///
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 {
182
183     init(argc, argv, crate_map);
184     let exit_code = run(main);
185     cleanup();
186
187     return exit_code;
188 }
189
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.
192 ///
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);
198     cleanup();
199
200     return exit_code;
201 }
202
203 /// One-time runtime initialization.
204 ///
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`.
211     unsafe {
212         args::init(argc, argv);
213         env::init();
214         logging::init(crate_map);
215         rust_update_gc_metadata(crate_map);
216     }
217
218     extern {
219         fn rust_update_gc_metadata(crate_map: *u8);
220     }
221 }
222
223 /// One-time runtime cleanup.
224 pub fn cleanup() {
225     args::cleanup();
226 }
227
228 /// Execute the main function in a scheduler.
229 ///
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 {
234     run_(main, false)
235 }
236
237 pub fn run_on_main_thread(main: ~fn()) -> int {
238     run_(main, true)
239 }
240
241 fn run_(main: ~fn(), use_main_sched: bool) -> int {
242     static DEFAULT_ERROR_CODE: int = 101;
243
244     let nscheds = util::default_sched_threads();
245
246     let main = Cell::new(main);
247
248     // The shared list of sleeping schedulers.
249     let sleepers = SleeperList::new();
250
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);
257     }
258
259     // The schedulers.
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 = ~[];
264
265     for i in range(0u, nscheds) {
266         rtdebug!("inserting a regular scheduler");
267
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(),
272                                         work_queues.clone(),
273                                         sleepers.clone());
274         let handle = sched.make_handle();
275
276         scheds.push(sched);
277         handles.push(handle);
278     }
279
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 {
283
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);
288
289         // This scheduler needs a queue that isn't part of the stealee
290         // set.
291         let work_queue = WorkQueue::new();
292
293         let main_loop = ~UvEventLoop::new();
294         let mut main_sched = ~Scheduler::new_special(main_loop,
295                                                      work_queue,
296                                                      work_queues.clone(),
297                                                      sleepers.clone(),
298                                                      false,
299                                                      Some(friend_handle));
300         let main_handle = main_sched.make_handle();
301         handles.push(main_handle);
302         Some(main_sched)
303     } else {
304         None
305     };
306
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();
311
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| {
316
317         let mut handles = handles.take();
318         for handle in handles.mut_iter() {
319             handle.send(Shutdown);
320         }
321
322         unsafe {
323             let exit_code = if exit_success {
324                 use rt::util;
325
326                 // If we're exiting successfully, then return the global
327                 // exit status, which can be set programmatically.
328                 util::get_exit_status()
329             } else {
330                 DEFAULT_ERROR_CODE
331             };
332             (*exit_code_clone.get()).store(exit_code, SeqCst);
333         }
334     };
335
336     let mut threads = ~[];
337
338     let on_exit = Cell::new(on_exit);
339
340     if !use_main_sched {
341
342         // In the case where we do not use a main_thread scheduler we
343         // run the main task in one of our threads.
344
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);
348
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());
354         };
355         threads.push(thread);
356     }
357
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");
367             };
368             sched.bootstrap(bootstrap_task);
369         };
370         threads.push(thread);
371     }
372
373     // If we do have a main thread scheduler, run it now.
374
375     if use_main_sched {
376
377         rtdebug!("about to create the main scheduler task");
378
379         let mut main_sched = main_sched.unwrap();
380
381         let home = Sched(main_sched.make_handle());
382         let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
383                                                   home, main.take());
384         main_task.death.on_exit = Some(on_exit.take());
385         rtdebug!("bootstrapping main_task");
386
387         main_sched.bootstrap(main_task);
388     }
389
390     rtdebug!("waiting for threads");
391
392     // Wait for schedulers
393     for thread in threads.move_iter() {
394         thread.join();
395     }
396
397     // Return the exit code
398     unsafe {
399         (*exit_code.get()).load(SeqCst)
400     }
401 }
402
403 pub fn in_sched_context() -> bool {
404     unsafe {
405         match Local::try_unsafe_borrow::<Task>() {
406             Some(task) => {
407                 match (*task).task_type {
408                     SchedTask => true,
409                     _ => false
410                 }
411             }
412             None => false
413         }
414     }
415 }
416
417 pub fn in_green_task_context() -> bool {
418     unsafe {
419         match Local::try_unsafe_borrow::<Task>() {
420             Some(task) => {
421                 match (*task).task_type {
422                     GreenTask(_) => true,
423                     _ => false
424                 }
425             }
426             None => false
427         }
428     }
429 }