mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-23 13:01:42 -08:00
threading: use safer method to disable interrupts when resizing stacks
Due to the use of mprotect() for fast interrupt dispatch it is
not possible to write in the thread local environment when
interrupts are disabled. We need to use sigprocmask to block
interrupts in this case.
This commit is contained in:
parent
8a68a5c225
commit
fc29c08d93
3 changed files with 34 additions and 6 deletions
|
|
@ -38,14 +38,13 @@ ecl_stack_set_size(cl_env_ptr env, cl_index tentative_new_size)
|
|||
old_stack = env->stack;
|
||||
new_stack = (cl_object *)ecl_alloc_atomic(new_size * sizeof(cl_object));
|
||||
|
||||
ecl_disable_interrupts_env(env);
|
||||
ECL_STACK_RESIZE_DISABLE_INTERRUPTS(env);
|
||||
memcpy(new_stack, old_stack, env->stack_size * sizeof(cl_object));
|
||||
env->stack_size = new_size;
|
||||
env->stack_limit_size = new_size - 2*safety_area;
|
||||
env->stack = new_stack;
|
||||
env->stack_top = env->stack + top;
|
||||
env->stack_limit = env->stack + (new_size - 2*safety_area);
|
||||
ecl_enable_interrupts_env(env);
|
||||
|
||||
/* A stack always has at least one element. This is assumed by cl__va_start
|
||||
* and friends, which take a sp=0 to have no arguments.
|
||||
|
|
@ -53,6 +52,8 @@ ecl_stack_set_size(cl_env_ptr env, cl_index tentative_new_size)
|
|||
if (top == 0) {
|
||||
*(env->stack_top++) = ecl_make_fixnum(0);
|
||||
}
|
||||
ECL_STACK_RESIZE_ENABLE_INTERRUPTS(env);
|
||||
|
||||
return env->stack_top;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -139,13 +139,13 @@ ecl_bds_set_size(cl_env_ptr env, cl_index new_size)
|
|||
env->bds_limit_size = new_size - 2*margin;
|
||||
org = ecl_alloc_atomic(new_size * sizeof(*org));
|
||||
|
||||
ecl_disable_interrupts_env(env);
|
||||
ECL_STACK_RESIZE_DISABLE_INTERRUPTS(env);
|
||||
memcpy(org, old_org, (limit + 1) * sizeof(*org));
|
||||
env->bds_top = org + limit;
|
||||
env->bds_org = org;
|
||||
env->bds_limit = org + (new_size - 2*margin);
|
||||
env->bds_size = new_size;
|
||||
ecl_enable_interrupts_env(env);
|
||||
ECL_STACK_RESIZE_ENABLE_INTERRUPTS(env);
|
||||
|
||||
ecl_dealloc(old_org);
|
||||
}
|
||||
|
|
@ -505,13 +505,13 @@ frs_set_size(cl_env_ptr env, cl_index new_size)
|
|||
env->frs_limit_size = new_size - 2*margin;
|
||||
org = ecl_alloc_atomic(new_size * sizeof(*org));
|
||||
|
||||
ecl_disable_interrupts_env(env);
|
||||
ECL_STACK_RESIZE_DISABLE_INTERRUPTS(the_env);
|
||||
memcpy(org, old_org, (limit + 1) * sizeof(*org));
|
||||
env->frs_top = org + limit;
|
||||
env->frs_org = org;
|
||||
env->frs_limit = org + (new_size - 2*margin);
|
||||
env->frs_size = new_size;
|
||||
ecl_enable_interrupts_env(env);
|
||||
ECL_STACK_RESIZE_ENABLE_INTERRUPTS(the_env);
|
||||
|
||||
ecl_dealloc(old_org);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -642,6 +642,33 @@ static union {
|
|||
# endif /* _MSC_VER == 1600 */
|
||||
#endif /* ~NAN */
|
||||
|
||||
/*
|
||||
* safe stack resizing
|
||||
*/
|
||||
|
||||
/* We can't block interrupts with ecl_disable_interrupts() and write
|
||||
* in the thread local environment if we use fast interrupt dispatch
|
||||
* via mprotect(), so we have to use sigprocmask instead. No
|
||||
* performance problems, since this is only used for stack
|
||||
* resizing. */
|
||||
#ifdef ECL_USE_MPROTECT
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
#include <signal.h>
|
||||
#define ECL_STACK_RESIZE_DISABLE_INTERRUPTS(the_env) \
|
||||
sigset_t __sigset_new, __sigset_previous; \
|
||||
sigfillset(&__sigset_new); \
|
||||
pthread_sigmask(SIG_BLOCK, &__sigset_new, &__sigset_previous)
|
||||
#define ECL_STACK_RESIZE_ENABLE_INTERRUPTS(the_env) \
|
||||
pthread_sigmask(SIG_SETMASK, &__sigset_previous, NULL)
|
||||
#else
|
||||
#error "Can't protect stack resizing from interrupts without sigprocmask. Either build ECL without mprotect() or live with possible race conditions."
|
||||
#endif /* HAVE_SIGPROCMASK */
|
||||
#else
|
||||
#define ECL_STACK_RESIZE_DISABLE_INTERRUPTS(the_env) ecl_disable_interrupts_env(the_env);
|
||||
#define ECL_STACK_RESIZE_ENABLE_INTERRUPTS(the_env) ecl_enable_interrupts_env(env);
|
||||
#endif /* ECL_USE_MPROTECT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue