From d7f5e437a28dd85b8a7523af9212a9a1100ea725 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 21 Apr 2013 19:03:52 -0700 Subject: core::rt: Add the local heap to newsched tasks Reusing the existing boxed_region implementation from the runtime --- src/rt/rust_builtin.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'src/rt/rust_builtin.cpp') diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a0db6f64f69..b8749b8f73d 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -851,6 +851,41 @@ rust_initialize_global_state() { } } +extern "C" CDECL memory_region* +rust_new_memory_region(uintptr_t synchronized, + uintptr_t detailed_leaks, + uintptr_t poison_on_free) { + return new memory_region((bool)synchronized, + (bool)detailed_leaks, + (bool)poison_on_free); +} + +extern "C" CDECL void +rust_delete_memory_region(memory_region *region) { + delete region; +} + +extern "C" CDECL boxed_region* +rust_new_boxed_region(memory_region *region, + uintptr_t poison_on_free) { + return new boxed_region(region, poison_on_free); +} + +extern "C" CDECL void +rust_delete_boxed_region(boxed_region *region) { + delete region; +} + +extern "C" CDECL rust_opaque_box* +rust_boxed_region_malloc(boxed_region *region, type_desc *td, size_t size) { + return region->malloc(td, size); +} + +extern "C" CDECL void +rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) { + region->free(box); +} + // // Local Variables: // mode: C++ -- cgit 1.4.1-3-g733a5 From 42c0f88232847e97e6cf3578ef197d1942bba44d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 17:15:31 -0700 Subject: core::rt: Add unwinding to newsched tasks --- src/libcore/rt/io/mod.rs | 1 + src/libcore/rt/local_services.rs | 78 +++++++++++++++++++++++++++++++++++++--- src/libcore/rt/sched/mod.rs | 7 +--- src/libcore/rt/test.rs | 41 +++++++++++++++++++++ src/libcore/sys.rs | 25 ++++++++++--- src/libcore/task/mod.rs | 18 ++++++++-- src/rt/rust_builtin.cpp | 22 ++++++++++++ src/rt/rust_upcall.cpp | 16 +++++++-- src/rt/rustrt.def.in | 2 ++ 9 files changed, 190 insertions(+), 20 deletions(-) (limited to 'src/rt/rust_builtin.cpp') diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index d9d6622277f..131743305bc 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -153,6 +153,7 @@ pub mod mem; pub mod stdio; /// Implementations for Option +#[cfg(not(stage0))] // Requires condition! fixes mod option; /// Basic stream compression. XXX: Belongs with other flate code diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index d29e57a17af..fc75a256428 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -19,7 +19,8 @@ //! (freestanding rust with local services?). use prelude::*; -use libc::c_void; +use libc::{c_void, uintptr_t}; +use cast::transmute; use super::sched::{Task, local_sched}; use super::local_heap::LocalHeap; @@ -35,7 +36,10 @@ pub struct LocalServices { pub struct GarbageCollector; pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); pub struct Logger; -pub struct Unwinder; + +pub struct Unwinder { + unwinding: bool, +} impl LocalServices { pub fn new() -> LocalServices { @@ -44,17 +48,28 @@ impl LocalServices { gc: GarbageCollector, storage: LocalStorage(ptr::null(), None), logger: Logger, - unwinder: Unwinder, + unwinder: Unwinder { unwinding: false }, destroyed: false } } + pub fn run(&mut self, f: &fn()) { + // This is just an assertion that `run` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + + self.unwinder.try(f); + self.destroy(); + } + /// Must be called manually before finalization to clean up /// thread-local resources. Some of the routines here expect /// LocalServices to be available recursively so this must be /// called unsafely, without removing LocalServices from /// thread-local-storage. - pub fn destroy(&mut self) { + fn destroy(&mut self) { // This is just an assertion that `destroy` was called unsafely // and this instance of LocalServices is still accessible. do borrow_local_services |sched| { @@ -72,6 +87,51 @@ impl Drop for LocalServices { fn finalize(&self) { assert!(self.destroyed) } } +// Just a sanity check to make sure we are catching a Rust-thrown exception +static UNWIND_TOKEN: uintptr_t = 839147; + +impl Unwinder { + pub fn try(&mut self, f: &fn()) { + use sys::Closure; + + unsafe { + let closure: Closure = transmute(f); + let code = transmute(closure.code); + let env = transmute(closure.env); + + let token = rust_try(try_fn, code, env); + assert!(token == 0 || token == UNWIND_TOKEN); + } + + extern fn try_fn(code: *c_void, env: *c_void) { + unsafe { + let closure: Closure = Closure { + code: transmute(code), + env: transmute(env), + }; + let closure: &fn() = transmute(closure); + closure(); + } + } + + extern { + #[rust_stack] + fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; + } + } + + pub fn begin_unwind(&mut self) -> ! { + self.unwinding = true; + unsafe { + rust_begin_unwind(UNWIND_TOKEN); + return transmute(()); + } + extern { + fn rust_begin_unwind(token: uintptr_t); + } + } +} + /// Borrow a pointer to the installed local services. /// Fails (likely aborting the process) if local services are not available. pub fn borrow_local_services(f: &fn(&mut LocalServices)) { @@ -125,4 +185,14 @@ mod test { } } } + + #[test] + fn unwind() { + do run_in_newsched_task() { + let result = spawn_try(||()); + assert!(result.is_ok()); + let result = spawn_try(|| fail!()); + assert!(result.is_err()); + } + } } \ No newline at end of file diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index b7d861b8946..65456c30fee 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -353,15 +353,10 @@ pub impl Task { unsafe { let sched = local_sched::unsafe_borrow(); sched.run_cleanup_job(); - } - - start(); - unsafe { - // Destroy the local heap, TLS, etc. let sched = local_sched::unsafe_borrow(); let task = sched.current_task.get_mut_ref(); - task.local_services.destroy(); + task.local_services.run(start); } let sched = local_sched::take(); diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index e394a873fea..f3d73c91bd6 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use result::{Result, Ok, Err}; use super::io::net::ip::{IpAddr, Ipv4}; /// Creates a new scheduler in a new thread and runs a task in it, @@ -47,6 +48,46 @@ pub fn spawn_immediately(f: ~fn()) { } } +/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed +pub fn spawn_try(f: ~fn()) -> Result<(), ()> { + use cell::Cell; + use super::sched::*; + use task; + use unstable::finally::Finally; + + // Our status variables will be filled in from the scheduler context + let mut failed = false; + let failed_ptr: *mut bool = &mut failed; + + // Switch to the scheduler + let f = Cell(Cell(f)); + let mut sched = local_sched::take(); + do sched.deschedule_running_task_and_then() |old_task| { + let old_task = Cell(old_task); + let f = f.take(); + let mut sched = local_sched::take(); + let new_task = ~do Task::new(&mut sched.stack_pool) { + do (|| { + (f.take())() + }).finally { + // Check for failure then resume the parent task + unsafe { *failed_ptr = task::failing(); } + let sched = local_sched::take(); + do sched.switch_running_tasks_and_then(old_task.take()) |new_task| { + let new_task = Cell(new_task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(new_task.take()); + } + } + } + }; + + sched.resume_task_immediately(new_task); + } + + if !failed { Ok(()) } else { Err(()) } +} + /// Get a port number, starting at 9600, for use in tests pub fn next_test_port() -> u16 { unsafe { diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 04f96f5eb22..c50bc03517f 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -134,12 +134,27 @@ pub fn log_str(t: &T) -> ~str { /** Initiate task failure */ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { + + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + + match context() { + OldTaskContext => { + do str::as_buf(msg) |msg_buf, _msg_len| { + do str::as_buf(file) |file_buf, _file_len| { + unsafe { + let msg_buf = cast::transmute(msg_buf); + let file_buf = cast::transmute(file_buf); + begin_unwind_(msg_buf, file_buf, line as libc::size_t) + } + } + } + } + _ => { + gc::cleanup_stack_for_failure(); unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) + let local_services = unsafe_borrow_local_services(); + local_services.unwinder.begin_unwind(); } } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index a243bfba85c..e1f4805a692 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -558,8 +558,22 @@ pub fn yield() { pub fn failing() -> bool { //! True if the running task has failed - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) + use rt::{context, OldTaskContext}; + use rt::local_services::borrow_local_services; + + match context() { + OldTaskContext => { + unsafe { + rt::rust_task_is_unwinding(rt::rust_get_task()) + } + } + _ => { + let mut unwinding = false; + do borrow_local_services |local| { + unwinding = local.unwinder.unwinding; + } + return unwinding; + } } } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index b8749b8f73d..b37644460aa 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -886,6 +886,28 @@ rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) { region->free(box); } +typedef void *(rust_try_fn)(void*, void*); + +extern "C" CDECL uintptr_t +rust_try(rust_try_fn f, void *fptr, void *env) { + try { + f(fptr, env); + } catch (uintptr_t token) { + assert(token != 0); + return token; + } + return 0; +} + +extern "C" CDECL void +rust_begin_unwind(uintptr_t token) { +#ifndef __WIN32__ + throw token; +#else + abort("failing on win32"); +#endif +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 9f39e1433fc..34236c36c14 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -272,7 +272,13 @@ upcall_rust_personality(int version, s_rust_personality_args args = {(_Unwind_Reason_Code)0, version, actions, exception_class, ue_header, context}; - rust_task *task = rust_get_current_task(); + rust_task *task = rust_try_get_current_task(); + + if (task == NULL) { + // Assuming we're running with the new scheduler + upcall_s_rust_personality(&args); + return args.retval; + } // The personality function is run on the stack of the // last function that threw or landed, which is going @@ -309,8 +315,12 @@ upcall_del_stack() { // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { - rust_task *task = rust_get_current_task(); - task->reset_stack_limit(); + rust_task *task = rust_try_get_current_task(); + if (task != NULL) { + task->reset_stack_limit(); + } else { + // We must be in a newsched task + } } // diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 9aa80156783..5e9a4b343ee 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -228,3 +228,5 @@ rust_new_boxed_region rust_delete_boxed_region rust_boxed_region_malloc rust_boxed_region_free +rust_try +rust_begin_unwind \ No newline at end of file -- cgit 1.4.1-3-g733a5 From abc49fdfae0b80acfa010fd6151ff8ffc229c03b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Apr 2013 21:33:03 -0700 Subject: rt: abort doesn't take an argument --- src/rt/rust_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rt/rust_builtin.cpp') diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 2097d8dd933..8b7b89680fc 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -909,7 +909,7 @@ rust_begin_unwind(uintptr_t token) { #ifndef __WIN32__ throw token; #else - abort("failing on win32"); + abort(); #endif } -- cgit 1.4.1-3-g733a5