]> git.lizzy.rs Git - rust.git/blob - src/libstd/rt/mod.rs
760ca8a9adadcbae741cce4423728ffd6ea3e75e
[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 * `core::task` - The user-facing interface to the Rust task model.
44 * `core::task::local_data` - The interface to local data.
45 * `core::gc` - The garbage collector.
46 * `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`.
47 * `core::condition` - Uses local data.
48 * `core::cleanup` - Local heap destruction.
49 * `core::io` - In the future `core::io` will use an `rt` implementation.
50 * `core::logging`
51 * `core::pipes`
52 * `core::comm`
53 * `core::stackwalk`
54
55 */
56
57 #[doc(hidden)];
58 #[deny(unused_imports)];
59 #[deny(unused_mut)];
60 #[deny(unused_variable)];
61 #[deny(unused_unsafe)];
62
63 use cell::Cell;
64 use clone::Clone;
65 use container::Container;
66 use iter::Times;
67 use iterator::{Iterator, IteratorUtil};
68 use option::{Some, None};
69 use ptr::RawPtr;
70 use rt::local::Local;
71 use rt::sched::{Scheduler, Shutdown};
72 use rt::sleeper_list::SleeperList;
73 use rt::task::{Task, SchedTask, GreenTask, Sched};
74 use rt::thread::Thread;
75 use rt::work_queue::WorkQueue;
76 use rt::uv::uvio::UvEventLoop;
77 use unstable::atomics::{AtomicInt, SeqCst};
78 use unstable::sync::UnsafeAtomicRcBox;
79 use vec::{OwnedVector, MutableVector};
80
81 /// The global (exchange) heap.
82 pub mod global_heap;
83
84 /// Implementations of language-critical runtime features like @.
85 pub mod task;
86
87 /// Facilities related to task failure, killing, and death.
88 mod kill;
89
90 /// The coroutine task scheduler, built on the `io` event loop.
91 mod sched;
92
93 /// Synchronous I/O.
94 pub mod io;
95
96 /// The EventLoop and internal synchronous I/O interface.
97 mod rtio;
98
99 /// libuv and default rtio implementation.
100 pub mod uv;
101
102 /// The Local trait for types that are accessible via thread-local
103 /// or task-local storage.
104 pub mod local;
105
106 /// A parallel work-stealing deque.
107 mod work_queue;
108
109 /// A parallel queue.
110 mod message_queue;
111
112 /// A parallel data structure for tracking sleeping schedulers.
113 mod sleeper_list;
114
115 /// Stack segments and caching.
116 mod stack;
117
118 /// CPU context swapping.
119 mod context;
120
121 /// Bindings to system threading libraries.
122 mod thread;
123
124 /// The runtime configuration, read from environment variables
125 pub mod env;
126
127 /// The local, managed heap
128 pub mod local_heap;
129
130 /// The Logger trait and implementations
131 pub mod logging;
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 core::comm
144 pub mod comm;
145
146 /// Routines for select()ing on pipes.
147 pub mod select;
148
149 // FIXME #5248 shouldn't be pub
150 /// The runtime needs to be able to put a pointer into thread-local storage.
151 pub mod local_ptr;
152
153 // FIXME #5248: The import in `sched` doesn't resolve unless this is pub!
154 /// Bindings to pthread/windows thread-local storage.
155 pub mod thread_local_storage;
156
157 pub mod metrics;
158
159 // FIXME #5248 shouldn't be pub
160 /// Just stuff
161 pub mod util;
162
163 // Global command line argument storage
164 pub mod args;
165
166 // Support for dynamic borrowck
167 pub mod borrowck;
168
169 /// Set up a default runtime configuration, given compiler-supplied arguments.
170 ///
171 /// This is invoked by the `start` _language item_ (unstable::lang) to
172 /// run a Rust executable.
173 ///
174 /// # Arguments
175 ///
176 /// * `argc` & `argv` - The argument vector. On Unix this information is used
177 ///   by os::args.
178 /// * `crate_map` - Runtime information about the executing crate, mostly for logging
179 ///
180 /// # Return value
181 ///
182 /// The return value is used as the process return code. 0 on success, 101 on error.
183 pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
184
185     init(argc, argv, crate_map);
186     let exit_code = run(main);
187     cleanup();
188
189     return exit_code;
190 }
191
192 /// Like `start` but creates an additional scheduler on the current thread,
193 /// which in most cases will be the 'main' thread, and pins the main task to it.
194 ///
195 /// This is appropriate for running code that must execute on the main thread,
196 /// such as the platform event loop and GUI.
197 pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
198     init(argc, argv, crate_map);
199     let exit_code = run_on_main_thread(main);
200     cleanup();
201
202     return exit_code;
203 }
204
205 /// One-time runtime initialization.
206 ///
207 /// Initializes global state, including frobbing
208 /// the crate's logging flags, registering GC
209 /// metadata, and storing the process arguments.
210 pub fn init(argc: int, argv: **u8, crate_map: *u8) {
211     // XXX: Derefing these pointers is not safe.
212     // Need to propagate the unsafety to `start`.
213     unsafe {
214         args::init(argc, argv);
215         logging::init(crate_map);
216         rust_update_gc_metadata(crate_map);
217     }
218
219     extern {
220         fn rust_update_gc_metadata(crate_map: *u8);
221     }
222 }
223
224 /// One-time runtime cleanup.
225 pub fn cleanup() {
226     args::cleanup();
227 }
228
229 /// Execute the main function in a scheduler.
230 ///
231 /// Configures the runtime according to the environment, by default
232 /// using a task scheduler with the same number of threads as cores.
233 /// Returns a process exit code.
234 pub fn run(main: ~fn()) -> int {
235     run_(main, false)
236 }
237
238 pub fn run_on_main_thread(main: ~fn()) -> int {
239     run_(main, true)
240 }
241
242 fn run_(main: ~fn(), use_main_sched: bool) -> int {
243     static DEFAULT_ERROR_CODE: int = 101;
244
245     let nscheds = util::default_sched_threads();
246
247     let main = Cell::new(main);
248
249     // The shared list of sleeping schedulers. Schedulers wake each other
250     // occassionally to do new work.
251     let sleepers = SleeperList::new();
252     // The shared work queue. Temporary until work stealing is implemented.
253     let work_queue = WorkQueue::new();
254
255     // The schedulers.
256     let mut scheds = ~[];
257     // Handles to the schedulers. When the main task ends these will be
258     // sent the Shutdown message to terminate the schedulers.
259     let mut handles = ~[];
260
261     do nscheds.times {
262         rtdebug!("inserting a regular scheduler");
263
264         // Every scheduler is driven by an I/O event loop.
265         let loop_ = ~UvEventLoop::new();
266         let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
267         let handle = sched.make_handle();
268
269         scheds.push(sched);
270         handles.push(handle);
271     }
272
273     // If we need a main-thread task then create a main thread scheduler
274     // that will reject any task that isn't pinned to it
275     let main_sched = if use_main_sched {
276
277         // Create a friend handle.
278         let mut friend_sched = scheds.pop();
279         let friend_handle = friend_sched.make_handle();
280         scheds.push(friend_sched);
281
282         let main_loop = ~UvEventLoop::new();
283         let mut main_sched = ~Scheduler::new_special(main_loop,
284                                                      work_queue.clone(),
285                                                      sleepers.clone(),
286                                                      false,
287                                                      Some(friend_handle));
288         let main_handle = main_sched.make_handle();
289         handles.push(main_handle);
290         Some(main_sched)
291     } else {
292         None
293     };
294
295     // Create a shared cell for transmitting the process exit
296     // code from the main task to this function.
297     let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
298     let exit_code_clone = exit_code.clone();
299
300     // When the main task exits, after all the tasks in the main
301     // task tree, shut down the schedulers and set the exit code.
302     let handles = Cell::new(handles);
303     let on_exit: ~fn(bool) = |exit_success| {
304
305         let mut handles = handles.take();
306         for handle in handles.mut_iter() {
307             handle.send(Shutdown);
308         }
309
310         unsafe {
311             let exit_code = if exit_success {
312                 use rt::util;
313
314                 // If we're exiting successfully, then return the global
315                 // exit status, which can be set programmatically.
316                 util::get_exit_status()
317             } else {
318                 DEFAULT_ERROR_CODE
319             };
320             (*exit_code_clone.get()).store(exit_code, SeqCst);
321         }
322     };
323
324     let mut threads = ~[];
325
326     let on_exit = Cell::new(on_exit);
327
328     if !use_main_sched {
329
330         // In the case where we do not use a main_thread scheduler we
331         // run the main task in one of our threads.
332
333         let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
334                                             main.take());
335         main_task.death.on_exit = Some(on_exit.take());
336         let main_task_cell = Cell::new(main_task);
337
338         let sched = scheds.pop();
339         let sched_cell = Cell::new(sched);
340         let thread = do Thread::start {
341             let sched = sched_cell.take();
342             sched.bootstrap(main_task_cell.take());
343         };
344         threads.push(thread);
345     }
346
347     // Run each remaining scheduler in a thread.
348     while !scheds.is_empty() {
349         rtdebug!("creating regular schedulers");
350         let sched = scheds.pop();
351         let sched_cell = Cell::new(sched);
352         let thread = do Thread::start {
353             let mut sched = sched_cell.take();
354             let bootstrap_task = ~do Task::new_root(&mut sched.stack_pool) || {
355                 rtdebug!("boostraping a non-primary scheduler");
356             };
357             sched.bootstrap(bootstrap_task);
358         };
359         threads.push(thread);
360     }
361
362     // If we do have a main thread scheduler, run it now.
363
364     if use_main_sched {
365
366         rtdebug!("about to create the main scheduler task");
367
368         let mut main_sched = main_sched.unwrap();
369
370         let home = Sched(main_sched.make_handle());
371         let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool,
372                                                   home, main.take());
373         main_task.death.on_exit = Some(on_exit.take());
374         rtdebug!("boostrapping main_task");
375
376         main_sched.bootstrap(main_task);
377     }
378
379     rtdebug!("waiting for threads");
380
381     // Wait for schedulers
382     for thread in threads.consume_iter() {
383         thread.join();
384     }
385
386     // Return the exit code
387     unsafe {
388         (*exit_code.get()).load(SeqCst)
389     }
390 }
391
392 /// Possible contexts in which Rust code may be executing.
393 /// Different runtime services are available depending on context.
394 /// Mostly used for determining if we're using the new scheduler
395 /// or the old scheduler.
396 #[deriving(Eq)]
397 pub enum RuntimeContext {
398     // Only the exchange heap is available
399     GlobalContext,
400     // The scheduler may be accessed
401     SchedulerContext,
402     // Full task services, e.g. local heap, unwinding
403     TaskContext,
404     // Running in an old-style task
405     OldTaskContext
406 }
407
408 /// Determine the current RuntimeContext
409 pub fn context() -> RuntimeContext {
410
411     use task::rt::rust_task;
412
413     if unsafe { rust_try_get_task().is_not_null() } {
414         return OldTaskContext;
415     } else if Local::exists::<Task>() {
416         // In this case we know it is a new runtime context, but we
417         // need to check which one. Going to try borrowing task to
418         // check. Task should always be in TLS, so hopefully this
419         // doesn't conflict with other ops that borrow.
420         return do Local::borrow::<Task,RuntimeContext> |task| {
421             match task.task_type {
422                 SchedTask => SchedulerContext,
423                 GreenTask(_) => TaskContext
424             }
425         };
426     } else {
427         return GlobalContext;
428     }
429
430     extern {
431         #[rust_stack]
432         pub fn rust_try_get_task() -> *rust_task;
433     }
434 }