@@ -185,41 +185,33 @@ pub mod args;
185
185
// Support for dynamic borrowck
186
186
pub mod borrowck;
187
187
188
- /// Set up a default runtime configuration, given compiler-supplied arguments.
189
- ///
190
- /// This is invoked by the `start` _language item_ (unstable::lang) to
191
- /// run a Rust executable.
192
- ///
193
- /// # Arguments
194
- ///
195
- /// * `argc` & `argv` - The argument vector. On Unix this information is used
196
- /// by os::args.
197
- ///
198
- /// # Return value
199
- ///
200
- /// The return value is used as the process return code. 0 on success, 101 on error.
201
- pub fn start ( argc : int , argv : * * u8 , main : proc ( ) ) -> int {
202
-
203
- init ( argc, argv) ;
204
- let exit_code = run ( main) ;
205
- // unsafe is ok b/c we're sure that the runtime is gone
206
- unsafe { cleanup ( ) ; }
188
+ /// The default error code of the rust runtime if the main task fails instead
189
+ /// of exiting cleanly.
190
+ pub static DEFAULT_ERROR_CODE : int = 101 ;
207
191
208
- return exit_code;
209
- }
210
-
211
- /// Like `start` but creates an additional scheduler on the current thread,
212
- /// which in most cases will be the 'main' thread, and pins the main task to it.
192
+ /// The interface to the current runtime.
213
193
///
214
- /// This is appropriate for running code that must execute on the main thread,
215
- /// such as the platform event loop and GUI.
216
- pub fn start_on_main_thread ( argc : int , argv : * * u8 , main : proc ( ) ) -> int {
217
- init ( argc, argv) ;
218
- let exit_code = run_on_main_thread ( main) ;
219
- // unsafe is ok b/c we're sure that the runtime is gone
220
- unsafe { cleanup ( ) ; }
221
-
222
- return exit_code;
194
+ /// This trait is used as the abstraction between 1:1 and M:N scheduling. The
195
+ /// two independent crates, libnative and libgreen, both have objects which
196
+ /// implement this trait. The goal of this trait is to encompass all the
197
+ /// fundamental differences in functionality between the 1:1 and M:N runtime
198
+ /// modes.
199
+ pub trait Runtime {
200
+ // Necessary scheduling functions, used for channels and blocking I/O
201
+ // (sometimes).
202
+ fn yield_now ( ~self , cur_task : ~Task ) ;
203
+ fn maybe_yield ( ~self , cur_task : ~Task ) ;
204
+ fn deschedule ( ~self , times : uint , cur_task : ~Task ,
205
+ f: |BlockedTask | -> Result < ( ) , BlockedTask > ) ;
206
+ fn reawaken ( ~self , to_wake : ~Task , can_resched : bool ) ;
207
+
208
+ // Miscellaneous calls which are very different depending on what context
209
+ // you're in.
210
+ fn spawn_sibling ( ~self , cur_task : ~Task , opts : TaskOpts , f : proc ( ) ) ;
211
+ fn local_io < ' a > ( & ' a mut self ) -> Option < rtio:: LocalIo < ' a > > ;
212
+
213
+ // XXX: This is a serious code smell and this should not exist at all.
214
+ fn wrap ( ~self ) -> ~Any ;
223
215
}
224
216
225
217
/// One-time runtime initialization.
@@ -250,239 +242,3 @@ pub unsafe fn cleanup() {
250
242
args:: cleanup ( ) ;
251
243
local_ptr:: cleanup ( ) ;
252
244
}
253
-
254
- /// Execute the main function in a scheduler.
255
- ///
256
- /// Configures the runtime according to the environment, by default
257
- /// using a task scheduler with the same number of threads as cores.
258
- /// Returns a process exit code.
259
- pub fn run ( main : proc ( ) ) -> int {
260
- run_ ( main, false )
261
- }
262
-
263
- pub fn run_on_main_thread ( main : proc ( ) ) -> int {
264
- run_ ( main, true )
265
- }
266
-
267
- fn run_ ( main : proc ( ) , use_main_sched : bool ) -> int {
268
- static DEFAULT_ERROR_CODE : int = 101 ;
269
-
270
- let nscheds = util:: default_sched_threads ( ) ;
271
-
272
- let mut main = Some ( main) ;
273
-
274
- // The shared list of sleeping schedulers.
275
- let sleepers = SleeperList :: new ( ) ;
276
-
277
- // Create a work queue for each scheduler, ntimes. Create an extra
278
- // for the main thread if that flag is set. We won't steal from it.
279
- let mut pool = deque:: BufferPool :: new ( ) ;
280
- let arr = vec:: from_fn ( nscheds, |_| pool. deque ( ) ) ;
281
- let ( workers, stealers) = vec:: unzip ( arr. move_iter ( ) ) ;
282
-
283
- // The schedulers.
284
- let mut scheds = ~[ ] ;
285
- // Handles to the schedulers. When the main task ends these will be
286
- // sent the Shutdown message to terminate the schedulers.
287
- let mut handles = ~[ ] ;
288
-
289
- for worker in workers. move_iter ( ) {
290
- rtdebug ! ( "inserting a regular scheduler" ) ;
291
-
292
- // Every scheduler is driven by an I/O event loop.
293
- let loop_ = new_event_loop ( ) ;
294
- let mut sched = ~Scheduler :: new ( loop_,
295
- worker,
296
- stealers. clone ( ) ,
297
- sleepers. clone ( ) ) ;
298
- let handle = sched. make_handle ( ) ;
299
-
300
- scheds. push ( sched) ;
301
- handles. push ( handle) ;
302
- }
303
-
304
- // If we need a main-thread task then create a main thread scheduler
305
- // that will reject any task that isn't pinned to it
306
- let main_sched = if use_main_sched {
307
-
308
- // Create a friend handle.
309
- let mut friend_sched = scheds. pop ( ) ;
310
- let friend_handle = friend_sched. make_handle ( ) ;
311
- scheds. push ( friend_sched) ;
312
-
313
- // This scheduler needs a queue that isn't part of the stealee
314
- // set.
315
- let ( worker, _) = pool. deque ( ) ;
316
-
317
- let main_loop = new_event_loop ( ) ;
318
- let mut main_sched = ~Scheduler :: new_special ( main_loop,
319
- worker,
320
- stealers. clone ( ) ,
321
- sleepers. clone ( ) ,
322
- false ,
323
- Some ( friend_handle) ) ;
324
- let mut main_handle = main_sched. make_handle ( ) ;
325
- // Allow the scheduler to exit when the main task exits.
326
- // Note: sending the shutdown message also prevents the scheduler
327
- // from pushing itself to the sleeper list, which is used for
328
- // waking up schedulers for work stealing; since this is a
329
- // non-work-stealing scheduler it should not be adding itself
330
- // to the list.
331
- main_handle. send ( Shutdown ) ;
332
- Some ( main_sched)
333
- } else {
334
- None
335
- } ;
336
-
337
- // Create a shared cell for transmitting the process exit
338
- // code from the main task to this function.
339
- let exit_code = UnsafeArc :: new ( AtomicInt :: new ( 0 ) ) ;
340
- let exit_code_clone = exit_code. clone ( ) ;
341
-
342
- // Used to sanity check that the runtime only exits once
343
- let exited_already = UnsafeArc :: new ( AtomicBool :: new ( false ) ) ;
344
-
345
- // When the main task exits, after all the tasks in the main
346
- // task tree, shut down the schedulers and set the exit code.
347
- let handles = handles;
348
- let on_exit: proc ( TaskResult ) = proc ( exit_success) {
349
- unsafe {
350
- assert ! ( !( * exited_already. get( ) ) . swap( true , SeqCst ) ,
351
- "the runtime already exited" ) ;
352
- }
353
-
354
- let mut handles = handles;
355
- for handle in handles. mut_iter ( ) {
356
- handle. send ( Shutdown ) ;
357
- }
358
-
359
- unsafe {
360
- let exit_code = if exit_success. is_ok ( ) {
361
- use rt:: util;
362
-
363
- // If we're exiting successfully, then return the global
364
- // exit status, which can be set programmatically.
365
- util:: get_exit_status ( )
366
- } else {
367
- DEFAULT_ERROR_CODE
368
- } ;
369
- ( * exit_code_clone. get ( ) ) . store ( exit_code, SeqCst ) ;
370
- }
371
- } ;
372
-
373
- let mut threads = ~[ ] ;
374
- let mut on_exit = Some ( on_exit) ;
375
-
376
- if !use_main_sched {
377
-
378
- // In the case where we do not use a main_thread scheduler we
379
- // run the main task in one of our threads.
380
-
381
- let mut main_task = ~Task :: new_root ( & mut scheds[ 0 ] . stack_pool ,
382
- None ,
383
- :: util:: replace ( & mut main,
384
- None ) . unwrap ( ) ) ;
385
- main_task. name = Some ( SendStrStatic ( "<main>" ) ) ;
386
- main_task. death . on_exit = :: util:: replace ( & mut on_exit, None ) ;
387
-
388
- let sched = scheds. pop ( ) ;
389
- let main_task = main_task;
390
- let thread = do Thread :: start {
391
- sched. bootstrap ( main_task) ;
392
- } ;
393
- threads. push ( thread) ;
394
- }
395
-
396
- // Run each remaining scheduler in a thread.
397
- for sched in scheds. move_rev_iter ( ) {
398
- rtdebug ! ( "creating regular schedulers" ) ;
399
- let thread = do Thread :: start {
400
- let mut sched = sched;
401
- let bootstrap_task = ~do Task :: new_root ( & mut sched. stack_pool , None ) || {
402
- rtdebug ! ( "boostraping a non-primary scheduler" ) ;
403
- } ;
404
- sched. bootstrap ( bootstrap_task) ;
405
- } ;
406
- threads. push ( thread) ;
407
- }
408
-
409
- // If we do have a main thread scheduler, run it now.
410
-
411
- if use_main_sched {
412
- rtdebug ! ( "about to create the main scheduler task" ) ;
413
-
414
- let mut main_sched = main_sched. unwrap ( ) ;
415
-
416
- let home = Sched ( main_sched. make_handle ( ) ) ;
417
- let mut main_task = ~Task :: new_root_homed ( & mut main_sched. stack_pool ,
418
- None ,
419
- home,
420
- :: util:: replace ( & mut main,
421
- None ) .
422
- unwrap ( ) ) ;
423
- main_task. name = Some ( SendStrStatic ( "<main>" ) ) ;
424
- main_task. death . on_exit = :: util:: replace ( & mut on_exit, None ) ;
425
- rtdebug ! ( "bootstrapping main_task" ) ;
426
-
427
- main_sched. bootstrap ( main_task) ;
428
- }
429
-
430
- rtdebug ! ( "waiting for threads" ) ;
431
-
432
- // Wait for schedulers
433
- for thread in threads. move_iter ( ) {
434
- thread. join ( ) ;
435
- }
436
-
437
- // Return the exit code
438
- unsafe {
439
- ( * exit_code. get ( ) ) . load ( SeqCst )
440
- }
441
- }
442
-
443
- pub fn in_sched_context ( ) -> bool {
444
- unsafe {
445
- let task_ptr: Option < * mut Task > = Local :: try_unsafe_borrow ( ) ;
446
- match task_ptr {
447
- Some ( task) => {
448
- match ( * task) . task_type {
449
- SchedTask => true ,
450
- _ => false
451
- }
452
- }
453
- None => false
454
- }
455
- }
456
- }
457
-
458
- pub fn in_green_task_context ( ) -> bool {
459
- unsafe {
460
- let task: Option < * mut Task > = Local :: try_unsafe_borrow ( ) ;
461
- match task {
462
- Some ( task) => {
463
- match ( * task) . task_type {
464
- GreenTask ( _) => true ,
465
- _ => false
466
- }
467
- }
468
- None => false
469
- }
470
- }
471
- }
472
-
473
- pub fn new_event_loop ( ) -> ~rtio:: EventLoop {
474
- match crate_map:: get_crate_map ( ) {
475
- None => { }
476
- Some ( map) => {
477
- match map. event_loop_factory {
478
- None => { }
479
- Some ( factory) => return factory ( )
480
- }
481
- }
482
- }
483
-
484
- // If the crate map didn't specify a factory to create an event loop, then
485
- // instead just use a basic event loop missing all I/O services to at least
486
- // get the scheduler running.
487
- return basic:: event_loop ( ) ;
488
- }
0 commit comments