Bill Allombert on Wed, 02 Nov 2005 18:08:33 +0100


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

Re: GP handling of SIGINT (Linux)


On Mon, May 16, 2005 at 11:01:02AM +0200, Bill Allombert wrote:
> On Mon, Apr 18, 2005 at 01:33:23PM +0200, Jeroen Demeyer wrote:
>
> After reading carefully the glibc documentation and the code, it looks
> like the code was made for System V, and should also work on BSD but
> not on Linux...
> 
> 1) gp_sighandler start by doing 
>   (void)os_signal(sig,gp_sighandler);
> 
> This is a SYSV idiom: SYSV reset the signal handler to SIG_DFL when
> calling the handler, so this line reinstate the gphandler.
> 
> BSD and POSIX instead does not change the handler, but block the signal
> (see sigprocmask). However BSD longjmp will restore the set of blocked
> signals, so will unblock it, but not Linux longjmp, you have to use
> sigsetjmp/siglongjmp (which are slower). (POSIX itself allows both
> behaviour).
> 
> One solution is to use sigsetjmp/siglongjmp and this seems to fix the 
> problem, but I don't think this is the best solution because sigsetjmp
> is slower than setjmp. I think it is cleaner to use sigaction to set up
> the signal handling to behave the way we like.
> 
> > A very ugly hack around this is to change this default.  I have done 
> > this in attached patch.  I can only say it fixes my problem, but it 
> > could very well break things.  The behaviour is also likely to be 
> > OS-dependent.
> 
> I am not sure it is a "very ugly hack". I think you are very close
> to a correct fix to the problem. signal(2) is deprecated in favour
> sigaction anyway.

Indeed, here a patch that add support for sigaction when available.
This avoid portability problems of signal().  This patch is strongly
based on your patch, Jeroen, thanks a lot!

Cheers,
Bill.
Index: config/get_libc
===================================================================
RCS file: /home/cvs/pari/config/get_libc,v
retrieving revision 1.8
diff -u -r1.8 get_libc
--- config/get_libc	6 Jun 2005 13:55:10 -0000	1.8
+++ config/get_libc	2 Nov 2005 16:14:05 -0000
@@ -13,7 +13,7 @@
   *cygwin*) list='times ftime';; # getrusage based timer always returns 0
   *) list='getrusage times ftime';;
 esac; . ./look
-list='sigsetmask sigrelse'; . ./look
+list='sigaction sigsetmask sigrelse'; . ./look
 list=TIOCGWINSZ; . ./look
 list=getrlimit; . ./look
 list='stat opendir'; . ./look
Index: config/paricfg.h.SH
===================================================================
RCS file: /home/cvs/pari/config/paricfg.h.SH,v
retrieving revision 1.24
diff -u -r1.24 paricfg.h.SH
--- config/paricfg.h.SH	6 Jun 2005 13:55:10 -0000	1.24
+++ config/paricfg.h.SH	2 Nov 2005 16:14:05 -0000
@@ -160,6 +160,10 @@
      esac;;
 esac
 
+case $has_sigaction in
+yes) echo '#define HAS_SIGACTION' >> $file;;
+esac
+
 case "$has_sigrelse" in
 yes) echo '#define USE_SIGRELSE 1' >> $file;;
   *) case "$has_sigsetmask" in
Index: src/language/es.c
===================================================================
RCS file: /home/cvs/pari/src/language/es.c,v
retrieving revision 1.206
diff -u -r1.206 es.c
--- src/language/es.c	29 Oct 2005 13:59:26 -0000	1.206
+++ src/language/es.c	2 Nov 2005 16:14:05 -0000
@@ -2809,11 +2809,21 @@
   close(fd);
 #endif
 }
+typedef void (*pari_sighandler_t)(int);
 
-void
-(*os_signal(int sig, void (*f)(int)))(int)
+pari_sighandler_t
+os_signal(int sig, pari_sighandler_t f)
 {
-#ifdef WINCE
+#ifdef HAS_SIGACTION
+  struct sigaction sa, oldsa;
+
+  sa.sa_handler = f;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_NODEFER;
+
+  if (sigaction(sig, &sa, &oldsa)) return NULL;
+  return oldsa.sa_handler;
+#elif defined(WINCE)
   return SIG_IGN;
 #else
   return signal(sig,f);
Index: src/language/init.c
===================================================================
RCS file: /home/cvs/pari/src/language/init.c,v
retrieving revision 1.274
diff -u -r1.274 init.c
--- src/language/init.c	29 Oct 2005 13:40:01 -0000	1.274
+++ src/language/init.c	2 Nov 2005 16:14:05 -0000
@@ -312,7 +312,10 @@
 pari_sighandler(int sig)
 {
   char *msg;
+#ifndef HAS_SIGACTION
+  /*SYSV reset the signal handler in the handler*/
   (void)os_signal(sig,pari_sighandler);
+#endif
   switch(sig)
   {
 #ifdef SIGBREAK
--- /dev/null	Sat Mar  1 19:52:54 2003
+++ config/has_sigaction.c	Wed Nov  2 16:59:16 2005
@@ -0,0 +1,12 @@
+#include <signal.h>
+main()
+{
+  struct sigaction sa, oldsa;
+
+  sa.sa_handler = SIG_DFL;
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = SA_NODEFER;
+
+  (void)(sigaction(SIGINT, &sa, &oldsa));
+  return 0;
+}