I've run across the problem a number of times, primarily in the test suite,
where:
        kill 'HUP', $$;
will blow away the whole Perl image...setting $SIG doesn't help, no real
way to catch it.

On VMS 6.2, the reason is simple: the CRTL kill() is implemented with
SYS$FORCEX, which causes a SYS$EXIT to be called rather than raising an
exception.

Later versions of VMS (7.1, for example) have a rather nicer kill(), where
signals are actually delivered.

I did some checking into this, and found a way to implement a gentler
kill() using an undocumented system service: SYS$SIGPRC.  Doing some
assembly-level stepping through kill() on VMS 7.1 gives some hint that
SYS$SIGPRC is indeed what is being used.

Here's a patch to:

 CONFIGURE.COM:
    check if kill is doing a SYS$FORCEX
     check if SYS$SIGPRC will work as a kill() substitute
       --> #define KILL_BY_SIGPRC in config.h

 [.VMS]VMSISH.H
    if KILL_BY_SIGPRC defines kill -> Perl_my_kill

 [.VMS]VMS.C
    On first call to Perl_my_kill we:
        set a temp exception handler
        run through the signals and store the VMS exception status produced

    Then check if the signal is in valid range, call SYS$SIGPRC with the
        correct VMS status, handle errors, etc.


I found that on VMS 7.1, kill() was throwing an exception with code:
            0x10000000 + 0x3DF00 + (signal*8)
While VMS 6.2 was a whole gamut of more "normal" codes (ACCVIO, etc.)
There didn't seem to be an obvious source of the mapping of
signal#->VMS_status, so it looked like a dynamic mapping would be best...
and should still work if you take your .EXE from VMS 6.2 to 7.1, for example.

Okay, you can all flame me now for proposing to insert an undocumented
system service (gasp!) call in Perl.  But note that this would only affect
VMS versions earlier than current, where the system software is presumably
static.

For (a tiny bit) more info on SYS$SIGPRC, see:
    http://www.openvms.compaq.com/wizard/wiz_2889.html

diff -uBb configure.com-orig configure.com
--- configure.com-orig  Mon Nov 19 14:27:56 2001
+++ configure.com       Mon Nov 19 16:02:52 2001
@@ -4914,9 +4914,51 @@
 $   WS "    printf(""%d\n"", i);"
 $   WS "    exit(0);"
 $   WS "}"
+$   CS
 $   GOSUB compile
 $   d_nv_preserves_uv_bits = tmp
 $ ENDIF
+$!
+$ echo4 "Checking whether your kill() uses SYS$FORCEX..."
+$ kill_by_sigprc = "undef"
+$ OS
+$ WS "#include <stdio.h>"
+$ WS "#include <signal.h>"
+$ WS "void handler(int s) { printf(""%d\n"",s); } "
+$ WS "main(){"
+$ WS "    printf(""0"");"
+$ WS "    signal(1,handler); kill(0,1);"
+$ WS "}"
+$ CS
+$ ON ERROR THEN CONTINUE
+$ GOSUB compile
+$ IF tmp .NES. "01"
+$ THEN 
+$   echo "Yes, it does." 
+$   echo4 "Checking whether we can use SYS$SIGPRC instead"
+$   OS
+$   WS "#include <stdio.h>"
+$   WS "#include <lib$routines.h>"
+$   WS "unsigned long code = 0;"
+$   WS "int handler(unsigned long *args) {"
+$   WS "    code = args[1];"
+$   WS "    return 1;"
+$   WS "}"
+$   WS "main() { "
+$   WS "    int iss, sys$sigprc();"
+$   WS "    lib$establish(handler);"
+$   WS "    iss = sys$sigprc(0,0,0x1234);"
+$   WS "    iss =  ((iss&1)==1 && code == 0x1234);" 
+$   WS "    printf(""%d\n"",iss);"
+$   WS "}"
+$   CS
+$   GOSUB compile
+$   IF tmp .EQS. "1"
+$   THEN
+$       echo "looks like we can"
+$       kill_by_sigprc = "define"
+$   ENDIF
+$ ENDIF
 $ DELETE/SYMBOL tmp
 $!
 $! Finally the composite ones. All config
@@ -5748,6 +5790,7 @@
 $! Alas this does not help to build Fcntl
 $!   WC "#define PERL_IGNORE_FPUSIG SIGFPE"
 $ ENDIF
+$ IF kill_by_sigprc .EQS. "define" then WC "#define KILL_BY_SIGPRC"
 $ CLOSE CONFIG
 $!
 $ echo4 "Doing variable substitutions on .SH files..."
diff -uBb vms/vms.c-orig vms/vms.c
--- vms/vms.c-orig      Mon Nov 19 17:19:14 2001
+++ vms/vms.c   Mon Nov 19 17:19:10 2001
@@ -1093,6 +1093,75 @@
 /*}}}*/
 #endif
 
+#ifdef KILL_BY_SIGPRC
+/* okay, this is some blatent hackery ... 
+   we use this if the kill() in the CRTL uses sys$forcex.  So, instead
+   we use the (undocumented) system service sys$sigprc.  It has the same
+   parameters as sys$forcex, but throws an exception in the target process
+   rather than calling sys$exit.
+
+   The tricky bit is to go from unixoid signal#'s to VMS condition codes.
+   And to do that, we run through the signals and make a table of the VMS
+   codes that are actually thrown.
+*/
+
+static unsigned long sig_code[_SIG_MAX+1];
+static int sig_code_ndx = -1;
+
+static int
+temp_handler(unsigned long *args)
+{
+    sig_code[sig_code_ndx] = args[1];
+    return SS$_CONTINUE;
+}
+
+static void
+get_sigcodes(void)
+{
+    int iss;
+    if (sig_code_ndx != -1) return;
+
+    lib$establish(temp_handler);
+    for (sig_code_ndx = _SIG_MIN; sig_code_ndx < _SIG_MAX+1; sig_code_ndx++) {
+        iss = raise(sig_code_ndx);
+    }
+}
+
+
+int
+Perl_my_kill(int pid, int sig)
+{
+    int iss;
+    int sys$sigprc();
+
+    get_sigcodes();
+    if (sig < _SIG_MIN || sig > _SIG_MAX) {
+        return -1;
+    }
+
+    iss = sys$sigprc(&pid,0,sig_code[sig]);
+    if (iss&1) return 0;
+
+    switch (iss) {
+      case SS$_NOPRIV:
+        set_errno(EPERM);  break;
+      case SS$_NONEXPR:  
+      case SS$_NOSUCHNODE:
+      case SS$_UNREACHABLE:
+        set_errno(ESRCH);  break;
+      case SS$_INSFMEM:
+        set_errno(ENOMEM); break;
+      default:
+        _ckvmssts(iss);
+        set_errno(EVMSERR);
+    } 
+    set_vaxc_errno(iss);
+ 
+    return -1;
+}
+#endif
+
+
 /* default piping mailbox size */
 #define PERL_BUFSIZ        512
 
diff -uBb vms/vmsish.h-orig vms/vmsish.h
--- vms/vmsish.h-orig   Mon Nov 19 14:28:12 2001
+++ vms/vmsish.h        Mon Nov 19 13:38:28 2001
@@ -511,6 +511,10 @@
 #    define sigaction(a,b,c) Perl_my_sigaction(a,b,c)
 #  endif
 #endif
+#ifdef KILL_BY_SIGPRC
+#  define kill  Perl_my_kill
+#endif
+
 
 /* VMS doesn't use a real sys_nerr, but we need this when scanning for error
  * messages in text strings . . .
@@ -768,6 +772,9 @@
 #ifndef HOMEGROWN_POSIX_SIGNALS
 int    Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);
 #endif
+#ifdef KILL_BY_SIGPRC
+int    Perl_my_kill (int, int);
+#endif
 int    Perl_my_utime (pTHX_ char *, struct utimbuf *);
 void   Perl_vms_image_init (int *, char ***);
 struct dirent *        Perl_readdir (pTHX_ DIR *);
--
 Drexel University       \V                    --Chuck Lane
======]---------->--------*------------<-------[===========
     (215) 895-1545     _/ \  Particle Physics
FAX: (215) 895-5934     /\ /~~~~~~~~~~~        [EMAIL PROTECTED]

Reply via email to