Skip to content

Commit

Permalink
Make foreign calls work outside of tasks. rust-lang#4451
Browse files Browse the repository at this point in the history
  • Loading branch information
brson committed Feb 6, 2013
1 parent a8c8bfc commit e91040c
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 19 deletions.
3 changes: 0 additions & 3 deletions mk/tests.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 32 additions & 16 deletions src/rt/rust_upcall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();

try {
task->call_on_c_stack(args, fn_ptr);
} catch (...) {
// Logging here is not reliable
assert(false && "Foreign code threw an exception");
rust_task *task = rust_try_get_current_task();

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);
}
}

Expand All @@ -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();

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");
rust_task *task = rust_try_get_current_task();

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);
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/test/run-pass/foreign-call-no-runtime.rs
Original file line number Diff line number Diff line change
@@ -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;
}
}

0 comments on commit e91040c

Please sign in to comment.