Reliable signal patch
Kenneth Albanowski [Tue, 26 Nov 1996 10:40:50 +0000 (05:40 -0500)]
Subject: reliable signal patch (was Re: Reliable signals)

On Tue, 26 Nov 1996, Kenneth Albanowski wrote:

> > I found that 2 places in perl still use unreliable signals:
> >  my_pclose() in util.c
> >  pp_system() in pp_sys.c
> >
> > Is this working as designed, or an omission?
> I guess a new set of signal macros are needed, to reliably save and
> restore signal settings.

Here is a patch that accomplishes this. It replaces the rsignal
construction in mg.c with a generalized set of functions: rsignal,
rsignalsave, rsignalrestore, and rsignalstate.

Note that global.sym is patched to accomodate the new globally accessible
functions. They probably will be of use to XSUBs too.

This was diffed from a slightly messy 5.003_08, but should apply
acceptably over any 5.003_* series.

p5p-msgid: <Pine.LNX.3.93.961126053209.294J-100000@kjahds.com>

global.sym
mg.c
perl.h
pp_sys.c
proto.h
util.c

index ca7240a..3ae801f 100644 (file)
@@ -979,6 +979,10 @@ regnext
 regprop
 repeatcpy
 rninstr
+rsignal
+rsignalsave
+rsignalstate
+rsignalrestore
 runops
 safecalloc
 safemalloc
diff --git a/mg.c b/mg.c
index 8c678f4..6bc242a 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -634,46 +634,6 @@ MAGIC* mg;
     return 0;
 }
 
-#ifdef HAS_SIGACTION
-/* set up reliable signal() clone */
-
-typedef void (*Sigfunc) _((int));
-
-static
-Sigfunc rsignal(signo,handler)
-int signo;
-Sigfunc handler;
-{
-    struct sigaction act,oact;
-    
-    act.sa_handler = handler;
-    sigemptyset(&act.sa_mask);
-    act.sa_flags = 0;
-#ifdef SA_RESTART
-    act.sa_flags |= SA_RESTART;        /* SVR4, 4.3+BSD */
-#endif
-    if (sigaction(signo, &act, &oact) < 0)
-       return(SIG_ERR);
-    else
-       return(oact.sa_handler);
-}
-
-#else
-
-/* ah well, so much for reliability */
-
-#define rsignal(x,y) signal(x,y)
-
-#endif
-
-static sig_trapped;
-static
-Signal_t
-sig_trap(signo)
-int signo;
-{
-    sig_trapped++;
-}
 int
 magic_getsig(sv,mg)
 SV* sv;
@@ -686,15 +646,11 @@ MAGIC* mg;
        if(psig_ptr[i])
            sv_setsv(sv,psig_ptr[i]);
        else {
-           void (*origsig) _((int));
-           /* get signal state without losing signals */
-           sig_trapped=0;
-           origsig = rsignal(i,sig_trap);
-           rsignal(i,origsig);
-           if(sig_trapped)
-               kill(getpid(),i);
+           Sighandler_t sigstate;
+           sigstate = rsignalstate(i);
+
            /* cache state so we don't fetch it again */
-           if(origsig == SIG_IGN)
+           if(sigstate == SIG_IGN)
                sv_setpv(sv,"IGNORE");
            else
                sv_setsv(sv,&sv_undef);
diff --git a/perl.h b/perl.h
index f740c9a..770190d 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -1157,6 +1157,14 @@ I32 unlnk _((char*));
 #  endif
 #endif
 
+typedef Signal_t (*Sighandler_t) _((int));
+
+#ifdef HAS_SIGACTION
+typedef struct sigaction Sigsave_t;
+#else
+typedef Sighandler_t Sigsave_t;
+#endif
+
 #define SCAN_DEF 0
 #define SCAN_TR 1
 #define SCAN_REPL 2
index d580fba..ab8b8e6 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -2856,8 +2856,7 @@ PP(pp_system)
     int childpid;
     int result;
     int status;
-    Signal_t (*ihand)();     /* place to save signal during system() */
-    Signal_t (*qhand)();     /* place to save signal during system() */
+    Sigsave_t ihand,qhand;     /* place to save signals during system() */
 
 #if (defined(HAS_FORK) || defined(AMIGAOS)) && !defined(VMS) && !defined(OS2)
     if (SP - MARK == 1) {
@@ -2877,13 +2876,13 @@ PP(pp_system)
        sleep(5);
     }
     if (childpid > 0) {
-       ihand = signal(SIGINT, SIG_IGN);
-       qhand = signal(SIGQUIT, SIG_IGN);
+       rsignalsave(SIGINT, SIG_IGN, &ihand);
+       rsignalsave(SIGQUIT, SIG_IGN, &qhand);
        do {
            result = wait4pid(childpid, &status, 0);
        } while (result == -1 && errno == EINTR);
-       (void)signal(SIGINT, ihand);
-       (void)signal(SIGQUIT, qhand);
+       (void)rsignalrestore(SIGINT, &ihand);
+       (void)rsignalrestore(SIGQUIT, &qhand);
        statusvalue = FIXSTATUS(status);
        if (result < 0)
            value = -1;
diff --git a/proto.h b/proto.h
index 3b89d99..98d9420 100644 (file)
--- a/proto.h
+++ b/proto.h
@@ -355,6 +355,10 @@ char*      regnext _((char* p));
 char*  regprop _((char* op));
 void   repeatcpy _((char* to, char* from, I32 len, I32 count));
 char*  rninstr _((char* big, char* bigend, char* little, char* lend));
+Sighandler_t rsignal _((int, Sighandler_t));
+int    rsignalsave _((int, Sighandler_t, Sigsave_t*));
+int    rsignalrestore _((int, Sigsave_t*));
+Sighandler_t rsignalstate _((int));
 int    runops _((void));
 #ifndef HAS_RENAME
 I32    same_dirent _((char* a, char* b));
diff --git a/util.c b/util.c
index 22bda3f..da73b57 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1778,13 +1778,116 @@ int newfd;
 }
 #endif
 
+#ifdef HAS_SIGACTION
+
+Sighandler_t rsignal(signo,handler)
+int signo;
+Sighandler_t handler;
+{
+    struct sigaction act,oact;
+    
+    act.sa_handler = handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+#ifdef SA_RESTART
+    act.sa_flags |= SA_RESTART;        /* SVR4, 4.3+BSD */
+#endif
+    if (sigaction(signo, &act, &oact) < 0)
+       return(SIG_ERR);
+    else
+       return(oact.sa_handler);
+}
+
+int rsignalsave(signo, handler, save)
+int signo;
+Sighandler_t handler;
+Sigsave_t *save;
+{
+    struct sigaction act;
+    
+    act.sa_handler = handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+#ifdef SA_RESTART
+    act.sa_flags |= SA_RESTART;        /* SVR4, 4.3+BSD */
+#endif
+    return sigaction(signo, &act, save);
+}
+
+int rsignalrestore(signo, save)
+int signo;
+Sigsave_t *save;
+{
+    return sigaction(signo, save, 0);
+}
+
+Sighandler_t rsignalstate(signo)
+int signo;
+{
+    struct sigaction oact;
+    if (sigaction(signo, 0, &oact)<0)
+        return (SIG_ERR);
+    else
+        return (oact.sa_handler);
+}
+
+#else
+
+static int sig_trapped;
+
+static
+Signal_t sig_trap(signo)
+int signo;
+{
+    sig_trapped++;
+}
+
+Sighandler_t rsignalstate(signo)
+int signo;
+{
+    Sighandler_t oldsig;
+    sig_trapped=0;
+    oldsig = signal(signo, sig_trap);
+    signal(signo, oldsig);
+    if (sig_trapped)
+        kill(getpid(),signo);
+        
+    return oldsig;
+}
+
+Sighandler_t rsignal(signo,handler)
+int signo;
+Sighandler_t handler;
+{
+    return signal(signo,handler);
+}
+
+int rsignalsave(signo, handler, save)
+int signo;
+Sighandler_t handler;
+Sigsave_t *save;
+{
+    *save = signal(signo,handler);
+    return (*save == SIG_ERR) ? -1 : 0;
+}
+
+int rsignalrestore(signo, save)
+int signo;
+Sigsave_t *save;
+{
+    return (signal(signo, *save) == SIG_ERR) ? -1 : 0;
+}
+
+#endif
+
+
 #if  (!defined(DOSISH) || defined(HAS_FORK) || defined(AMIGAOS)) \
      && !defined(VMS)  /* VMS' my_popen() is in VMS.c */
 I32
 my_pclose(ptr)
 PerlIO *ptr;
 {
-    Signal_t (*hstat)(), (*istat)(), (*qstat)();
+    Sigsave_t hstat, istat, qstat;
     int status;
     SV **svp;
     int pid;
@@ -1802,15 +1905,15 @@ PerlIO *ptr;
 #ifdef UTS
     if(kill(pid, 0) < 0) { return(pid); }   /* HOM 12/23/91 */
 #endif
-    hstat = signal(SIGHUP, SIG_IGN);
-    istat = signal(SIGINT, SIG_IGN);
-    qstat = signal(SIGQUIT, SIG_IGN);
+    rsignalsave(SIGHUP, SIG_IGN, &hstat);
+    rsignalsave(SIGINT, SIG_IGN, &istat);
+    rsignalsave(SIGQUIT, SIG_IGN, &qstat);
     do {
        pid = wait4pid(pid, &status, 0);
     } while (pid == -1 && errno == EINTR);
-    signal(SIGHUP, hstat);
-    signal(SIGINT, istat);
-    signal(SIGQUIT, qstat);
+    rsignalrestore(SIGHUP, &hstat);
+    rsignalrestore(SIGINT, &istat);
+    rsignalrestore(SIGQUIT, &qstat);
     return(pid < 0 ? pid : status);
 }
 #endif /* !DOSISH */