Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Print inside SIGNALS

by pedrete (Sexton)
on Jul 16, 2018 at 13:46 UTC ( [id://1218573]=perlquestion: print w/replies, xml ) Need Help??

pedrete has asked for the wisdom of the Perl Monks concerning the following question:

Hi PerlMonks...

Is there any safe way of print to STDOUT inside a signal?

something like this

alarm 10; $SIG{ALRM} = \&Finish; sub Finish { print "Timeout reached"; }

does not work in Linux Debian.

Thanks!

Replies are listed 'Best First'.
Re: Print inside SIGNALS
by Corion (Patriarch) on Jul 16, 2018 at 13:50 UTC

    The following works for me:

    alarm 2; $SIG{ALRM} = \&Finish; sleep 30; sub Finish { print "Timeout reached"; }

    But also see perlipc on signals and how they (badly) interact with filehandles.

      Thank everybody...

      My actual perl program is huge to post it here. It does not use threads but it execute many external commands.

      The Signal works and the Finish sub is executed.... it deletes temp files, close FHs, etc... everything works BUT print.. it does not print anything in STDOUT!

      If the Finish sub is executed by the program itself (not via ALARM), then it prints to STDOUT normally..

      I know that you are not magicians and that without the full code you cannot be accurate, but i would appreciate any clue or suggestion you may provide, please...

        print returns false and sets $! on failure.

        Turn on autoflush (see perlvar):

        $| = 1;
        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      Thanks Corion... it does not work in my Debian box ... :-( I edit... It works! it seems ALARM only affects user level calls...

        I'm on a Debian box as well, and the behaviour is like this:

        • Your original code doesn't print anything because the program finishes before the timer rings. That's quite normal.
        • With Corion's example, I get the print - but not the full sleep time, the code immediately resumes after the alarm. I didn't know that, but the alarm documentation gives a hint: It is usually a mistake to intermix "alarm" and "sleep" calls, because "sleep" may be internally implemented on your system with "alarm".

        If your C library's print function isn't re-entrant (many aren't), then there's always a chance that weird things happen when the signal goes off while your code is printing something.

        Are you using threads in your script? From the threads documentation, signals in threads are not real signals and won't interrupt a blocked system call.

        it seems ALARM only affects user level calls..

        Not at all. As Corion's program demonstrates, system calls are clearly interrupted.

        The signal will only be handled between Perl ops, so a long running op (regex match or XS function call) could delay the handling of the signal.

        Then something is really messed up with your box. Unless you didn't actually run Corion's program?

Re: Print inside SIGNALS
by tybalt89 (Monsignor) on Jul 16, 2018 at 14:04 UTC
    perl -e 'alarm 3;$SIG{ALRM}=sub{print "Timeout reached\n"}; sleep 10'

    works for me on my ArchLinux system.

    Note you didn't have a newline on your print, maybe you just missed the output because it wasn't on a separate line?

Re: Print inside SIGNALS
by pedrete (Sexton) on Jul 16, 2018 at 19:46 UTC

    This code does not work..

    alarm 2; $SIG{ALRM} = \&Finish; while (1==1){}; sub Finish { print "Timeout reached"; }

    BUT... This code works... and after 2 seconds, the program dies...

    alarm 2; $SIG{ALRM} = \&Finish; while (1==1){}; sub Finish { die; }

    So something happens with print...

      I can replicate that the first snippet doesn't seem to output anything. However, it seems that the signal does get triggered, it just has something to do with buffering, as the following two examples work. Are you really just doing print "Timeout reached"; in your original code, without the newline or anything else that would cause the output to get flushed? See also Suffering from Buffering.

      $ perl -wMstrict -e 'alarm 2; $SIG{ALRM}=sub{ print "Timeout reached" }; while(){}' ^C $ perl -wMstrict -e 'alarm 2; $SIG{ALRM}=sub{ print "Timeout reached\n" }; while(){}' Timeout reached $ perl -wMstrict -e '$|++; alarm 2; $SIG{ALRM}=sub{ print "Timeout reached" }; while(){}' Timeout reached

      Elsewhere in this thread you said:

      My actual perl program is huge to post it here. It does not use threads but it execute many external commands.

      Well, the trick is to reduce the actual code down to an SSCCE. Delete some code from your program, if the problem persists, that code can stay deleted, but if the problem goes away, then put that code back in. Repeat this over and over until your code is a 10 to 20 line program that demonstrates the issue. Not only will this help you in narrowing down the problem, it'll give us a way to reproduce the actual issue ourselves.

      Other than the above buffering issue, I wouldn't exclude the possibility that one of the external programs is the culprit, or something else you're doing in your "huge" program. For example, perhaps something questionable is happening to STDOUT.

        I can replicate that the first snippet doesn't seem to output anything.

        Since you killed the process instead of letting it exit cleanly (e.g. using die or exit), it didn't get to flush its buffers.

        Fool me... EUREKA! Buffering issue as suggested by haukex !!!!

        Thank you everybody....

      This is not so special. If you print to a terminal, you might note that this code does work, in the sense that the output appears after two seconds:
      alarm 2; $SIG{ALRM} = \&Finish; while (1==1){}; sub Finish { print "Timeout reached\n"; }
      After that, the endless loop continues. The only difference is the line feed: STDOUT is typically line buffered if output is to the terminal. So, you just don't see the output. For output to a file or socket, you might want to set $| to a true value.
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1218573]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2024-04-18 02:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found