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