]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/mod.rs
auto merge of #9301 : luqmana/rust/ncm, r=brson
[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 // XXX: this should not be here.
58 #[allow(missing_doc)];
59
60 use cell::Cell;
61 use clone::Clone;
62 use container::Container;
63 use iter::Iterator;
64 use option::{Option, None, Some};
65 use ptr::RawPtr;
66 use rt::local::Local;
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;
75 use vec;
76 use vec::{OwnedVector, MutableVector, ImmutableVector};
77
78 /// The global (exchange) heap.
79 pub mod global_heap;
80
81 /// Implementations of language-critical runtime features like @.
82 pub mod task;
83
84 /// Facilities related to task failure, killing, and death.
85 mod kill;
86
87 /// The coroutine task scheduler, built on the `io` event loop.
88 mod sched;
89
90 /// Synchronous I/O.
91 pub mod io;
92
93 /// The EventLoop and internal synchronous I/O interface.
94 mod rtio;
95
96 /// libuv and default rtio implementation.
97 pub mod uv;
98
99 /// The Local trait for types that are accessible via thread-local
100 /// or task-local storage.
101 pub mod local;
102
103 /// A parallel work-stealing deque.
104 mod work_queue;
105
106 /// A parallel queue.
107 mod message_queue;
108
109 /// A parallel data structure for tracking sleeping schedulers.
110 mod sleeper_list;
111
112 /// Stack segments and caching.
113 pub mod stack;
114
115 /// CPU context swapping.
116 mod context;
117
118 /// Bindings to system threading libraries.
119 mod thread;
120
121 /// The runtime configuration, read from environment variables.
122 pub mod env;
123
124 /// The local, managed heap
125 pub mod local_heap;
126
127 /// The Logger trait and implementations
128 pub mod logging;
129
130 /// Crate map
131 pub mod crate_map;
132
133 /// Tools for testing the runtime
134 pub mod test;
135
136 /// Reference counting
137 pub mod rc;
138
139 /// A simple single-threaded channel type for passing buffered data between
140 /// scheduler and task context
141 pub mod tube;
142
143 /// Simple reimplementation of std::comm
144 pub mod comm;
145
146 mod select;
147
148 // FIXME #5248 shouldn't be pub
149 /// The runtime needs to be able to put a pointer into thread-local storage.
150 pub mod local_ptr;
151
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;
155
156 // FIXME #5248 shouldn't be pub
157 /// Just stuff
158 pub mod util;
159
160 // Global command line argument storage
161 pub mod args;
162
163 // Support for dynamic borrowck
164 pub mod borrowck;
165
166 /// Set up a default runtime configuration, given compiler-supplied arguments.
167 ///
168 /// This is invoked by the `start` _language item_ (unstable::lang) to
169 /// run a Rust executable.
170 ///
171 /// # Arguments
172 ///
173 /// * `argc` & `argv` - The argument vector. On Unix this information is used
174 ///   by os::args.
175 ///
176 /// # Return value
177 ///
178 /// The return value is used as the process return code. 0 on success, 101 on error.
179 #[cfg(stage0)]
180 pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
181
182     init(argc, argv, crate_map);
183     let exit_code = run(main);
184     cleanup();
185
186     return exit_code;
187 }
188 #[cfg(not(stage0))]
189 pub fn start(argc: int, argv: **u8, main: ~fn()) -> int {
190
191     init(argc, argv);
192     let exit_code = run(main);
193     cleanup();
194
195     return exit_code;
196 }
197
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.
200 ///
201 /// This is appropriate for running code that must execute on the main thread,
202 /// such as the platform event loop and GUI.
203 #[cfg(stage0)]
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);
207     cleanup();
208
209     return exit_code;
210 }
211 #[cfg(not(stage0))]
212 pub fn start_on_main_thread(argc: int, argv: **u8, main: ~fn()) -> int {
213     init(argc, argv);
214     let exit_code = run_on_main_thread(main);
215     cleanup();
216
217     return exit_code;
218 }
219
220 /// One-time runtime initialization.
221 ///
222 /// Initializes global state, including frobbing
223 /// the crate's logging flags, registering GC
224 /// metadata, and storing the process arguments.
225 #[cfg(stage0)]
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`.
229     unsafe {
230         args::init(argc, argv);
231         env::init();
232         logging::init(crate_map);
233     }
234 }
235 #[cfg(not(stage0))]
236 pub fn init(argc: int, argv: **u8) {
237     // XXX: Derefing these pointers is not safe.
238     // Need to propagate the unsafety to `start`.
239     unsafe {
240         args::init(argc, argv);
241         env::init();
242         logging::init();
243     }
244 }
245
246 /// One-time runtime cleanup.
247 pub fn cleanup() {
248     args::cleanup();
249 }
250
251 /// Execute the main function in a scheduler.
252 ///
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 {
257     run_(main, false)
258 }
259
260 pub fn run_on_main_thread(main: ~fn()) -> int {
261     run_(main, true)
262 }
263
264 fn run_(main: ~fn(), use_main_sched: bool) -> int {
265     static DEFAULT_ERROR_CODE: int = 101;
266
267     let nscheds = util::default_sched_threads();
268
269     let main = Cell::new(main);
270
271     // The shared list of sleeping schedulers.
272     let sleepers = SleeperList::new();
273
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());
277
278     // The schedulers.
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 = ~[];
283
284     for work_queue in work_queues.iter() {
285         rtdebug!("inserting a regular scheduler");
286
287         // Every scheduler is driven by an I/O event loop.
288         let loop_ = ~UvEventLoop::new();
289         let mut sched = ~Scheduler::new(loop_,
290                                         work_queue.clone(),
291                                         work_queues.clone(),
292                                         sleepers.clone());
293         let handle = sched.make_handle();
294
295         scheds.push(sched);
296         handles.push(handle);
297     }
298
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 {
302
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);
307
308         // This scheduler needs a queue that isn't part of the stealee
309         // set.
310         let work_queue = WorkQueue::new();
311
312         let main_loop = ~UvEventLoop::new();
313         let mut main_sched = ~Scheduler::new_special(main_loop,
314                                                      work_queue,
315                                                      work_queues.clone(),
316                                                      sleepers.clone(),
317                                                      false,
318                                                      Some(friend_handle));
319         let main_handle = main_sched.make_handle();
320         handles.push(main_handle);
321         Some(main_sched)
322     } else {
323         None
324     };
325
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();
330
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");
336
337         let mut handles = handles.take();
338         for handle in handles.mut_iter() {
339             handle.send(Shutdown);
340         }
341
342         unsafe {
343             let exit_code = if exit_success {
344                 use rt::util;
345
346                 // If we're exiting successfully, then return the global
347                 // exit status, which can be set programmatically.
348                 util::get_exit_status()
349             } else {
350                 DEFAULT_ERROR_CODE
351             };
352             (*exit_code_clone.get()).store(exit_code, SeqCst);
353         }
354     };
355
356     let mut threads = ~[];
357
358     let on_exit = Cell::new(on_exit);
359
360     if !use_main_sched {
361
362         // In the case where we do not use a main_thread scheduler we
363         // run the main task in one of our threads.
364
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);
368
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());
374         };
375         threads.push(thread);
376     }
377
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");
386             };
387             sched.bootstrap(bootstrap_task);
388         };
389         threads.push(thread);
390     }
391
392     // If we do have a main thread scheduler, run it now.
393
394     if use_main_sched {
395
396         rtdebug!("about to create the main scheduler task");
397
398         let mut main_sched = main_sched.unwrap();
399
400         let home = Sched(main_sched.make_handle());
401         let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
402                                                   home, main.take());
403         main_task.death.on_exit = Some(on_exit.take());
404         rtdebug!("bootstrapping main_task");
405
406         main_sched.bootstrap(main_task);
407     }
408
409     rtdebug!("waiting for threads");
410
411     // Wait for schedulers
412     for thread in threads.move_iter() {
413         thread.join();
414     }
415
416     // Return the exit code
417     unsafe {
418         (*exit_code.get()).load(SeqCst)
419     }
420 }
421
422 pub fn in_sched_context() -> bool {
423     unsafe {
424         let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
425         match task_ptr {
426             Some(task) => {
427                 match (*task).task_type {
428                     SchedTask => true,
429                     _ => false
430                 }
431             }
432             None => false
433         }
434     }
435 }
436
437 pub fn in_green_task_context() -> bool {
438     unsafe {
439         let task: Option<*mut Task> = Local::try_unsafe_borrow();
440         match task {
441             Some(task) => {
442                 match (*task).task_type {
443                     GreenTask(_) => true,
444                     _ => false
445                 }
446             }
447             None => false
448         }
449     }
450 }