Re: Bug#696757: ecl hang: SIGNAL problem
Hi!
As 12.12.1 in experimental builds while the unstable/testing one
doesn't I've bisected down the changes in upstream git. It seems to work
since c7953cc0f54281c3de6a845f3599544afba20b2a. The patch doesn't simply
apply to unstable so I haven't tested jet if that'd simply work. Also
it's a bit intrusive change done upstream but might give a hiunt for a
fix. Also the description sounds like it *could* affect the problem.
Christoph
commit c7953cc0f54281c3de6a845f3599544afba20b2a
Author: Juan Jose Garcia Ripoll <jjgarcia@users.sourceforge.net>
Date: Thu May 17 08:51:26 2012 +0200
Signal handlers receive now an optional keyword argument with the process that received the signal.
diff --git a/src/c/main.d b/src/c/main.d
index da63f83..29197a4 100644
--- a/src/c/main.d
+++ b/src/c/main.d
@@ -131,7 +131,9 @@ void
ecl_init_env(cl_env_ptr env)
{
env->c_env = NULL;
-
+#if !defined(ECL_THREADS)
+ env->own_process = Cnil;
+#endif
env->string_pool = Cnil;
env->stack = NULL;
diff --git a/src/c/symbols_list.h b/src/c/symbols_list.h
index a5e87f0..02c1680 100755
--- a/src/c/symbols_list.h
+++ b/src/c/symbols_list.h
@@ -1950,7 +1950,7 @@ cl_symbols[] = {
{EXT_ "WITH-UNIQUE-NAMES", EXT_ORDINARY, NULL, -1, OBJNULL},
-{SYS_ "HANDLE-SIGNAL", SI_ORDINARY, si_handle_signal, 1, OBJNULL},
+{SYS_ "HANDLE-SIGNAL", SI_ORDINARY, si_handle_signal, 2, OBJNULL},
{EXT_ "WITH-INTERRUPTS", MP_CONSTANT, NULL, -1, OBJNULL},
{EXT_ "WITHOUT-INTERRUPTS", MP_CONSTANT, NULL, -1, OBJNULL},
diff --git a/src/c/unixint.d b/src/c/unixint.d
index 18b0e04..a27e9da 100755
--- a/src/c/unixint.d
+++ b/src/c/unixint.d
@@ -321,7 +321,7 @@ unblock_signal(cl_env_ptr the_env, int signal)
ecl_def_ct_base_string(str_ignore_signal,"Ignore signal",13,static,const);
static void
-handle_signal_now(cl_object signal_code)
+handle_signal_now(cl_object signal_code, cl_object process)
{
switch (type_of(signal_code)) {
case t_fixnum:
@@ -336,6 +336,10 @@ handle_signal_now(cl_object signal_code)
*/
if (cl_find_class(2, signal_code, Cnil) != Cnil)
cl_cerror(2, str_ignore_signal, signal_code);
+#ifdef ECL_THREADS
+ else if (!Null(process))
+ _ecl_funcall3(signal_code, @':process', process);
+#endif
else
_ecl_funcall1(signal_code);
break;
@@ -351,9 +355,9 @@ handle_signal_now(cl_object signal_code)
}
cl_object
-si_handle_signal(cl_object signal_code)
+si_handle_signal(cl_object signal_code, cl_object process)
{
- handle_signal_now(signal_code);
+ handle_signal_now(signal_code, process);
@(return)
}
@@ -361,7 +365,7 @@ static void
handle_all_queued(cl_env_ptr env)
{
while (env->pending_interrupt != Cnil) {
- handle_signal_now(pop_signal(env));
+ handle_signal_now(pop_signal(env), env->own_process);
}
}
@@ -436,7 +440,7 @@ handle_or_queue(cl_env_ptr the_env, cl_object signal_code, int code)
else {
if (code) unblock_signal(the_env, code);
si_trap_fpe(@'last', Ct); /* Clear FPE exception flag */
- handle_signal_now(signal_code);
+ handle_signal_now(signal_code, the_env->own_process);
}
}
@@ -472,11 +476,112 @@ handler_fn_prototype(evil_signal_handler, int sig, siginfo_t *siginfo, void *dat
signal_object = ecl_gethash_safe(MAKE_FIXNUM(sig),
cl_core.known_signals,
Cnil);
- handle_signal_now(signal_object);
+ handle_signal_now(signal_object, the_env->own_process);
errno = old_errno;
}
#if defined(ECL_THREADS) && !defined(ECL_MS_WINDOWS_HOST)
+typedef struct {
+ cl_object process;
+ int signo;
+} signal_thread_message;
+static cl_object signal_thread_process = Cnil;
+static signal_thread_message signal_thread_msg;
+static cl_object signal_thread_spinlock = Cnil;
+static int signal_thread_pipe[2] = {-1,-1};
+
+static void
+handler_fn_prototype(deferred_signal_handler, int sig, siginfo_t *siginfo, void *data)
+{
+ int old_errno = errno;
+ cl_env_ptr the_env;
+ signal_thread_message msg;
+ reinstall_signal(sig, deferred_signal_handler);
+ /* The lisp environment might not be installed. */
+ the_env = ecl_process_env();
+ unlikely_if (zombie_process(the_env))
+ return;
+ msg.signo = sig;
+ msg.process = the_env->own_process;
+ if (msg.process == signal_thread_process) {
+ /* The signal handling thread may also receive signals. In
+ * this case we do not use the pipe, but just copy the message
+ * Note that read() will abort the thread will get notified. */
+ signal_thread_msg = msg;
+ } else if (signal_thread_pipe[1] > 0) {
+ ecl_get_spinlock(the_env, &signal_thread_spinlock);
+ write(signal_thread_pipe[1], &msg, sizeof(msg));
+ ecl_giveup_spinlock(&signal_thread_spinlock);
+ } else {
+ /* Nothing to do. There is no way to handle this signal because
+ * the responsible thread is not running */
+ }
+ errno = old_errno;
+}
+
+static cl_object
+asynchronous_signal_servicing_thread()
+{
+ const cl_env_ptr the_env = ecl_process_env();
+ int interrupt_signal;
+ /*
+ * We block all signals except the usual interrupt thread.
+ */
+ {
+ sigset_t handled_set;
+ sigfillset(&handled_set);
+ if (ecl_option_values[ECL_OPT_TRAP_INTERRUPT_SIGNAL]) {
+ interrupt_signal =
+ ecl_option_values[ECL_OPT_THREAD_INTERRUPT_SIGNAL];
+ sigdelset(&handled_set, interrupt_signal);
+ }
+ pthread_sigmask(SIG_BLOCK, &handled_set, NULL);
+ }
+ /*
+ * We create the object for communication. We need a lock to prevent other
+ * threads from writing before the pipe is created.
+ */
+ ecl_get_spinlock(the_env, &signal_thread_spinlock);
+ pipe(signal_thread_pipe);
+ ecl_giveup_spinlock(&signal_thread_spinlock);
+ signal_thread_msg.process = Cnil;
+ for (;;) {
+ cl_object signal_code;
+ signal_thread_msg.process = Cnil;
+ if (read(signal_thread_pipe[0], &signal_thread_msg,
+ sizeof(signal_thread_msg)) < 0)
+ {
+ if (errno != EINTR ||
+ signal_thread_msg.process != the_env->own_process)
+ break;
+ }
+ if (signal_thread_msg.signo == interrupt_signal &&
+ signal_thread_msg.process == the_env->own_process) {
+ break;
+ }
+#ifdef SIGCHLD
+ if (signal_thread_msg.signo == SIGCHLD) {
+ si_wait_for_all_processes();
+ continue;
+ }
+#endif
+ signal_code = ecl_gethash_safe(MAKE_FIXNUM(signal_thread_msg.signo),
+ cl_core.known_signals,
+ Cnil);
+ if (!Null(signal_code)) {
+ mp_process_run_function(4, @'si::handle-signal',
+ @'si::handle-signal',
+ signal_code,
+ signal_thread_msg.process);
+ }
+ }
+ close(signal_thread_pipe[0]);
+ close(signal_thread_pipe[1]);
+ ecl_return0(the_env);
+}
+#endif /* ECL_THREADS && !ECL_MS_WINDOWS_HOST */
+
+#if defined(ECL_THREADS) && !defined(ECL_MS_WINDOWS_HOST)
static void
handler_fn_prototype(process_interrupt_handler, int sig, siginfo_t *siginfo, void *data)
{
@@ -582,7 +687,7 @@ handler_fn_prototype(fpe_signal_handler, int sig, siginfo_t *info, void *data)
*/
si_trap_fpe(@'last', Ct); /* Clear FPE exception flag */
unblock_signal(the_env, code);
- handle_signal_now(condition);
+ handle_signal_now(condition, the_env->own_process);
/* We will not reach past this point. */
}
@@ -945,7 +1050,7 @@ _ecl_w32_exception_filter(struct _EXCEPTION_POINTERS* ep)
cl_object signal = pop_signal(the_env);
process->process.interrupt = Cnil;
while (signal != Cnil && signal) {
- handle_signal_now(signal);
+ handle_signal_now(signal, the_env->own_process);
signal = pop_signal(the_env);
}
return EXCEPTION_CONTINUE_EXECUTION;
@@ -953,37 +1058,37 @@ _ecl_w32_exception_filter(struct _EXCEPTION_POINTERS* ep)
}
/* Catch all arithmetic exceptions */
case EXCEPTION_INT_DIVIDE_BY_ZERO:
- handle_signal_now(@'division-by-zero');
+ handle_signal_now(@'division-by-zero', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_INT_OVERFLOW:
- handle_signal_now(@'arithmetic-error');
+ handle_signal_now(@'arithmetic-error', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- handle_signal_now(@'floating-point-overflow');
+ handle_signal_now(@'floating-point-overflow', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_OVERFLOW:
- handle_signal_now(@'floating-point-overflow');
+ handle_signal_now(@'floating-point-overflow', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_UNDERFLOW:
- handle_signal_now(@'floating-point-underflow');
+ handle_signal_now(@'floating-point-underflow', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_INEXACT_RESULT:
- handle_signal_now(@'floating-point-inexact');
+ handle_signal_now(@'floating-point-inexact', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_INVALID_OPERATION:
- handle_signal_now(@'floating-point-invalid-operation');
+ handle_signal_now(@'floating-point-invalid-operation', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_FLT_STACK_CHECK:
- handle_signal_now(@'arithmetic-error');
+ handle_signal_now(@'arithmetic-error', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
/* Catch segmentation fault */
case EXCEPTION_ACCESS_VIOLATION:
- handle_signal_now(@'ext::segmentation-violation');
+ handle_signal_now(@'ext::segmentation-violation', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
/* Catch illegal instruction */
case EXCEPTION_ILLEGAL_INSTRUCTION:
- handle_signal_now(@'ext::illegal-instruction');
+ handle_signal_now(@'ext::illegal-instruction', the_env->own_process);
return EXCEPTION_CONTINUE_EXECUTION;
/* Do not catch anything else */
default:
@@ -999,9 +1104,9 @@ static cl_object
W32_handle_in_new_thread(cl_object signal_code)
{
int outside_ecl = ecl_import_current_thread(@'si::handle-signal', Cnil);
- mp_process_run_function(3, @'si::handle-signal',
+ mp_process_run_function(4, @'si::handle-signal',
@'si::handle-signal',
- signal_code);
+ signal_code, Cnil);
if (outside_ecl) ecl_release_current_thread();
}
@@ -1021,7 +1126,7 @@ BOOL WINAPI W32_console_ctrl_handler(DWORD type)
}
#endif /* ECL_WINDOWS_THREADS */
-#if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
+#if 0
static cl_object
asynchronous_signal_servicing_thread()
{
@@ -1155,8 +1260,8 @@ install_asynchronous_signal_handlers()
#else
# if defined(ECL_THREADS) && defined(HAVE_SIGPROCMASK)
# define async_handler(signal,handler,mask) { \
- if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD]) { \
- sigaddset(mask, signal); \
+ if (ecl_option_values[ECL_OPT_SIGNAL_HANDLING_THREAD]) { \
+ mysignal(signal, deferred_signal_handler); \
} else { \
mysignal(signal,handler); \
}}
@@ -1221,6 +1326,7 @@ install_signal_handling_thread()
Cnil,
0);
cl_object process =
+ signal_thread_process =
mp_process_run_function_wait(2,
@'si::signal-servicing',
fun);
diff --git a/src/h/external.h b/src/h/external.h
index 57581da..c4dc09d 100755
--- a/src/h/external.h
+++ b/src/h/external.h
@@ -94,9 +94,7 @@ struct cl_env_struct {
BIGNUM_REGISTER_SIZE in config.h */
cl_object big_register[3];
-#ifdef ECL_THREADS
cl_object own_process;
-#endif
cl_object pending_interrupt;
cl_object signal_queue;
cl_object signal_queue_spinlock;
@@ -1868,7 +1866,7 @@ extern ECL_API cl_object si_copy_file(cl_object orig, cl_object end);
#define ecl_enable_interrupts() ecl_enable_interrupts_env(&cl_env)
#define ECL_PSEUDO_ATOMIC_ENV(env,stmt) (ecl_disable_interrupts_env(env),(stmt),ecl_enable_interrupts_env(env))
#define ECL_PSEUDO_ATOMIC(stmt) (ecl_disable_interrupts(),(stmt),ecl_enable_interrupts())
-extern ECL_API cl_object si_handle_signal(cl_object signal);
+extern ECL_API cl_object si_handle_signal(cl_object signal, cl_object process);
extern ECL_API cl_object si_get_signal_handler(cl_object signal);
extern ECL_API cl_object si_set_signal_handler(cl_object signal, cl_object handler);
extern ECL_API cl_object si_catch_signal(cl_narg narg, cl_object signal, cl_object state, ...);
diff --git a/src/lsp/top.lsp b/src/lsp/top.lsp
index b6e43a3..9857dde 100644
--- a/src/lsp/top.lsp
+++ b/src/lsp/top.lsp
@@ -498,7 +498,7 @@ Use special code 0 to cancel this operation.")
(restart-case (simple-terminal-interrupt)
(continue ())))
-(defun terminal-interrupt (&optional (correctablep t))
+(defun terminal-interrupt (&key process (correctablep t))
(declare (ignore correctablep))
#+threads
(mp:without-interrupts
Reply to: