Re: Fragile signals
Ilya Zakharevich [Thu, 13 Feb 1997 06:44:39 +0000 (01:44 -0500)]
Ilya Zakharevich writes:
>
> Some messages of mine get stuck in the chain:
>
>         Nico => Debian => floor
>
> I repost them now:
>
> As you may remember, the following program
>
> #!/usr/bin/perl
> sub foo { ++$a }
> $SIG{ALRM} = sub { $run = 0 ; return };
> while (1) {
>   $a = 0;
>   $run = 1;
>   alarm 1;
>   foo while $run;
>   print $i++, ": $a\n";
> }
> die "Not reached";
> __END__
>
> will not call malloc/realloc/free in sighandler, but nevertheless it
> would not run more than approx. 25 iterations. This shows that 4% of
> subroutine-calling frame is not signal-safe.
>
> The following patch makes it run approx. twice as long (on _17) (thus

Well, the following patch makes it run 4 times as long. The only
failure mode I have seen was silent walking off runops().

Here is the statistics (number of iterations before failure):

   Before:
                23, 24, 14, 22, 19, 13, 30, 11
        (4 core dumps, 2 attempts to free unref scalar, 1 panic:
                leave-scope, 1 silent)
   After:
                42, 936, 63, 131, 280.
        (all silent)

It looks like handling of internal stacks needs a lot of
improvement. What this patch does is only a symptomatic treatment, but
it may go into 004 nevertheless (especially if one can see why op
becomes 0 at some moment). I tried saving/restoring op in the handler,
but this does not help...

p5p-msgid: <199702130644.BAA07572@monk.mps.ohio-state.edu>

mg.c

diff --git a/mg.c b/mg.c
index 77c0417..2ee52a3 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -1540,11 +1540,18 @@ int sig;
     SV *sv;
     CV *cv;
     AV *oldstack;
-    
+    int long_savestack = savestack_ix + 15 <= savestack_max;
+    int long_cxstack = cxstack_ix < cxstack_max - 1;
+      
+    if (long_cxtack) cxstack_ix++;     /* Protect from overwrite. */
     if(!psig_ptr[sig])
        die("Signal SIG%s received, but no signal handler set.\n",
        sig_name[sig]);
 
+    /* Max number of items pushed there is 3*n or 4. We cannot fix
+       infinity, so we fix 4 (in fact 5): */
+    if (long_savestack) savestack_ix += 5;     /* Protect save in progress. */
+
     cv = sv_2cv(psig_ptr[sig],&st,&gv,TRUE);
     if (!cv || !CvROOT(cv)) {
        if (dowarn)
@@ -1571,6 +1578,8 @@ int sig;
     perl_call_sv((SV*)cv, G_DISCARD);
 
     SWITCHSTACK(signalstack, oldstack);
-
+    if (long_savestack) savestack_ix -= 5; /* Unprotect save in progress. */
+    if (long_cxstack) cxstack_ix--;
+    
     return;
 }