]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/mod.rs
auto merge of #10891 : chris-morgan/rust/macroize-(or-should-that-be-macroify)-syntax...
[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 clone::Clone;
61 use container::Container;
62 use iter::Iterator;
63 use option::{Option, None, Some};
64 use ptr::RawPtr;
65 use rt::local::Local;
66 use rt::sched::{Scheduler, Shutdown};
67 use rt::sleeper_list::SleeperList;
68 use rt::task::UnwindResult;
69 use rt::task::{Task, SchedTask, GreenTask, Sched};
70 use send_str::SendStrStatic;
71 use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
72 use unstable::sync::UnsafeArc;
73 use vec::{OwnedVector, MutableVector, ImmutableVector};
74 use vec;
75
76 use self::thread::Thread;
77
78 // the os module needs to reach into this helper, so allow general access
79 // through this reexport.
80 pub use self::util::set_exit_status;
81
82 // this is somewhat useful when a program wants to spawn a "reasonable" number
83 // of workers based on the constraints of the system that it's running on.
84 // Perhaps this shouldn't be a `pub use` though and there should be another
85 // method...
86 pub use self::util::default_sched_threads;
87
88 // Re-export of the functionality in the kill module
89 pub use self::kill::BlockedTask;
90
91 // XXX: these probably shouldn't be public...
92 #[doc(hidden)]
93 pub mod shouldnt_be_public {
94     pub use super::select::SelectInner;
95     pub use super::select::{SelectInner, SelectPortInner};
96     pub use super::local_ptr::native::maybe_tls_key;
97     #[cfg(not(windows), not(target_os = "android"))]
98     pub use super::local_ptr::compiled::RT_TLS_PTR;
99 }
100
101 // Internal macros used by the runtime.
102 mod macros;
103
104 /// Basic implementation of an EventLoop, provides no I/O interfaces
105 mod basic;
106
107 /// The global (exchange) heap.
108 pub mod global_heap;
109
110 /// Implementations of language-critical runtime features like @.
111 pub mod task;
112
113 /// Facilities related to task failure, killing, and death.
114 mod kill;
115
116 /// The coroutine task scheduler, built on the `io` event loop.
117 pub mod sched;
118
119 /// The EventLoop and internal synchronous I/O interface.
120 pub mod rtio;
121
122 /// The Local trait for types that are accessible via thread-local
123 /// or task-local storage.
124 pub mod local;
125
126 /// A parallel queue.
127 pub mod message_queue;
128
129 /// A mostly lock-free multi-producer, single consumer queue.
130 mod mpsc_queue;
131
132 /// A lock-free multi-producer, multi-consumer bounded queue.
133 mod mpmc_bounded_queue;
134
135 /// A parallel work-stealing deque
136 pub mod deque;
137
138 /// A parallel data structure for tracking sleeping schedulers.
139 pub mod sleeper_list;
140
141 /// Stack segments and caching.
142 pub mod stack;
143
144 /// CPU context swapping.
145 mod context;
146
147 /// Bindings to system threading libraries.
148 pub mod thread;
149
150 /// The runtime configuration, read from environment variables.
151 pub mod env;
152
153 /// The local, managed heap
154 pub mod local_heap;
155
156 /// The Logger trait and implementations
157 pub mod logging;
158
159 /// Crate map
160 pub mod crate_map;
161
162 /// Tools for testing the runtime
163 pub mod test;
164
165 /// Reference counting
166 pub mod rc;
167
168 /// A simple single-threaded channel type for passing buffered data between
169 /// scheduler and task context
170 pub mod tube;
171
172 /// Simple reimplementation of std::comm
173 pub mod comm;
174
175 mod select;
176
177 /// The runtime needs to be able to put a pointer into thread-local storage.
178 mod local_ptr;
179
180 /// Bindings to pthread/windows thread-local storage.
181 mod thread_local_storage;
182
183 /// Just stuff
184 mod util;
185
186 // Global command line argument storage
187 pub mod args;
188
189 // Support for dynamic borrowck
190 pub mod borrowck;
191
192 /// Set up a default runtime configuration, given compiler-supplied arguments.
193 ///
194 /// This is invoked by the `start` _language item_ (unstable::lang) to
195 /// run a Rust executable.
196 ///
197 /// # Arguments
198 ///
199 /// * `argc` & `argv` - The argument vector. On Unix this information is used
200 ///   by os::args.
201 ///
202 /// # Return value
203 ///
204 /// The return value is used as the process return code. 0 on success, 101 on error.
205 pub fn start(argc: int, argv: **u8, main: proc()) -> int {
206
207     init(argc, argv);
208     let exit_code = run(main);
209     // unsafe is ok b/c we're sure that the runtime is gone
210     unsafe { cleanup(); }
211
212     return exit_code;
213 }
214
215 /// Like `start` but creates an additional scheduler on the current thread,
216 /// which in most cases will be the 'main' thread, and pins the main task to it.
217 ///
218 /// This is appropriate for running code that must execute on the main thread,
219 /// such as the platform event loop and GUI.
220 pub fn start_on_main_thread(argc: int, argv: **u8, main: proc()) -> int {
221     init(argc, argv);
222     let exit_code = run_on_main_thread(main);
223     // unsafe is ok b/c we're sure that the runtime is gone
224     unsafe { cleanup(); }
225
226     return exit_code;
227 }
228
229 /// One-time runtime initialization.
230 ///
231 /// Initializes global state, including frobbing
232 /// the crate's logging flags, registering GC
233 /// metadata, and storing the process arguments.
234 pub fn init(argc: int, argv: **u8) {
235     // XXX: Derefing these pointers is not safe.
236     // Need to propagate the unsafety to `start`.
237     unsafe {
238         args::init(argc, argv);
239         env::init();
240         logging::init();
241     }
242 }
243
244 /// One-time runtime cleanup.
245 ///
246 /// This function is unsafe because it performs no checks to ensure that the
247 /// runtime has completely ceased running. It is the responsibility of the
248 /// caller to ensure that the runtime is entirely shut down and nothing will be
249 /// poking around at the internal components.
250 ///
251 /// Invoking cleanup while portions of the runtime are still in use may cause
252 /// undefined behavior.
253 pub unsafe fn cleanup() {
254     args::cleanup();
255     local_ptr::cleanup();
256 }
257
258 /// Execute the main function in a scheduler.
259 ///
260 /// Configures the runtime according to the environment, by default
261 /// using a task scheduler with the same number of threads as cores.
262 /// Returns a process exit code.
263 pub fn run(main: proc()) -> int {
264     run_(main, false)
265 }
266
267 pub fn run_on_main_thread(main: proc()) -> int {
268     run_(main, true)
269 }
270
271 fn run_(main: proc(), use_main_sched: bool) -> int {
272     static DEFAULT_ERROR_CODE: int = 101;
273
274     let nscheds = util::default_sched_threads();
275
276     let mut main = Some(main);
277
278     // The shared list of sleeping schedulers.
279     let sleepers = SleeperList::new();
280
281     // Create a work queue for each scheduler, ntimes. Create an extra
282     // for the main thread if that flag is set. We won't steal from it.
283     let mut pool = deque::BufferPool::new();
284     let arr = vec::from_fn(nscheds, |_| pool.deque());
285     let (workers, stealers) = vec::unzip(arr.move_iter());
286
287     // The schedulers.
288     let mut scheds = ~[];
289     // Handles to the schedulers. When the main task ends these will be
290     // sent the Shutdown message to terminate the schedulers.
291     let mut handles = ~[];
292
293     for worker in workers.move_iter() {
294         rtdebug!("inserting a regular scheduler");
295
296         // Every scheduler is driven by an I/O event loop.
297         let loop_ = new_event_loop();
298         let mut sched = ~Scheduler::new(loop_,
299                                         worker,
300                                         stealers.clone(),
301                                         sleepers.clone());
302         let handle = sched.make_handle();
303
304         scheds.push(sched);
305         handles.push(handle);
306     }
307
308     // If we need a main-thread task then create a main thread scheduler
309     // that will reject any task that isn't pinned to it
310     let main_sched = if use_main_sched {
311
312         // Create a friend handle.
313         let mut friend_sched = scheds.pop();
314         let friend_handle = friend_sched.make_handle();
315         scheds.push(friend_sched);
316
317         // This scheduler needs a queue that isn't part of the stealee
318         // set.
319         let (worker, _) = pool.deque();
320
321         let main_loop = new_event_loop();
322         let mut main_sched = ~Scheduler::new_special(main_loop,
323                                                      worker,
324                                                      stealers.clone(),
325                                                      sleepers.clone(),
326                                                      false,
327                                                      Some(friend_handle));
328         let mut main_handle = main_sched.make_handle();
329         // Allow the scheduler to exit when the main task exits.
330         // Note: sending the shutdown message also prevents the scheduler
331         // from pushing itself to the sleeper list, which is used for
332         // waking up schedulers for work stealing; since this is a
333         // non-work-stealing scheduler it should not be adding itself
334         // to the list.
335         main_handle.send(Shutdown);
336         Some(main_sched)
337     } else {
338         None
339     };
340
341     // Create a shared cell for transmitting the process exit
342     // code from the main task to this function.
343     let exit_code = UnsafeArc::new(AtomicInt::new(0));
344     let exit_code_clone = exit_code.clone();
345
346     // Used to sanity check that the runtime only exits once
347     let exited_already = UnsafeArc::new(AtomicBool::new(false));
348
349     // When the main task exits, after all the tasks in the main
350     // task tree, shut down the schedulers and set the exit code.
351     let handles = handles;
352     let on_exit: proc(UnwindResult) = proc(exit_success) {
353         unsafe {
354             assert!(!(*exited_already.get()).swap(true, SeqCst),
355                     "the runtime already exited");
356         }
357
358         let mut handles = handles;
359         for handle in handles.mut_iter() {
360             handle.send(Shutdown);
361         }
362
363         unsafe {
364             let exit_code = if exit_success.is_success() {
365                 use rt::util;
366
367                 // If we're exiting successfully, then return the global
368                 // exit status, which can be set programmatically.
369                 util::get_exit_status()
370             } else {
371                 DEFAULT_ERROR_CODE
372             };
373             (*exit_code_clone.get()).store(exit_code, SeqCst);
374         }
375     };
376
377     let mut threads = ~[];
378     let mut on_exit = Some(on_exit);
379
380     if !use_main_sched {
381
382         // In the case where we do not use a main_thread scheduler we
383         // run the main task in one of our threads.
384
385         let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
386                                             None,
387                                             ::util::replace(&mut main,
388                                                             None).unwrap());
389         main_task.name = Some(SendStrStatic("<main>"));
390         main_task.death.on_exit = ::util::replace(&mut on_exit, None);
391
392         let sched = scheds.pop();
393         let main_task = main_task;
394         let thread = do Thread::start {
395             sched.bootstrap(main_task);
396         };
397         threads.push(thread);
398     }
399
400     // Run each remaining scheduler in a thread.
401     for sched in scheds.move_rev_iter() {
402         rtdebug!("creating regular schedulers");
403         let thread = do Thread::start {
404             let mut sched = sched;
405             let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool, None) || {
406                 rtdebug!("boostraping a non-primary scheduler");
407             };
408             sched.bootstrap(bootstrap_task);
409         };
410         threads.push(thread);
411     }
412
413     // If we do have a main thread scheduler, run it now.
414
415     if use_main_sched {
416         rtdebug!("about to create the main scheduler task");
417
418         let mut main_sched = main_sched.unwrap();
419
420         let home = Sched(main_sched.make_handle());
421         let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
422                                                   None,
423                                                   home,
424                                                   ::util::replace(&mut main,
425                                                                   None).
426                                                                   unwrap());
427         main_task.name = Some(SendStrStatic("<main>"));
428         main_task.death.on_exit = ::util::replace(&mut on_exit, None);
429         rtdebug!("bootstrapping main_task");
430
431         main_sched.bootstrap(main_task);
432     }
433
434     rtdebug!("waiting for threads");
435
436     // Wait for schedulers
437     for thread in threads.move_iter() {
438         thread.join();
439     }
440
441     // Return the exit code
442     unsafe {
443         (*exit_code.get()).load(SeqCst)
444     }
445 }
446
447 pub fn in_sched_context() -> bool {
448     unsafe {
449         let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
450         match task_ptr {
451             Some(task) => {
452                 match (*task).task_type {
453                     SchedTask => true,
454                     _ => false
455                 }
456             }
457             None => false
458         }
459     }
460 }
461
462 pub fn in_green_task_context() -> bool {
463     unsafe {
464         let task: Option<*mut Task> = Local::try_unsafe_borrow();
465         match task {
466             Some(task) => {
467                 match (*task).task_type {
468                     GreenTask(_) => true,
469                     _ => false
470                 }
471             }
472             None => false
473         }
474     }
475 }
476
477 pub fn new_event_loop() -> ~rtio::EventLoop {
478     match crate_map::get_crate_map() {
479         None => {}
480         Some(map) => {
481             match map.event_loop_factory {
482                 None => {}
483                 Some(factory) => return factory()
484             }
485         }
486     }
487
488     // If the crate map didn't specify a factory to create an event loop, then
489     // instead just use a basic event loop missing all I/O services to at least
490     // get the scheduler running.
491     return basic::event_loop();
492 }