/** The exception handling personality function. It figures out what to do with each landing pad. Just a stack-switching wrapper around the C++ personality function. */ extern "C" _Unwind_Reason_Code upcall_rust_personality(int version, _Unwind_Action actions, uint64_t exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context) { s_rust_personality_args args = {(_Unwind_Reason_Code)0, version, actions, exception_class, ue_header, context}; rust_task *task = rust_try_get_current_task(); if (task == NULL) { // Assuming we're running with the new scheduler upcall_s_rust_personality(&args); return args.retval; } // The personality function is run on the stack of the // last function that threw or landed, which is going // to sometimes be the C stack. If we're on the Rust stack // then switch to the C stack. if (task->on_rust_stack()) { UPCALL_SWITCH_STACK(task, &args, upcall_s_rust_personality); } else { upcall_s_rust_personality(&args); } return args.retval; }
// Landing pads need to call this to insert the // correct limit into TLS. // NB: This must run on the Rust stack because it // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { rust_task *task = rust_try_get_current_task(); if (task != NULL) { task->reset_stack_limit(); } else { // We must be in a newsched task } }
extern "C" CDECL void upcall_fail(char const *expr, char const *file, size_t line) { rust_task *task = rust_try_get_current_task(); if (task == NULL) { // FIXME #5161: Need to think about what to do here printf("failure outside of a task"); abort(); } s_fail_args args = {task,expr,file,line}; UPCALL_SWITCH_STACK(task, &args, upcall_s_fail); }
/********************************************************************** * 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 * upcalls to switch to the C stack. The return value is passed through a * field in the args parameter. This upcall is specifically for switching * to the shim functions generated by rustc. */ extern "C" CDECL void upcall_call_shim_on_c_stack(void *args, void *fn_ptr) { 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); } }
/* * The opposite of above. Starts on a C stack and switches to the Rust * stack. This is the only upcall that runs from the C stack. */ extern "C" CDECL void upcall_call_shim_on_rust_stack(void *args, void *fn_ptr) { 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); } }
extern "C" rust_task * rust_try_get_task() { return rust_try_get_current_task(); }