add indirection on thread start to avoid ObjC exception issues

In Mac OS X 10.11, something about the use of exceptions triggers
a libunwind stack traversal, and that traversal runs into trouble
with Racket's stack mangling for threads. Inserting generated code
in the stack frame sequence causes libunwind to give up and avoids
a crash (e.g., with `-j -l drracket` on startup).
This commit is contained in:
Matthew Flatt 2015-10-06 09:31:47 -06:00
parent f86c5dfe0a
commit 4d3852ae69
5 changed files with 54 additions and 2 deletions

View File

@ -348,6 +348,7 @@ struct scheme_jit_common_record {
void *list_ref_code, *list_tail_code;
void *finish_tail_call_code, *finish_tail_call_fixup_code;
void *module_run_start_code, *module_exprun_start_code, *module_start_start_code;
void *thread_start_child_code;
void *box_flonum_from_stack_code, *box_flonum_from_reg_code;
void *fl1_fail_code[JIT_NUM_FL_KINDS], *fl2rr_fail_code[2][JIT_NUM_FL_KINDS];
void *fl2fr_fail_code[2][JIT_NUM_FL_KINDS], *fl2rf_fail_code[2][JIT_NUM_FL_KINDS];

View File

@ -3639,6 +3639,33 @@ static int more_common0(mz_jit_state *jitter, void *_data)
scheme_jit_register_sub_func(jitter, sjc.module_start_start_code, scheme_eof);
}
/* *** thread_start_child_code *** */
/* A simple indirection to generate code that libunwind can't follow,
particularly as used by exceptions in the Objective-C runtime */
{
int in;
sjc.thread_start_child_code = jit_get_ip();
jit_prolog(2);
in = jit_arg_p();
jit_getarg_p(JIT_R0, in); /* child */
in = jit_arg_p();
jit_getarg_p(JIT_R1, in); /* child_thunk */
CHECK_LIMIT();
mz_push_locals();
jit_prepare(2);
jit_pusharg_p(JIT_R1);
jit_pusharg_p(JIT_R0);
(void)mz_finish(scheme_do_thread_start_child);
CHECK_LIMIT();
mz_pop_locals();
jit_ret();
CHECK_LIMIT();
scheme_jit_register_sub_func(jitter, sjc.thread_start_child_code, scheme_eof);
}
return 1;
}

View File

@ -689,6 +689,7 @@ void scheme_jit_now(Scheme_Object *f)
typedef void *(*Module_Run_Proc)(Scheme_Env *menv, Scheme_Env *env, Scheme_Object **name);
typedef void *(*Module_Exprun_Proc)(Scheme_Env *menv, int set_ns, Scheme_Object **name);
typedef void *(*Module_Start_Proc)(struct Start_Module_Args *a, Scheme_Object **name);
typedef void (*Thread_Start_Child_Proc)(Scheme_Thread *child, Scheme_Object *child_thunk);
void *scheme_module_run_start(Scheme_Env *menv, Scheme_Env *env, Scheme_Object *name)
{
@ -717,8 +718,23 @@ void *scheme_module_start_start(struct Start_Module_Args *a, Scheme_Object *name
return scheme_module_start_finish(a);
}
void scheme_thread_start_child(Scheme_Thread *child, Scheme_Object *child_thunk)
{
Thread_Start_Child_Proc proc = (Thread_Start_Child_Proc)sjc.thread_start_child_code;
if (proc)
proc(child, child_thunk);
else
scheme_do_thread_start_child(child, child_thunk);
}
#else
void* scheme_jit_find_code_end(void *p) { return NULL; }
void scheme_thread_start_child(Scheme_Thread *child, Scheme_Object *child_thunk)
{
return scheme_do_thread_start_child(child, child_thunk);
}
#endif

View File

@ -667,6 +667,9 @@ void scheme_suspend_remembered_threads(void);
void scheme_resume_remembered_threads(void);
#endif
void scheme_thread_start_child(Scheme_Thread *child, Scheme_Object *child_thunk);
void scheme_do_thread_start_child(Scheme_Thread *child, Scheme_Object *child_thunk);
int scheme_wait_until_suspend_ok(void);
#ifdef MZ_USE_MZRT

View File

@ -1,6 +1,6 @@
/*
Racket
Copyright (c) 2004-2015 PLT Design Inc.
Copyright (c) 2004-2014 PLT Design Inc.
Copyright (c) 1995-2001 Matthew Flatt
This library is free software; you can redistribute it and/or
@ -3167,6 +3167,11 @@ static void start_child(Scheme_Thread * volatile child,
}
}
void scheme_do_thread_start_child(Scheme_Thread *child, Scheme_Object *child_eval)
{
return start_child(child, child_eval);
}
static Scheme_Object *make_subprocess(Scheme_Object *child_thunk,
void *child_start,
Scheme_Config *config,
@ -3223,7 +3228,7 @@ static Scheme_Object *make_subprocess(Scheme_Object *child_thunk,
child->stack_start = child_start;
/* Sets the child's jmpbuf for swapping in later: */
start_child(child, child_thunk);
scheme_thread_start_child(child, child_thunk);
if (scheme_notify_multithread && turn_on_multi) {
scheme_notify_multithread(1);