[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: