Skip to content

Commit 82b29ae

Browse files
committed
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.
2 parents b027c5f + 34a27db commit 82b29ae

File tree

2 files changed

+82
-10
lines changed

2 files changed

+82
-10
lines changed

src/libstd/rt/mod.rs

+61-10
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ use clone::Clone;
6565
use container::Container;
6666
use iter::Times;
6767
use iterator::IteratorUtil;
68-
use option::Some;
68+
use option::{Some, None};
6969
use ptr::RawPtr;
7070
use rt::sched::{Scheduler, Shutdown};
7171
use rt::sleeper_list::SleeperList;
72-
use rt::task::Task;
72+
use rt::task::{Task, Sched};
7373
use rt::thread::Thread;
7474
use rt::work_queue::WorkQueue;
7575
use rt::uv::uvio::UvEventLoop;
@@ -187,6 +187,19 @@ pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
187187
return exit_code;
188188
}
189189

190+
/// Like `start` but creates an additional scheduler on the current thread,
191+
/// which in most cases will be the 'main' thread, and pins the main task to it.
192+
///
193+
/// This is appropriate for running code that must execute on the main thread,
194+
/// such as the platform event loop and GUI.
195+
pub fn start_on_main_thread(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
196+
init(argc, argv, crate_map);
197+
let exit_code = run_on_main_thread(main);
198+
cleanup();
199+
200+
return exit_code;
201+
}
202+
190203
/// One-time runtime initialization.
191204
///
192205
/// Initializes global state, including frobbing
@@ -217,10 +230,17 @@ pub fn cleanup() {
217230
/// using a task scheduler with the same number of threads as cores.
218231
/// Returns a process exit code.
219232
pub fn run(main: ~fn()) -> int {
233+
run_(main, false)
234+
}
235+
236+
pub fn run_on_main_thread(main: ~fn()) -> int {
237+
run_(main, true)
238+
}
220239

240+
fn run_(main: ~fn(), use_main_sched: bool) -> int {
221241
static DEFAULT_ERROR_CODE: int = 101;
222242

223-
let nthreads = util::default_sched_threads();
243+
let nscheds = util::default_sched_threads();
224244

225245
// The shared list of sleeping schedulers. Schedulers wake each other
226246
// occassionally to do new work.
@@ -234,7 +254,7 @@ pub fn run(main: ~fn()) -> int {
234254
// sent the Shutdown message to terminate the schedulers.
235255
let mut handles = ~[];
236256

237-
for nthreads.times {
257+
for nscheds.times {
238258
// Every scheduler is driven by an I/O event loop.
239259
let loop_ = ~UvEventLoop::new();
240260
let mut sched = ~Scheduler::new(loop_, work_queue.clone(), sleepers.clone());
@@ -244,6 +264,21 @@ pub fn run(main: ~fn()) -> int {
244264
handles.push(handle);
245265
}
246266

267+
// If we need a main-thread task then create a main thread scheduler
268+
// that will reject any task that isn't pinned to it
269+
let mut main_sched = if use_main_sched {
270+
let main_loop = ~UvEventLoop::new();
271+
let mut main_sched = ~Scheduler::new_special(main_loop,
272+
work_queue.clone(),
273+
sleepers.clone(),
274+
false);
275+
let main_handle = main_sched.make_handle();
276+
handles.push(main_handle);
277+
Some(main_sched)
278+
} else {
279+
None
280+
};
281+
247282
// Create a shared cell for transmitting the process exit
248283
// code from the main task to this function.
249284
let exit_code = UnsafeAtomicRcBox::new(AtomicInt::new(0));
@@ -273,12 +308,22 @@ pub fn run(main: ~fn()) -> int {
273308
}
274309
};
275310

276-
// Create and enqueue the main task.
277-
let main_cell = Cell::new(main);
278-
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool,
279-
main_cell.take());
280-
main_task.death.on_exit = Some(on_exit);
281-
scheds[0].enqueue_task(main_task);
311+
// Build the main task and queue it up
312+
match main_sched {
313+
None => {
314+
// The default case where we don't need a scheduler on the main thread.
315+
// Just put an unpinned task onto one of the default schedulers.
316+
let mut main_task = ~Task::new_root(&mut scheds[0].stack_pool, main);
317+
main_task.death.on_exit = Some(on_exit);
318+
scheds[0].enqueue_task(main_task);
319+
}
320+
Some(ref mut main_sched) => {
321+
let home = Sched(main_sched.make_handle());
322+
let mut main_task = ~Task::new_root_homed(&mut scheds[0].stack_pool, home, main);
323+
main_task.death.on_exit = Some(on_exit);
324+
main_sched.enqueue_task(main_task);
325+
}
326+
};
282327

283328
// Run each scheduler in a thread.
284329
let mut threads = ~[];
@@ -293,6 +338,12 @@ pub fn run(main: ~fn()) -> int {
293338
threads.push(thread);
294339
}
295340

341+
// Run the main-thread scheduler
342+
match main_sched {
343+
Some(sched) => { let _ = sched.run(); },
344+
None => ()
345+
}
346+
296347
// Wait for schedulers
297348
{ let _threads = threads; }
298349

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
// xfail-fast
12+
13+
#[start]
14+
fn start(argc: int, argv: **u8, crate_map: *u8) -> int {
15+
do std::rt::start_on_main_thread(argc, argv, crate_map) {
16+
info!("running on main thread");
17+
do spawn {
18+
info!("running on another thread");
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)