Make foreign calls work outside of tasks. #4451

This commit is contained in:
Brian Anderson 2013-01-11 18:32:46 -08:00
parent a8c8bfc7b5
commit e91040c704
3 changed files with 54 additions and 17 deletions

View File

@ -746,9 +746,6 @@ $(3)/test/$$(FT_DRIVER)-$(2).out: \
--logfile tmp/$$(FT_DRIVER)-$(2).log
check-fast-T-$(2)-H-$(3): \
check-stage2-T-$(2)-H-$(3)-rustc \
check-stage2-T-$(2)-H-$(3)-core \
check-stage2-T-$(2)-H-$(3)-std \
$(3)/test/$$(FT_DRIVER)-$(2).out
endef

View File

@ -45,6 +45,8 @@ call_upcall_on_c_stack(rust_task *task, void *args, void *fn_ptr) {
task->call_on_c_stack(args, fn_ptr);
}
typedef void (*CDECL stack_switch_shim)(void*);
/**********************************************************************
* Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument.
* This is used by the C compiler to call foreign functions and by other
@ -54,13 +56,20 @@ call_upcall_on_c_stack(rust_task *task, void *args, void *fn_ptr) {
*/
extern "C" CDECL void
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
rust_task *task = rust_get_current_task();
rust_task *task = rust_try_get_current_task();
try {
task->call_on_c_stack(args, fn_ptr);
} catch (...) {
// Logging here is not reliable
assert(false && "Foreign code threw an exception");
if (task) {
// We're running in task context, do a stack switch
try {
task->call_on_c_stack(args, fn_ptr);
} catch (...) {
// Logging here is not reliable
assert(false && "Foreign code threw an exception");
}
} else {
// There's no task. Call the function and hope for the best
stack_switch_shim f = (stack_switch_shim)fn_ptr;
f(args);
}
}
@ -70,15 +79,22 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
*/
extern "C" CDECL void
upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
rust_task *task = rust_get_current_task();
rust_task *task = rust_try_get_current_task();
try {
task->call_on_rust_stack(args, fn_ptr);
} catch (...) {
// We can't count on being able to unwind through arbitrary
// code. Our best option is to just fail hard.
// Logging here is not reliable
assert(false && "Rust task failed after reentering the Rust stack");
if (task) {
try {
task->call_on_rust_stack(args, fn_ptr);
} catch (...) {
// We can't count on being able to unwind through arbitrary
// code. Our best option is to just fail hard.
// Logging here is not reliable
assert(false
&& "Rust task failed after reentering the Rust stack");
}
} else {
// There's no task. Call the function and hope for the best
stack_switch_shim f = (stack_switch_shim)fn_ptr;
f(args);
}
}

View File

@ -0,0 +1,24 @@
use core::private::run_in_bare_thread;
extern {
pub fn rust_dbg_call(cb: *u8,
data: libc::uintptr_t) -> libc::uintptr_t;
}
pub fn main() {
unsafe {
do run_in_bare_thread() {
unsafe {
let i = &100;
rust_dbg_call(callback, cast::transmute(i));
}
}
}
}
extern fn callback(data: libc::uintptr_t) {
unsafe {
let data: *int = cast::transmute(data);
assert *data == 100;
}
}