threading: fix race conditions in ECL_WITH_GLOBAL_ENV_RD/WRLOCK

We can't use ecl_disable_interrupts, because often writes in the
    thread local environment happen while we hold the locks (e.g.
    env->packages_to_be_created is written in find_pending_package
    while the lock is held in ecl_make_package). Therefore we use the
    lisp interrupt blocking mechanism. For this, the order of
    operations in cl_boot has to be modified a bit.
This commit is contained in:
Marius Gerbershagen 2018-02-18 20:50:50 +01:00
parent e5281a4685
commit 3f0fc4f855
5 changed files with 27 additions and 19 deletions

View file

@ -557,6 +557,24 @@ cl_boot(int argc, char **argv)
#endif
env->packages_to_be_created = ECL_NIL;
#ifdef ECL_THREADS
env->bindings_array = si_make_vector(ECL_T, ecl_make_fixnum(1024),
ECL_NIL, ECL_NIL, ECL_NIL, ECL_NIL);
si_fill_array_with_elt(env->bindings_array, ECL_NO_TL_BINDING, ecl_make_fixnum(0), ECL_NIL);
env->thread_local_bindings_size = env->bindings_array->vector.dim;
env->thread_local_bindings = env->bindings_array->vector.self.t;
#endif
/*
* Initialize the per-thread data.
* This cannot come later, because we need to be able to bind
* ext::*interrupts-enabled while creating packages.
*/
init_big();
ecl_init_env(env);
ecl_cs_set_org(env);
cl_core.lisp_package =
ecl_make_package(str_common_lisp,
cl_list(2, str_cl, str_LISP),
@ -623,14 +641,6 @@ cl_boot(int argc, char **argv)
/* These must come _after_ the packages and NIL/T have been created */
init_all_symbols();
/*
* Initialize the per-thread data.
* This cannot come later, because some routines need the
* frame stack immediately (for instance SI:PATHNAME-TRANSLATIONS).
*/
init_big();
ecl_init_env(env);
ecl_cs_set_org(env);
#if !defined(GBC_BOEHM)
/* We need this because a lot of stuff is to be created */
init_GC();
@ -648,11 +658,6 @@ cl_boot(int argc, char **argv)
#endif
#ifdef ECL_THREADS
env->bindings_array = si_make_vector(ECL_T, ecl_make_fixnum(1024),
ECL_NIL, ECL_NIL, ECL_NIL, ECL_NIL);
si_fill_array_with_elt(env->bindings_array, ECL_NO_TL_BINDING, ecl_make_fixnum(0), ECL_NIL);
env->thread_local_bindings_size = env->bindings_array->vector.dim;
env->thread_local_bindings = env->bindings_array->vector.self.t;
ECL_SET(@'mp::*current-process*', env->own_process);
#endif

View file

@ -77,6 +77,7 @@ cl_symbols[] = {
{SYS_ "DUMMY-TAG", SI_ORDINARY, NULL, -1, OBJNULL},
{SYS_ "*RESTART-CLUSTERS*", SI_SPECIAL, NULL, -1, Cnil},
{SYS_ "*HANDLER-CLUSTERS*", SI_SPECIAL, NULL, -1, Cnil},
{EXT_ "*INTERRUPTS-ENABLED*", EXT_SPECIAL, NULL, 1, ECL_T},
/* LISP PACKAGE */
{"&ALLOW-OTHER-KEYS", CL_ORDINARY, NULL, -1, OBJNULL},
@ -1102,7 +1103,6 @@ cl_symbols[] = {
{SYS_ "*IGNORE-EOF-ON-TERMINAL-IO*", SI_SPECIAL, NULL, -1, ECL_NIL},
{SYS_ "*INDENT-FORMATTED-OUTPUT*", SI_SPECIAL, NULL, -1, ECL_NIL},
{SYS_ "*INIT-FUNCTION-PREFIX*", SI_SPECIAL, NULL, -1, ECL_NIL},
{EXT_ "*INTERRUPTS-ENABLED*", EXT_SPECIAL, NULL, 1, ECL_T},
{SYS_ "*KEEP-DEFINITIONS*", SI_SPECIAL, NULL, -1, ECL_T},
{EXT_ "*LOAD-HOOKS*", EXT_SPECIAL, NULL, -1, OBJNULL},
{SYS_ "*LOAD-SEARCH-LIST*", SI_SPECIAL, NULL, -1, ECL_NIL},

View file

@ -77,6 +77,7 @@ cl_symbols[] = {
{SYS_ "DUMMY-TAG",NULL},
{SYS_ "*RESTART-CLUSTERS*",NULL},
{SYS_ "*HANDLER-CLUSTERS*",NULL},
{EXT_ "*INTERRUPTS-ENABLED*",NULL},
/* LISP PACKAGE */
{"&ALLOW-OTHER-KEYS",NULL},
@ -1102,7 +1103,6 @@ cl_symbols[] = {
{SYS_ "*IGNORE-EOF-ON-TERMINAL-IO*",NULL},
{SYS_ "*INDENT-FORMATTED-OUTPUT*",NULL},
{SYS_ "*INIT-FUNCTION-PREFIX*",NULL},
{EXT_ "*INTERRUPTS-ENABLED*",NULL},
{SYS_ "*KEEP-DEFINITIONS*",NULL},
{EXT_ "*LOAD-HOOKS*",NULL},
{SYS_ "*LOAD-SEARCH-LIST*",NULL},

View file

@ -401,18 +401,20 @@ extern void cl_write_object(cl_object x, cl_object stream);
#ifdef ECL_RWLOCK
# define ECL_WITH_GLOBAL_ENV_RDLOCK_BEGIN(the_env) { \
const cl_env_ptr __ecl_pack_env = the_env; \
ecl_disable_interrupts_env(__ecl_pack_env); \
ecl_bds_bind(__ecl_pack_env, ECL_INTERRUPTS_ENABLED, ECL_NIL); \
mp_get_rwlock_read_wait(cl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_RDLOCK_END \
mp_giveup_rwlock_read(cl_core.global_env_lock); \
ecl_enable_interrupts_env(__ecl_pack_env); }
ecl_bds_unwind1(__ecl_pack_env); \
ecl_check_pending_interrupts(__ecl_pack_env); }
# define ECL_WITH_GLOBAL_ENV_WRLOCK_BEGIN(the_env) { \
const cl_env_ptr __ecl_pack_env = the_env; \
ecl_disable_interrupts_env(__ecl_pack_env); \
ecl_bds_bind(__ecl_pack_env, ECL_INTERRUPTS_ENABLED, ECL_NIL); \
mp_get_rwlock_write_wait(cl_core.global_env_lock);
# define ECL_WITH_GLOBAL_ENV_WRLOCK_END \
mp_giveup_rwlock_write(cl_core.global_env_lock); \
ecl_enable_interrupts_env(__ecl_pack_env); }
ecl_bds_unwind1(__ecl_pack_env); \
ecl_check_pending_interrupts(__ecl_pack_env); }
#else
# define ECL_WITH_GLOBAL_ENV_RDLOCK_BEGIN(the_env)
# define ECL_WITH_GLOBAL_ENV_RDLOCK_END

View file

@ -249,6 +249,7 @@ enum ecl_stype { /* symbol type */
#define ECL_DUMMY_TAG ((cl_object)(cl_symbols+4))
#define ECL_RESTART_CLUSTERS ((cl_object)(cl_symbols+5))
#define ECL_HANDLER_CLUSTERS ((cl_object)(cl_symbols+6))
#define ECL_INTERRUPTS_ENABLED ((cl_object)(cl_symbols+7))
#define ECL_NO_TL_BINDING ((cl_object)(1 << ECL_TAG_BITS))
struct ecl_symbol {