Make foreign calls work outside of tasks. #4451
This commit is contained in:
parent
a8c8bfc7b5
commit
e91040c704
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue