about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/tests.mk3
-rw-r--r--src/rt/rust_upcall.cpp48
-rw-r--r--src/test/run-pass/foreign-call-no-runtime.rs24
3 files changed, 56 insertions, 19 deletions
diff --git a/mk/tests.mk b/mk/tests.mk
index e9b407b8d79..db72a227705 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -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
diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp
index 0e6df8e14a4..ea396146755 100644
--- a/src/rt/rust_upcall.cpp
+++ b/src/rt/rust_upcall.cpp
@@ -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();
-
-    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);
     }
 }
 
@@ -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);
     }
 }
 
diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs
new file mode 100644
index 00000000000..865aa775362
--- /dev/null
+++ b/src/test/run-pass/foreign-call-no-runtime.rs
@@ -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;
+    }
+}
\ No newline at end of file