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