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