@@ -65,11 +65,11 @@ use clone::Clone;
65
65
use container:: Container ;
66
66
use iter:: Times ;
67
67
use iterator:: IteratorUtil ;
68
- use option:: Some ;
68
+ use option:: { Some , None } ;
69
69
use ptr:: RawPtr ;
70
70
use rt:: sched:: { Scheduler , Shutdown } ;
71
71
use rt:: sleeper_list:: SleeperList ;
72
- use rt:: task:: Task ;
72
+ use rt:: task:: { Task , Sched } ;
73
73
use rt:: thread:: Thread ;
74
74
use rt:: work_queue:: WorkQueue ;
75
75
use rt:: uv:: uvio:: UvEventLoop ;
@@ -187,6 +187,19 @@ pub fn start(argc: int, argv: **u8, crate_map: *u8, main: ~fn()) -> int {
187
187
return exit_code;
188
188
}
189
189
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
+
190
203
/// One-time runtime initialization.
191
204
///
192
205
/// Initializes global state, including frobbing
@@ -217,10 +230,17 @@ pub fn cleanup() {
217
230
/// using a task scheduler with the same number of threads as cores.
218
231
/// Returns a process exit code.
219
232
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
+ }
220
239
240
+ fn run_ ( main : ~fn ( ) , use_main_sched : bool ) -> int {
221
241
static DEFAULT_ERROR_CODE : int = 101 ;
222
242
223
- let nthreads = util:: default_sched_threads ( ) ;
243
+ let nscheds = util:: default_sched_threads ( ) ;
224
244
225
245
// The shared list of sleeping schedulers. Schedulers wake each other
226
246
// occassionally to do new work.
@@ -234,7 +254,7 @@ pub fn run(main: ~fn()) -> int {
234
254
// sent the Shutdown message to terminate the schedulers.
235
255
let mut handles = ~[ ] ;
236
256
237
- for nthreads . times {
257
+ for nscheds . times {
238
258
// Every scheduler is driven by an I/O event loop.
239
259
let loop_ = ~UvEventLoop : : new( ) ;
240
260
let mut sched = ~Scheduler :: new( loop_, work_queue. clone( ) , sleepers. clone( ) ) ;
@@ -244,6 +264,21 @@ pub fn run(main: ~fn()) -> int {
244
264
handles. push( handle) ;
245
265
}
246
266
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
+
247
282
// Create a shared cell for transmitting the process exit
248
283
// code from the main task to this function.
249
284
let exit_code = UnsafeAtomicRcBox :: new( AtomicInt :: new( 0 ) ) ;
@@ -273,12 +308,22 @@ pub fn run(main: ~fn()) -> int {
273
308
}
274
309
} ;
275
310
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
+ } ;
282
327
283
328
// Run each scheduler in a thread.
284
329
let mut threads = ~[ ] ;
@@ -293,6 +338,12 @@ pub fn run(main: ~fn()) -> int {
293
338
threads. push( thread) ;
294
339
}
295
340
341
+ // Run the main-thread scheduler
342
+ match main_sched {
343
+ Some ( sched) => { let _ = sched. run( ) ; } ,
344
+ None => ( )
345
+ }
346
+
296
347
// Wait for schedulers
297
348
{ let _threads = threads; }
298
349
0 commit comments