]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/mod.rs
auto merge of #10678 : alexcrichton/rust/issue-4877, r=pcwalton
[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::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};
75 use vec;
76
77 use self::thread::Thread;
78
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;
82
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
86 // method...
87 pub use self::util::default_sched_threads;
88
89 // Re-export of the functionality in the kill module
90 pub use self::kill::BlockedTask;
91
92 // XXX: these probably shouldn't be public...
93 #[doc(hidden)]
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;
100 }
101
102 // Internal macros used by the runtime.
103 mod macros;
104
105 /// Basic implementation of an EventLoop, provides no I/O interfaces
106 mod basic;
107
108 /// The global (exchange) heap.
109 pub mod global_heap;
110
111 /// Implementations of language-critical runtime features like @.
112 pub mod task;
113
114 /// Facilities related to task failure, killing, and death.
115 mod kill;
116
117 /// The coroutine task scheduler, built on the `io` event loop.
118 pub mod sched;
119
120 #[cfg(stage0)]
121 pub mod io {
122     pub use io::stdio;
123 }
124
125 /// The EventLoop and internal synchronous I/O interface.
126 pub mod rtio;
127
128 /// The Local trait for types that are accessible via thread-local
129 /// or task-local storage.
130 pub mod local;
131
132 /// A parallel queue.
133 pub mod message_queue;
134
135 /// A mostly lock-free multi-producer, single consumer queue.
136 mod mpsc_queue;
137
138 /// A lock-free multi-producer, multi-consumer bounded queue.
139 mod mpmc_bounded_queue;
140
141 /// A parallel work-stealing deque
142 pub mod deque;
143
144 /// A parallel data structure for tracking sleeping schedulers.
145 pub mod sleeper_list;
146
147 /// Stack segments and caching.
148 pub mod stack;
149
150 /// CPU context swapping.
151 mod context;
152
153 /// Bindings to system threading libraries.
154 pub mod thread;
155
156 /// The runtime configuration, read from environment variables.
157 pub mod env;
158
159 /// The local, managed heap
160 pub mod local_heap;
161
162 /// The Logger trait and implementations
163 pub mod logging;
164
165 /// Crate map
166 pub mod crate_map;
167
168 /// Tools for testing the runtime
169 pub mod test;
170
171 /// Reference counting
172 pub mod rc;
173
174 /// A simple single-threaded channel type for passing buffered data between
175 /// scheduler and task context
176 pub mod tube;
177
178 /// Simple reimplementation of std::comm
179 pub mod comm;
180
181 mod select;
182
183 /// The runtime needs to be able to put a pointer into thread-local storage.
184 mod local_ptr;
185
186 /// Bindings to pthread/windows thread-local storage.
187 mod thread_local_storage;
188
189 /// Just stuff
190 mod util;
191
192 // Global command line argument storage
193 pub mod args;
194
195 // Support for dynamic borrowck
196 pub mod borrowck;
197
198 /// Set up a default runtime configuration, given compiler-supplied arguments.
199 ///
200 /// This is invoked by the `start` _language item_ (unstable::lang) to
201 /// run a Rust executable.
202 ///
203 /// # Arguments
204 ///
205 /// * `argc` & `argv` - The argument vector. On Unix this information is used
206 ///   by os::args.
207 ///
208 /// # Return value
209 ///
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 {
212
213     init(argc, argv);
214     let exit_code = run(main);
215     // unsafe is ok b/c we're sure that the runtime is gone
216     unsafe { cleanup(); }
217
218     return exit_code;
219 }
220
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.
223 ///
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 {
227     init(argc, argv);
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(); }
231
232     return exit_code;
233 }
234
235 /// One-time runtime initialization.
236 ///
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`.
243     unsafe {
244         args::init(argc, argv);
245         env::init();
246         logging::init();
247     }
248 }
249
250 /// One-time runtime cleanup.
251 ///
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.
256 ///
257 /// Invoking cleanup while portions of the runtime are still in use may cause
258 /// undefined behavior.
259 pub unsafe fn cleanup() {
260     args::cleanup();
261     local_ptr::cleanup();
262 }
263
264 /// Execute the main function in a scheduler.
265 ///
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 {
270     run_(main, false)
271 }
272
273 pub fn run_on_main_thread(main: proc()) -> int {
274     run_(main, true)
275 }
276
277 fn run_(main: proc(), use_main_sched: bool) -> int {
278     static DEFAULT_ERROR_CODE: int = 101;
279
280     let nscheds = util::default_sched_threads();
281
282     let main = Cell::new(main);
283
284     // The shared list of sleeping schedulers.
285     let sleepers = SleeperList::new();
286
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());
292
293     // The schedulers.
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 = ~[];
298
299     for worker in workers.move_iter() {
300         rtdebug!("inserting a regular scheduler");
301
302         // Every scheduler is driven by an I/O event loop.
303         let loop_ = new_event_loop();
304         let mut sched = ~Scheduler::new(loop_,
305                                         worker,
306                                         stealers.clone(),
307                                         sleepers.clone());
308         let handle = sched.make_handle();
309
310         scheds.push(sched);
311         handles.push(handle);
312     }
313
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 {
317
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);
322
323         // This scheduler needs a queue that isn't part of the stealee
324         // set.
325         let (worker, _) = pool.deque();
326
327         let main_loop = new_event_loop();
328         let mut main_sched = ~Scheduler::new_special(main_loop,
329                                                      worker,
330                                                      stealers.clone(),
331                                                      sleepers.clone(),
332                                                      false,
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
340         // to the list.
341         main_handle.send(Shutdown);
342         Some(main_sched)
343     } else {
344         None
345     };
346
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();
351
352     // Used to sanity check that the runtime only exits once
353     let exited_already = UnsafeArc::new(AtomicBool::new(false));
354
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) {
359         unsafe {
360             assert!(!(*exited_already.get()).swap(true, SeqCst),
361                     "the runtime already exited");
362         }
363
364         let mut handles = handles;
365         for handle in handles.mut_iter() {
366             handle.send(Shutdown);
367         }
368
369         unsafe {
370             let exit_code = if exit_success.is_success() {
371                 use rt::util;
372
373                 // If we're exiting successfully, then return the global
374                 // exit status, which can be set programmatically.
375                 util::get_exit_status()
376             } else {
377                 DEFAULT_ERROR_CODE
378             };
379             (*exit_code_clone.get()).store(exit_code, SeqCst);
380         }
381     };
382
383     let mut threads = ~[];
384
385     let on_exit = Cell::new(on_exit);
386
387     if !use_main_sched {
388
389         // In the case where we do not use a main_thread scheduler we
390         // run the main task in one of our threads.
391
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);
396
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());
402         };
403         threads.push(thread);
404     }
405
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");
414             };
415             sched.bootstrap(bootstrap_task);
416         };
417         threads.push(thread);
418     }
419
420     // If we do have a main thread scheduler, run it now.
421
422     if use_main_sched {
423
424         rtdebug!("about to create the main scheduler task");
425
426         let mut main_sched = main_sched.unwrap();
427
428         let home = Sched(main_sched.make_handle());
429         let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, None,
430                                                   home, main.take());
431         main_task.name = Some(SendStrStatic("<main>"));
432         main_task.death.on_exit = Some(on_exit.take());
433         rtdebug!("bootstrapping main_task");
434
435         main_sched.bootstrap(main_task);
436     }
437
438     rtdebug!("waiting for threads");
439
440     // Wait for schedulers
441     for thread in threads.move_iter() {
442         thread.join();
443     }
444
445     // Return the exit code
446     unsafe {
447         (*exit_code.get()).load(SeqCst)
448     }
449 }
450
451 pub fn in_sched_context() -> bool {
452     unsafe {
453         let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
454         match task_ptr {
455             Some(task) => {
456                 match (*task).task_type {
457                     SchedTask => true,
458                     _ => false
459                 }
460             }
461             None => false
462         }
463     }
464 }
465
466 pub fn in_green_task_context() -> bool {
467     unsafe {
468         let task: Option<*mut Task> = Local::try_unsafe_borrow();
469         match task {
470             Some(task) => {
471                 match (*task).task_type {
472                     GreenTask(_) => true,
473                     _ => false
474                 }
475             }
476             None => false
477         }
478     }
479 }
480
481 pub fn new_event_loop() -> ~rtio::EventLoop {
482     match crate_map::get_crate_map() {
483         None => {}
484         Some(map) => {
485             match map.event_loop_factory {
486                 None => {}
487                 Some(factory) => return factory()
488             }
489         }
490     }
491
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();
496 }