Skip to content

Commit e91040c

Browse files
committed
Make foreign calls work outside of tasks. #4451
1 parent a8c8bfc commit e91040c

File tree

3 files changed

+56
-19
lines changed

3 files changed

+56
-19
lines changed

mk/tests.mk

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -746,9 +746,6 @@ $(3)/test/$$(FT_DRIVER)-$(2).out: \
746746
--logfile tmp/$$(FT_DRIVER)-$(2).log
747747

748748
check-fast-T-$(2)-H-$(3): \
749-
check-stage2-T-$(2)-H-$(3)-rustc \
750-
check-stage2-T-$(2)-H-$(3)-core \
751-
check-stage2-T-$(2)-H-$(3)-std \
752749
$(3)/test/$$(FT_DRIVER)-$(2).out
753750

754751
endef

src/rt/rust_upcall.cpp

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ call_upcall_on_c_stack(rust_task *task, void *args, void *fn_ptr) {
4545
task->call_on_c_stack(args, fn_ptr);
4646
}
4747

48+
typedef void (*CDECL stack_switch_shim)(void*);
49+
4850
/**********************************************************************
4951
* Switches to the C-stack and invokes |fn_ptr|, passing |args| as argument.
5052
* 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) {
5456
*/
5557
extern "C" CDECL void
5658
upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
57-
rust_task *task = rust_get_current_task();
58-
59-
try {
60-
task->call_on_c_stack(args, fn_ptr);
61-
} catch (...) {
62-
// Logging here is not reliable
63-
assert(false && "Foreign code threw an exception");
59+
rust_task *task = rust_try_get_current_task();
60+
61+
if (task) {
62+
// We're running in task context, do a stack switch
63+
try {
64+
task->call_on_c_stack(args, fn_ptr);
65+
} catch (...) {
66+
// Logging here is not reliable
67+
assert(false && "Foreign code threw an exception");
68+
}
69+
} else {
70+
// There's no task. Call the function and hope for the best
71+
stack_switch_shim f = (stack_switch_shim)fn_ptr;
72+
f(args);
6473
}
6574
}
6675

@@ -70,15 +79,22 @@ upcall_call_shim_on_c_stack(void *args, void *fn_ptr) {
7079
*/
7180
extern "C" CDECL void
7281
upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) {
73-
rust_task *task = rust_get_current_task();
74-
75-
try {
76-
task->call_on_rust_stack(args, fn_ptr);
77-
} catch (...) {
78-
// We can't count on being able to unwind through arbitrary
79-
// code. Our best option is to just fail hard.
80-
// Logging here is not reliable
81-
assert(false && "Rust task failed after reentering the Rust stack");
82+
rust_task *task = rust_try_get_current_task();
83+
84+
if (task) {
85+
try {
86+
task->call_on_rust_stack(args, fn_ptr);
87+
} catch (...) {
88+
// We can't count on being able to unwind through arbitrary
89+
// code. Our best option is to just fail hard.
90+
// Logging here is not reliable
91+
assert(false
92+
&& "Rust task failed after reentering the Rust stack");
93+
}
94+
} else {
95+
// There's no task. Call the function and hope for the best
96+
stack_switch_shim f = (stack_switch_shim)fn_ptr;
97+
f(args);
8298
}
8399
}
84100

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use core::private::run_in_bare_thread;
2+
3+
extern {
4+
pub fn rust_dbg_call(cb: *u8,
5+
data: libc::uintptr_t) -> libc::uintptr_t;
6+
}
7+
8+
pub fn main() {
9+
unsafe {
10+
do run_in_bare_thread() {
11+
unsafe {
12+
let i = &100;
13+
rust_dbg_call(callback, cast::transmute(i));
14+
}
15+
}
16+
}
17+
}
18+
19+
extern fn callback(data: libc::uintptr_t) {
20+
unsafe {
21+
let data: *int = cast::transmute(data);
22+
assert *data == 100;
23+
}
24+
}

0 commit comments

Comments
 (0)