diff options
| author | bors <bors@rust-lang.org> | 2013-07-27 18:25:24 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-07-27 18:25:24 -0700 |
| commit | 82b29ae5a583366d30e8052cab390fce031ab708 (patch) | |
| tree | b417359833b7c9b243490c87860c936f5f556000 /src/libstd/rt | |
| parent | b027c5fce3e74dfa5583224967e38ef40518ecfb (diff) | |
| parent | 34a27db8bf90d9cc3727a1c6654eccdc7018eb29 (diff) | |
| download | rust-82b29ae5a583366d30e8052cab390fce031ab708.tar.gz rust-82b29ae5a583366d30e8052cab390fce031ab708.zip | |
auto merge of #7864 : brson/rust/start-on-main-thread, r=brson
Applications that need to use the GUI can override start and set up the runtime using this function.
Diffstat (limited to 'src/libstd/rt')
| -rw-r--r-- | src/libstd/rt/mod.rs | 71 |
1 files changed, 61 insertions, 10 deletions
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index ef6155b1fb7..4eaf772d41a 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -65,11 +65,11 @@ use clone::Clone; use container::Container; use iter::Times; use iterator::IteratorUtil; -use option::Some; +use option::{Some, None}; use ptr::RawPtr; use rt::sched::{Scheduler, Shutdown}; use rt::sleeper_list::SleeperList; -use rt::task::Task; +use rt::task::{Task, Sched}; use rt::thread::Thread; use rt::work_queue::WorkQueue; use rt::uv::uvio::UvEventLoop; @@ -187,6 +187,19 @@ pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int { return exit_code; } +/// Like `start` but creates an additional scheduler on the current thread, +/// which in most cases will be the 'main' thread, and pins the main task to it. +/// +/// This is appropriate for running code that must execute on the main thread, +/// such as the platform event loop and GUI. +pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int { + init(argc, argv, crate_map); + let exit_code = run_on_main_thread(main); + cleanup(); + + return exit_code; +} + /// One-time runtime initialization. /// /// Initializes global state, including frobbing @@ -217,10 +230,17 @@ pub fn cleanup() { /// using a task scheduler with the same number of threads as cores. /// Returns a process exit code. pub fn run(main: ~fn()) -> int { + run_(main, false) +} + +pub fn run_on_main_thread(main: ~fn()) -> int { + run_(main, true) +} +fn run_(main: ~fn(), use_main_sched: bool) -> int { static DEFAULT_ERROR_CODE: int = 101; - let nthreads = util::default_sched_threads(); + let nscheds = util::default_sched_threads(); // The shared list of sleeping schedulers. Schedulers wake each other // occassionally to do new work. @@ -234,7 +254,7 @@ pub fn run(main: ~fn()) -> int { // sent the Shutdown message to terminate the schedulers. let mut handles = ~[]; - for nthreads.times { + for nscheds.times { // Every scheduler is driven by an I/O event loop. let loop_ = ~UvEventLoop::new(); let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone()); @@ -244,6 +264,21 @@ pub fn run(main: ~fn()) -> int { handles.push(handle); } + // If we need a main-thread task then create a main thread scheduler + // that will reject any task that isn't pinned to it + let mut main_sched = if use_main_sched { + let main_loop = ~UvEventLoop::new(); + let mut main_sched = ~Scheduler::new_special(main_loop, + work_queue.clone(), + sleepers.clone(), + false); + let main_handle = main_sched.make_handle(); + handles.push(main_handle); + Some(main_sched) + } else { + None + }; + // Create a shared cell for transmitting the process exit // code from the main task to this function. let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0)); @@ -273,12 +308,22 @@ pub fn run(main: ~fn()) -> int { } }; - // Create and enqueue the main task. - let main_cell = Cell::new(main); - let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, - main_cell.take()); - main_task.death.on_exit = Some(on_exit); - scheds[0].enqueue_task(main_task); + // Build the main task and queue it up + match main_sched { + None => { + // The default case where we don't need a scheduler on the main thread. + // Just put an unpinned task onto one of the default schedulers. + let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, main); + main_task.death.on_exit = Some(on_exit); + scheds[0].enqueue_task(main_task); + } + Some(ref mut main_sched) => { + let home = Sched(main_sched.make_handle()); + let mut main_task = ~Task::new_root_homed(&mut scheds[0].stack_pool, home, main); + main_task.death.on_exit = Some(on_exit); + main_sched.enqueue_task(main_task); + } + }; // Run each scheduler in a thread. let mut threads = ~[]; @@ -293,6 +338,12 @@ pub fn run(main: ~fn()) -> int { threads.push(thread); } + // Run the main-thread scheduler + match main_sched { + Some(sched) => { let _ = sched.run(); }, + None => () + } + // Wait for schedulers { let _threads = threads; } |
