Commit 57f66379 authored by Marius Gerbershagen's avatar Marius Gerbershagen
Browse files

threading: introduce thread safe ECL_UNWIND_PROTECT macro and use where needed

    Disabling interrupts during execution of cleanup forms of
    unwind-protect caused problems in some cases. Hence only do this
    where needed, i.e. for freeing resources (such as locks or files)
    shared between multiple threads or processes.
parent dfd24e45
......@@ -696,9 +696,9 @@ si_load_foreign_module(cl_object filename)
}
# ifdef ECL_THREADS
(void)0; /* MSVC complains about missing ';' before '}' */
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
mp_giveup_lock(ecl_symbol_value(@'mp::+load-compile-lock+'));
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
# endif
if (ecl_unlikely(ecl_t_of(output) != t_codeblock)) {
FEerror("LOAD-FOREIGN-MODULE: Could not load "
......@@ -728,9 +728,9 @@ si_unload_foreign_module(cl_object module)
if (ecl_likely(ecl_library_close(module))) output = ECL_T;
# ifdef ECL_THREADS
(void)0; /* MSVC complains about missing ';' before '}' */
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
mp_giveup_lock(ecl_symbol_value(@'mp::+load-compile-lock+'));
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
# endif
@(return output);
#endif
......
......@@ -111,14 +111,14 @@ si_load_source(cl_object source, cl_object verbose, cl_object print, cl_object e
}
}
ecl_bds_unwind1(the_env);
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
/* We do not want to come back here if close_stream fails,
therefore, first we frs_pop() current jump point, then
try to close the stream, and then jump to next catch
point */
if (strm != source)
cl_close(3, strm, @':abort', @'t');
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
@(return ECL_NIL);
}
......@@ -176,14 +176,14 @@ si_load_bytecodes(cl_object source, cl_object verbose, cl_object print, cl_objec
2, x, source);
}
}
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
/* We do not want to come back here if close_stream fails,
therefore, first we frs_pop() current jump point, then
try to close the stream, and then jump to next catch
point */
if (strm != source)
cl_close(3, strm, @':abort', @'t');
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
@(return ECL_NIL);
}
......
......@@ -2455,12 +2455,12 @@ ecl_init_module(cl_object block, void (*entry_point)(cl_object))
ecl_dealloc(VVtemp);
}
ecl_bds_unwind1(env);
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
if (in != OBJNULL)
cl_close(1,in);
env->packages_to_be_created = old_eptbc;
env->packages_to_be_created_p = ECL_NIL;
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
return block;
}
......@@ -601,9 +601,10 @@ mp_process_enable(cl_object process)
}
#endif
ecl_enable_interrupts_env(the_env);
} ECL_UNWIND_PROTECT_EXIT {
} ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT {
if (!ok) {
/* INV: interrupts are already disabled through unwind-protect */
/* INV: interrupts are already disabled through thread safe
* unwind-protect */
ecl_unlist_process(process);
/* Disable the barrier and alert possible waiting processes. */
mp_barrier_unblock(3, process->process.exit_barrier,
......@@ -615,7 +616,7 @@ mp_process_enable(cl_object process)
}
/* Unleash the thread */
ecl_giveup_spinlock(&process->process.start_stop_spinlock);
} ECL_UNWIND_PROTECT_END;
} ECL_UNWIND_PROTECT_THREAD_SAFE_END;
@(return (ok? process : ECL_NIL));
}
......
......@@ -51,6 +51,7 @@ ecl_giveup_spinlock(cl_object *lock)
static ECL_INLINE void
wait_queue_nconc(cl_env_ptr the_env, cl_object q, cl_object new_tail)
{
/* INV: interrupts are disabled */
ecl_get_spinlock(the_env, &q->queue.spinlock);
q->queue.list = ecl_nconc(q->queue.list, new_tail);
ecl_giveup_spinlock(&q->queue.spinlock);
......@@ -74,6 +75,7 @@ wait_queue_pop_all(cl_env_ptr the_env, cl_object q)
static ECL_INLINE void
wait_queue_delete(cl_env_ptr the_env, cl_object q, cl_object item)
{
/* INV: interrupts are disabled */
ecl_get_spinlock(the_env, &q->queue.spinlock);
q->queue.list = ecl_delete_eq(item, q->queue.list);
ecl_giveup_spinlock(&q->queue.spinlock);
......
......@@ -383,18 +383,18 @@ extern void cl_write_object(cl_object x, cl_object stream);
ECL_UNWIND_PROTECT_BEGIN(__ecl_the_env); \
ecl_enable_interrupts_env(__ecl_the_env);
# define ECL_WITH_LOCK_END \
ECL_UNWIND_PROTECT_EXIT { \
ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT { \
mp_giveup_lock(__ecl_the_lock); \
} ECL_UNWIND_PROTECT_END; }
} ECL_UNWIND_PROTECT_THREAD_SAFE_END; }
# define ECL_WITH_SPINLOCK_BEGIN(the_env,lock) { \
const cl_env_ptr __ecl_the_env = (the_env); \
cl_object *__ecl_the_lock = (lock); \
ECL_UNWIND_PROTECT_BEGIN(__ecl_the_env); \
ecl_get_spinlock(__ecl_the_env, __ecl_the_lock);
# define ECL_WITH_SPINLOCK_END \
ECL_UNWIND_PROTECT_EXIT { \
ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT { \
ecl_giveup_spinlock(__ecl_the_lock); \
} ECL_UNWIND_PROTECT_END; }
} ECL_UNWIND_PROTECT_THREAD_SAFE_END; }
#else
# define ECL_WITH_GLOBAL_LOCK_BEGIN(the_env)
# define ECL_WITH_GLOBAL_LOCK_END
......
......@@ -454,6 +454,19 @@ extern ECL_API ecl_frame_ptr _ecl_frs_push(register cl_env_ptr);
ecl_stack_pop_values(__the_env,__nr); \
if (__unwinding) ecl_unwind(__the_env,__next_fr); } while(0)
/* unwind-protect variant which disables interrupts during cleanup */
#define ECL_UNWIND_PROTECT_THREAD_SAFE_EXIT \
__unwinding=0; } \
ecl_bds_bind(__the_env,ECL_INTERRUPTS_ENABLED,ECL_NIL); \
ecl_frs_pop(__the_env); \
__nr = ecl_stack_push_values(__the_env);
#define ECL_UNWIND_PROTECT_THREAD_SAFE_END \
ecl_stack_pop_values(__the_env,__nr); \
ecl_bds_unwind1(__the_env); \
ecl_check_pending_interrupts(__the_env); \
if (__unwinding) ecl_unwind(__the_env,__next_fr); } while(0)
#define ECL_NEW_FRAME_ID(env) ecl_make_fixnum(env->frame_id++)
#define ECL_BLOCK_BEGIN(the_env,id) do { \
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment